#pragma once

namespace Mix{

	////////////////////////////////////////////////////////////////////////////////////////////////////

	template<typename T>
	class Container
	{
	private:
		UInt32 m_Pos;
		UInt32 m_Capacity;
		UInt32 m_ResizeStep;
		UInt32 m_TypeSize;
		T* m_pBuffer;

#ifdef _DEBUG
		Mix::StringW m_DebugName;
#endif //_DEBUG

	private:
		void Resize( UInt32 count )
		{
			UInt32 remCount = ( ( count % m_ResizeStep ) > 0 )? 1 : 0;
			UInt32 nextCapacity = m_Capacity + ( ( count / m_ResizeStep ) + remCount ) * m_ResizeStep;

			T* pNextBuffer = MIX_LIB_NEW T[nextCapacity];
			MIX_ASSERT( pNextBuffer != NULL );

			::memcpy_s( pNextBuffer, sizeof( T ) * nextCapacity, m_pBuffer, sizeof( T ) * m_Pos );
			MIX_LIB_DELETE_ARRAY( m_pBuffer );

			m_pBuffer = pNextBuffer;
			m_Capacity = nextCapacity;

#ifdef _DEBUG
			MIX_LOG_DEV_INFO( L"Mix::Container : Resize : Name[%s] Capacity[%u]", m_DebugName.GetConstPtr(), m_Capacity );
#endif //_DEBUG
		}

	public:
		MIX_DECLARE_ALLOCATOR();

		Container( void ) :
		m_pBuffer( NULL ),
		m_Capacity( 0 ),
		m_Pos( 0 ),
		m_ResizeStep( 0 )
		{
#ifdef _DEBUG
			m_DebugName = L"";
#endif //_DEBUG
		}

		Container( UInt32 defCapacity, UInt32 resizeStep, const wchar_t* pDebugName = NULL ) :
		m_pBuffer( NULL ),
		m_Capacity( 0 ),
		m_Pos( 0 ),
		m_ResizeStep( 0 )
		{
			MIX_ASSERT( defCapacity > 0 );
			MIX_ASSERT( resizeStep > 0 );

#ifdef _DEBUG
			m_DebugName = L"";
#endif //_DEBUG

			Initialize( defCapacity, resizeStep, pDebugName );
		}

		virtual ~Container( void )
		{
#ifdef _DEBUG
			MIX_LOG_DEV_INFO( L"Mix::Container : Release : Name[%s] Capacity[%u]", m_DebugName.GetConstPtr(), m_Capacity );
#endif //_DEBUG

			MIX_LIB_DELETE_ARRAY( m_pBuffer );
		}

		void Initialize( UInt32 defCapacity, UInt32 resizeStep, const wchar_t* pDebugName = NULL )
		{
			MIX_ASSERT( defCapacity > 0 );
			MIX_ASSERT( resizeStep > 0 );

			MIX_LIB_DELETE_ARRAY( m_pBuffer );

			m_pBuffer = MIX_LIB_NEW T[defCapacity];
			if( m_pBuffer != NULL )
			{
				m_Capacity = defCapacity;
			}

			m_ResizeStep = resizeStep;
			m_TypeSize = sizeof( T );
			m_Pos = 0;

#ifdef _DEBUG
			m_DebugName = MIX_SAFE_NAME( pDebugName );
			MIX_LOG_DEV_INFO( L"Mix::Container : Initialize : Name[%s] Capacity[%u] ResizeStep[%u]",
				m_DebugName.GetConstPtr(),
				m_Capacity,
				m_ResizeStep );
#endif //_DEBUG
		}

		void Clear( void )
		{
			m_Pos = 0;
		}

		T* Add( void )
		{
			if( m_Capacity == m_Pos )
			{
				Resize( 1 );
			}

			MIX_ASSERT( m_pBuffer != NULL );

			return &( m_pBuffer[m_Pos++] );
		}

		T* Add( UInt32 count )
		{
			MIX_ASSERT( count > 0 );

			if( ( m_Pos + count ) >= m_Capacity )
			{
				Resize( count );
			}

			MIX_ASSERT( m_pBuffer != NULL );

			UInt32 prePos = m_Pos;
			m_Pos += count;

			return &( m_pBuffer[prePos] );
		}

		T* Add( UInt32 count, const T& value )
		{
			MIX_ASSERT( count > 0 );

			if( ( m_Pos + count ) >= m_Capacity )
			{
				Resize( count );
			}

			MIX_ASSERT( m_pBuffer != NULL );

			UInt32 prePos = m_Pos;
			m_Pos += count;

			for( UInt32 i = prePos; i < m_Pos; i++ )
			{
				m_pBuffer[i] = value;
			}

			return &( m_pBuffer[prePos] );
		}

		T* Add( T const& data )
		{
			if( m_Capacity == m_Pos )
			{
				Resize( 1 );
			}

			MIX_ASSERT( m_pBuffer != NULL );

			m_pBuffer[m_Pos] = data;

			return &( m_pBuffer[m_Pos++] );
		}

		T* Add( T const* data, UInt32 count )
		{
			MIX_ASSERT( data != NULL );
			MIX_ASSERT( count > 0 );

			if( ( m_Pos + count ) >= m_Capacity )
			{
				Resize( count );
			}

			MIX_ASSERT( m_pBuffer != NULL );

			UInt32 prePos = m_Pos;

			const T* pSrc = &( data[0] );
			T* pDst = &( m_pBuffer[prePos] );
			T* pDstEnd = pDst + count;

			while( pDst != pDstEnd )
			{
				*pDst++ = *pSrc++;
			}

			m_Pos += count;

			return &( m_pBuffer[prePos] );
		}

		void Reduction( UInt32 count )
		{
			MIX_ASSERT( m_Pos >= count );

			m_Pos = count;
		}

		void Remove( const T& value )
		{
			if( m_Pos == 0 )
			{
				return;
			}

			if( m_Pos > 1 )
			{
				UInt32 index;

				for( index = 0; index < m_Pos; index++ )
				{
					if( m_pBuffer[index] == value )
					{
						break;
					}
				}

				if( index < m_Pos )
				{
					if( index != ( m_Pos - 1 ) )
					{
						Mix::Memory::Copy( &( m_pBuffer[index] ), &( m_pBuffer[index + 1] ), sizeof( T ) * ( m_Pos - index - 1 ) );
					}

					m_Pos--;
				}
			}
			else
			{
				m_Pos = 0;
			}
		}

		void RemoveByIndex( UInt32 index )
		{
			MIX_ASSERT( m_Pos > index );

			Mix::Memory::Copy( &( m_pBuffer[index] ), &( m_pBuffer[index + 1] ), sizeof( T ) * ( m_Pos - index - 1 ) );

			m_Pos--;
		}

		void FastRemove( const T& value )
		{
			if( m_Pos == 0 )
			{
				return;
			}

			if( m_Pos > 1 )
			{
				UInt32 index;

				for( index = 0; index < m_Pos; index++ )
				{
					if( m_pBuffer[index] == value )
					{
						m_pBuffer[index] = m_pBuffer[m_Pos - 1];
						m_Pos--;
						break;
					}
				}
			}
			else
			{
				m_Pos = 0;
			}
		}

		void FastRemoveByIndex( UInt32 index )
		{
			MIX_ASSERT( m_Pos > index );

			memcpy_s( &m_pBuffer[index], sizeof( T ), &m_pBuffer[m_Pos - 1], sizeof( T ) );

			m_Pos--;
		}

		T& PopBack( void )
		{
			MIX_ASSERT( m_Pos > 0 );

			m_Pos--;

			return m_pBuffer[m_Pos];
		}

		UInt32 GetCount( void ) const
		{
			return m_Pos;
		}

		UInt32 GetCapacity( void ) const
		{
			return m_Capacity;
		}

		T& GetFirst( void ) const
		{
			MIX_ASSERT( m_Pos > 0 );

			return m_pBuffer[0];
		}

		T& GetLast( void ) const
		{
			MIX_ASSERT( m_Pos > 0 );

			return m_pBuffer[m_Pos - 1];
		}

		T& GetCurrent( void ) const
		{
			MIX_ASSERT( m_Pos > 0 );

			return ( m_pBuffer + ( m_Pos - 1 ) );
		}

		const T& GetConstCurrent( void ) const
		{
			return ( m_pBuffer + ( m_Pos - 1 ) );
		}

		T* GetBeginPtr( void ) const
		{
			MIX_ASSERT( m_pBuffer != NULL );

			return ( m_Pos > 0 )? m_pBuffer : NULL;
		}

		const T* GetConstBeginPtr( void ) const
		{
			MIX_ASSERT( m_pBuffer != NULL );

			return ( m_Pos > 0 )? m_pBuffer : NULL;
		}

		T* GetEndPtr( void ) const
		{
			MIX_ASSERT( m_pBuffer != NULL );

			return ( m_Pos > 0 )? ( m_pBuffer + m_Pos ) : NULL;
		}

		const T* GetConstEndPtr( void ) const
		{
			MIX_ASSERT( m_pBuffer != NULL );

			return ( m_Pos > 0 )? ( m_pBuffer + m_Pos ) : NULL;
		}

		T* GetCurrentPtr( void ) const
		{
			return ( m_Pos > 0 )? ( m_pBuffer + ( m_Pos - 1 ) ) : NULL;
		}

		const T* GetConstCurrentPtr( void ) const
		{
			return ( m_Pos > 0 )? ( m_pBuffer + ( m_Pos - 1 ) ) : NULL;
		}

		T& operator[]( UInt32 index ) const
		{
			MIX_ASSERT( m_Pos > index );

			return m_pBuffer[index];
		}

		Boolean IsEmpty( void ) const
		{
			return ( m_Pos == 0 );
		}
	};

	////////////////////////////////////////////////////////////////////////////////////////////////////

	template<typename T, Mix::Memory::SECTION_TYPE ST>
	class ContainerT
	{
	private:
		UInt32 m_Pos;
		UInt32 m_Capacity;
		UInt32 m_ResizeStep;
		UInt32 m_TypeSize;
		T* m_pBuffer;

#ifdef _DEBUG
		Mix::StringW m_DebugName;
#endif //_DEBUG

	private:
		void Resize( UInt32 count )
		{
			UInt32 remCount = ( ( count % m_ResizeStep ) > 0 )? 1 : 0;
			UInt32 nextCapacity = m_Capacity + ( ( count / m_ResizeStep ) + remCount ) * m_ResizeStep;

			T* pNextBuffer = MIX_LIB_NEW_ARRAY_T( ST, T, nextCapacity );
			MIX_ASSERT( pNextBuffer != NULL );

			::memcpy_s( pNextBuffer, sizeof( T ) * nextCapacity, m_pBuffer, sizeof( T ) * m_Pos );

			MIX_LIB_DELETE_ARRAY_T( T, m_pBuffer );

			m_pBuffer = pNextBuffer;
			m_Capacity = nextCapacity;

#ifdef _DEBUG
			MIX_LOG_DEV_INFO( L"Mix::ContainerT : Resize : Name[%s] Capacity[%u]", m_DebugName.GetConstPtr(), m_Capacity );
#endif //_DEBUG
		}

	public:
		MIX_DECLARE_ALLOCATOR();

		ContainerT( void ) :
		m_pBuffer( NULL ),
		m_Capacity( 0 ),
		m_Pos( 0 ),
		m_ResizeStep( 0 )
		{
#ifdef _DEBUG
			m_DebugName = L"";
#endif //_DEBUG
		}

		ContainerT( UInt32 defCapacity, UInt32 resizeStep, const wchar_t* pDebugName = NULL ) :
		m_pBuffer( NULL ),
		m_Capacity( 0 ),
		m_Pos( 0 ),
		m_ResizeStep( 0 )
		{
			MIX_ASSERT( defCapacity > 0 );
			MIX_ASSERT( resizeStep > 0 );

#ifdef _DEBUG
			m_DebugName = L"";
#endif //_DEBUG

			Initialize( defCapacity, resizeStep, pDebugName );
		}

		virtual ~ContainerT( void )
		{
#ifdef _DEBUG
			MIX_LOG_DEV_INFO( L"Mix::ContainerT : Release : Name[%s] Capacity[%u]", m_DebugName.GetConstPtr(), m_Capacity );
#endif //_DEBUG

			MIX_LIB_DELETE_ARRAY_T( T, m_pBuffer );
		}

		void Initialize( UInt32 defCapacity, UInt32 resizeStep, const wchar_t* pDebugName = NULL )
		{
			MIX_ASSERT( defCapacity > 0 );
			MIX_ASSERT( resizeStep > 0 );

			MIX_LIB_DELETE_ARRAY_T( T, m_pBuffer );

			m_pBuffer = MIX_LIB_NEW_ARRAY_T( ST, T, defCapacity );
			if( m_pBuffer != NULL )
			{
				m_Capacity = defCapacity;
			}

			m_ResizeStep = resizeStep;
			m_TypeSize = sizeof( T );
			m_Pos = 0;

#ifdef _DEBUG
			m_DebugName = MIX_SAFE_NAME( pDebugName );
			MIX_LOG_DEV_INFO( L"Mix::ContainerT : Initialize : Name[%s] Capacity[%u] ResizeStep[%u]",
				m_DebugName.GetConstPtr(),
				m_Capacity,
				m_ResizeStep );
#endif //_DEBUG
		}

		void Clear( void )
		{
			m_Pos = 0;
		}

		T* Add( void )
		{
			if( m_Capacity == m_Pos )
			{
				Resize( 1 );
			}

			MIX_ASSERT( m_pBuffer != NULL );

			return &( m_pBuffer[m_Pos++] );
		}

		T* Add( UInt32 count )
		{
			MIX_ASSERT( count > 0 );

			if( ( m_Pos + count ) >= m_Capacity )
			{
				Resize( count );
			}

			MIX_ASSERT( m_pBuffer != NULL );

			UInt32 prePos = m_Pos;
			m_Pos += count;

			return &( m_pBuffer[prePos] );
		}

		T* Add( UInt32 count, const T& value )
		{
			MIX_ASSERT( count > 0 );

			if( ( m_Pos + count ) >= m_Capacity )
			{
				Resize( count );
			}

			MIX_ASSERT( m_pBuffer != NULL );

			UInt32 prePos = m_Pos;
			m_Pos += count;

			for( UInt32 i = prePos; i < m_Pos; i++ )
			{
				m_pBuffer[i] = value;
			}

			return &( m_pBuffer[prePos] );
		}

		T* Add( T const& data )
		{
			if( m_Capacity == m_Pos )
			{
				Resize( 1 );
			}

			MIX_ASSERT( m_pBuffer != NULL );

			m_pBuffer[m_Pos] = data;

			return &( m_pBuffer[m_Pos++] );
		}

		T* Add( T const* data, UInt32 count )
		{
			MIX_ASSERT( data != NULL );
			MIX_ASSERT( count > 0 );

			if( ( m_Pos + count ) >= m_Capacity )
			{
				Resize( count );
			}

			MIX_ASSERT( m_pBuffer != NULL );

			UInt32 prePos = m_Pos;

			const T* pSrc = &( data[0] );
			T* pDst = &( m_pBuffer[prePos] );
			T* pDstEnd = pDst + count;

			while( pDst != pDstEnd )
			{
				*pDst++ = *pSrc++;
			}

			m_Pos += count;

			return &( m_pBuffer[prePos] );
		}

		void Reduction( UInt32 count )
		{
			MIX_ASSERT( m_Pos >= count );

			m_Pos = count;
		}

		void Remove( const T& value )
		{
			if( m_Pos == 0 )
			{
				return;
			}

			if( m_Pos > 1 )
			{
				UInt32 index;

				for( index = 0; index < m_Pos; index++ )
				{
					if( m_pBuffer[index] == value )
					{
						break;
					}
				}

				if( index < m_Pos )
				{
					if( index != ( m_Pos - 1 ) )
					{
						Mix::Memory::Copy( &( m_pBuffer[index] ), &( m_pBuffer[index + 1] ), sizeof( T ) * ( m_Pos - index - 1 ) );
					}

					m_Pos--;
				}
			}
			else
			{
				m_Pos = 0;
			}
		}

		void RemoveByIndex( UInt32 index )
		{
			MIX_ASSERT( m_Pos > index );

			Mix::Memory::Copy( &( m_pBuffer[index] ), &( m_pBuffer[index + 1] ), sizeof( T ) * ( m_Pos - index - 1 ) );

			m_Pos--;
		}

		void FastRemove( const T& value )
		{
			if( m_Pos == 0 )
			{
				return;
			}

			if( m_Pos > 1 )
			{
				UInt32 index;

				for( index = 0; index < m_Pos; index++ )
				{
					if( m_pBuffer[index] == value )
					{
						m_pBuffer[index] = m_pBuffer[m_Pos - 1];
						m_Pos--;
						break;
					}
				}
			}
			else
			{
				m_Pos = 0;
			}
		}

		void FastRemoveByIndex( UInt32 index )
		{
			MIX_ASSERT( m_Pos > index );

			memcpy_s( &m_pBuffer[index], sizeof( T ), &m_pBuffer[m_Pos - 1], sizeof( T ) );

			m_Pos--;
		}

		T& PopBack( void )
		{
			MIX_ASSERT( m_Pos > 0 );

			m_Pos--;

			return m_pBuffer[m_Pos];
		}

		UInt32 GetCount( void ) const
		{
			return m_Pos;
		}

		UInt32 GetCapacity( void ) const
		{
			return m_Capacity;
		}

		T& GetFirst( void ) const
		{
			MIX_ASSERT( m_Pos > 0 );

			return m_pBuffer[0];
		}

		T& GetLast( void ) const
		{
			MIX_ASSERT( m_Pos > 0 );

			return m_pBuffer[m_Pos - 1];
		}

		T& GetCurrent( void ) const
		{
			MIX_ASSERT( m_Pos > 0 );

			return ( m_pBuffer + ( m_Pos - 1 ) );
		}

		const T& GetConstCurrent( void ) const
		{
			return ( m_pBuffer + ( m_Pos - 1 ) );
		}

		T* GetBeginPtr( void ) const
		{
			MIX_ASSERT( m_pBuffer != NULL );

			return ( m_Pos > 0 )? m_pBuffer : NULL;
		}

		const T* GetConstBeginPtr( void ) const
		{
			MIX_ASSERT( m_pBuffer != NULL );

			return ( m_Pos > 0 )? m_pBuffer : NULL;
		}

		T* GetEndPtr( void ) const
		{
			MIX_ASSERT( m_pBuffer != NULL );

			return ( m_Pos > 0 )? ( m_pBuffer + m_Pos ) : NULL;
		}

		const T* GetConstEndPtr( void ) const
		{
			MIX_ASSERT( m_pBuffer != NULL );

			return ( m_Pos > 0 )? ( m_pBuffer + m_Pos ) : NULL;
		}

		T* GetCurrentPtr( void ) const
		{
			return ( m_Pos > 0 )? ( m_pBuffer + ( m_Pos - 1 ) ) : NULL;
		}

		const T* GetConstCurrentPtr( void ) const
		{
			return ( m_Pos > 0 )? ( m_pBuffer + ( m_Pos - 1 ) ) : NULL;
		}

		T& operator[]( UInt32 index ) const
		{
			MIX_ASSERT( m_Pos > index );

			return m_pBuffer[index];
		}

		Boolean IsEmpty( void ) const
		{
			return ( m_Pos == 0 );
		}
	};

	////////////////////////////////////////////////////////////////////////////////////////////////////

	template<typename T>
	class DynamicContainer
	{
	private:
		UInt32 m_Pos;
		UInt32 m_Capacity;
		UInt32 m_ResizeStep;
		T** m_pBuffer;

#ifdef _DEBUG
		Mix::StringW m_DebugName;
#endif //_DEBUG

	private:
		void Fill( UInt32 start, UInt32 count )
		{
			UInt32 end = start + count;
			UInt32 i;

			for( i = start; i < end; i++ )
			{
				m_pBuffer[i] = MIX_LIB_NEW T();
				MIX_ASSERT( m_pBuffer[i] != NULL );
			}
		}

		void Resize( UInt32 count )
		{
			UInt32 remCount = ( ( count % m_ResizeStep ) > 0 )? 1 : 0;
			UInt32 addCapacity = ( ( count / m_ResizeStep ) + remCount ) * m_ResizeStep;
			UInt32 nextCapacity = m_Capacity + addCapacity;

			T** pNextBuffer = MIX_LIB_NEW T*[nextCapacity];
			MIX_ASSERT( pNextBuffer != NULL );

			::CopyMemory( pNextBuffer, m_pBuffer, sizeof( T* ) * m_Capacity );
			MIX_LIB_DELETE_ARRAY( m_pBuffer );

			m_pBuffer = pNextBuffer;

			Fill( m_Capacity, addCapacity );

			m_Capacity = nextCapacity;

#ifdef _DEBUG
			MIX_LOG_DEV_INFO( L"Mix::DynamicContainer : Resize : Name[%s] Capacity[%u]", m_DebugName.GetConstPtr(), m_Capacity );
#endif //_DEBUG
		}

	public:
		DynamicContainer( void ) :
		m_pBuffer( NULL ),
		m_Capacity( 0 ),
		m_Pos( 0 ),
		m_ResizeStep( 0 )
		{
#ifdef _DEBUG
			m_DebugName = L"";
#endif //_DEBUG
		}

		DynamicContainer( UInt32 defCapacity, UInt32 resizeStep, const wchar_t* pDebugName = NULL ) :
		m_pBuffer( NULL ),
		m_Capacity( 0 ),
		m_Pos( 0 ),
		m_ResizeStep( 0 )
		{
#ifdef _DEBUG
			m_DebugName = L"";
#endif //_DEBUG

			Initialize( defCapacity, resizeStep, pDebugName );
		}

		virtual ~DynamicContainer( void )
		{
#ifdef _DEBUG
			MIX_LOG_DEV_INFO( L"Mix::DynamicContainer : Release : Name[%s] Capacity[%u]", m_DebugName.GetConstPtr(), m_Capacity );
#endif //_DEBUG

			for( UInt32 i = 0; i < m_Capacity; i++ )
			{
				MIX_LIB_DELETE( m_pBuffer[i] );
			}

			MIX_LIB_DELETE_ARRAY( m_pBuffer );
		}

		void Initialize( UInt32 defCapacity, UInt32 resizeStep, const wchar_t* pDebugName = NULL )
		{
			MIX_ASSERT( defCapacity > 0 );
			MIX_ASSERT( resizeStep > 0 );

			m_Capacity = defCapacity;
			m_ResizeStep = resizeStep;

			m_pBuffer = MIX_LIB_NEW T*[defCapacity];
			MIX_ASSERT( m_pBuffer != NULL );

			Fill( 0, m_Capacity );

#ifdef _DEBUG
			m_DebugName = MIX_SAFE_NAME( pDebugName );
			MIX_LOG_DEV_INFO( L"Mix::DynamicContainer : Initialize : Name[%s] Capacity[%u] ResizeStep[%u]",
				m_DebugName.GetConstPtr(),
				m_Capacity,
				m_ResizeStep );
#endif //_DEBUG
		}

		void Clear( void )
		{
			m_Pos = 0;
		}

		T* Add( void )
		{
			if( m_Capacity == m_Pos )
			{
				Resize( 1 );
			}

			MIX_ASSERT( m_pBuffer != NULL );

			return m_pBuffer[m_Pos++];
		}

		T** Add( UInt32 count )
		{
			MIX_ASSERT( count > 0 );

			if( ( m_Pos + count ) >= m_Capacity )
			{
				Resize( count );
			}

			MIX_ASSERT( m_pBuffer != NULL );

			UInt32 prePos = m_Pos;
			m_Pos += count;

			return &( m_pBuffer[prePos] );
		}

		void RemoveByIndex( UInt32 index )
		{
			MIX_ASSERT( m_Pos > index );

			Mix::Memory::Copy( &( m_pBuffer[index] ), &( m_pBuffer[index + 1] ), sizeof( T* ) * ( m_Pos - index - 1 ) );

			m_Pos--;
		}

		void FastRemoveByIndex( UInt32 index )
		{
			MIX_ASSERT( m_Pos > index );

			UInt32 lastIndex = m_Pos - 1;
			T* pTemp = m_pBuffer[index];

			m_pBuffer[index] = m_pBuffer[lastIndex];
			m_pBuffer[lastIndex] = pTemp;

			m_Pos--;
		}

		void Reduction( UInt32 count )
		{
			MIX_ASSERT( m_Pos >= count );

			m_Pos = count;
		}

		UInt32 GetCount( void ) const
		{
			return m_Pos;
		}

		UInt32 GetCapacity( void ) const
		{
			return m_Capacity;
		}

		T** GetBeginPtr( void ) const
		{
			MIX_ASSERT( m_pBuffer != NULL );

			return ( m_Pos > 0 )? m_pBuffer : NULL;
		}

		T** GetEndPtr( void ) const
		{
			MIX_ASSERT( m_pBuffer != NULL );

			return ( m_Pos > 0 )? ( m_pBuffer + m_Pos ) : NULL;
		}

		T* const* GetConstBeginPtr( void ) const
		{
			MIX_ASSERT( m_pBuffer != NULL );

			return ( m_Pos > 0 )? m_pBuffer : NULL;
		}

		T* const* GetConstEndPtr( void ) const
		{
			MIX_ASSERT( m_pBuffer != NULL );

			return ( m_Pos > 0 )? ( m_pBuffer + m_Pos ) : NULL;
		}

		T* operator[]( UInt32 index ) const
		{
			MIX_ASSERT( m_Pos > index );

			return m_pBuffer[index];
		}

		Boolean IsEmpty( void ) const
		{
			return ( m_Pos == 0 );
		}
	};

	////////////////////////////////////////////////////////////////////////////////////////////////////

	template<typename T, Mix::Memory::SECTION_TYPE ST>
	class DynamicContainerT
	{
	private:
		UInt32 m_Pos;
		UInt32 m_Capacity;
		UInt32 m_ResizeStep;
		T** m_pBuffer;

#ifdef _DEBUG
		Mix::StringW m_DebugName;
#endif //_DEBUG

	private:
		void Fill( UInt32 start, UInt32 count )
		{
			UInt32 end = start + count;
			UInt32 i;

			for( i = start; i < end; i++ )
			{
				m_pBuffer[i] = MIX_LIB_NEW_T( ST, T );
				MIX_ASSERT( m_pBuffer[i] != NULL );
			}
		}

		void Resize( UInt32 count )
		{
			UInt32 remCount = ( ( count % m_ResizeStep ) > 0 )? 1 : 0;
			UInt32 addCapacity = ( ( count / m_ResizeStep ) + remCount ) * m_ResizeStep;
			UInt32 nextCapacity = m_Capacity + addCapacity;

			T** pNextBuffer = MIX_LIB_NEW_ARRAY_T( ST, T*, nextCapacity );
			MIX_ASSERT( pNextBuffer != NULL );

			::CopyMemory( pNextBuffer, m_pBuffer, sizeof( T* ) * m_Capacity );
			MIX_LIB_DELETE_PTR_ARRAY_T( m_pBuffer );

			m_pBuffer = pNextBuffer;

			Fill( m_Capacity, addCapacity );

			m_Capacity = nextCapacity;

#ifdef _DEBUG
			MIX_LOG_DEV_INFO( L"Mix::DynamicContainerT : Resize : Name[%s] Capacity[%u]", m_DebugName.GetConstPtr(), m_Capacity );
#endif //_DEBUG
		}

	public:
		DynamicContainerT( void ) :
		m_pBuffer( NULL ),
		m_Capacity( 0 ),
		m_Pos( 0 ),
		m_ResizeStep( 0 )
		{
#ifdef _DEBUG
			m_DebugName = L"";
#endif //_DEBUG
		}

		DynamicContainerT( UInt32 defCapacity, UInt32 resizeStep, const wchar_t* pDebugName = NULL ) :
		m_pBuffer( NULL ),
		m_Capacity( 0 ),
		m_Pos( 0 ),
		m_ResizeStep( 0 )
		{
#ifdef _DEBUG
			m_DebugName = L"";
#endif //_DEBUG

			Initialize( defCapacity, resizeStep, pDebugName );
		}

		virtual ~DynamicContainerT( void )
		{
#ifdef _DEBUG
			MIX_LOG_DEV_INFO( L"Mix::DynamicContainerT : Release : Name[%s] Capacity[%u]", m_DebugName.GetConstPtr(), m_Capacity );
#endif //_DEBUG

			for( UInt32 i = 0; i < m_Capacity; i++ )
			{
				MIX_LIB_DELETE_T( T, m_pBuffer[i] );
			}

			MIX_LIB_DELETE_PTR_ARRAY_T( m_pBuffer );
		}

		void Initialize( UInt32 defCapacity, UInt32 resizeStep, const wchar_t* pDebugName = NULL )
		{
			MIX_ASSERT( defCapacity > 0 );
			MIX_ASSERT( resizeStep > 0 );

			m_Capacity = defCapacity;
			m_ResizeStep = resizeStep;

			m_pBuffer = MIX_LIB_NEW_ARRAY_T( ST, T*, defCapacity );
			MIX_ASSERT( m_pBuffer != NULL );

			Fill( 0, m_Capacity );

#ifdef _DEBUG
			m_DebugName = MIX_SAFE_NAME( pDebugName );
			MIX_LOG_DEV_INFO( L"Mix::DynamicContainerT : Initialize : Name[%s] Capacity[%u] ResizeStep[%u]",
				m_DebugName.GetConstPtr(),
				m_Capacity,
				m_ResizeStep );
#endif //_DEBUG
		}

		void Clear( void )
		{
			m_Pos = 0;
		}

		T* Add( void )
		{
			if( m_Capacity == m_Pos )
			{
				Resize( 1 );
			}

			MIX_ASSERT( m_pBuffer != NULL );

			return m_pBuffer[m_Pos++];
		}

		T** Add( UInt32 count )
		{
			MIX_ASSERT( count > 0 );

			if( ( m_Pos + count ) >= m_Capacity )
			{
				Resize( count );
			}

			MIX_ASSERT( m_pBuffer != NULL );

			UInt32 prePos = m_Pos;
			m_Pos += count;

			return &( m_pBuffer[prePos] );
		}

		void RemoveByIndex( UInt32 index )
		{
			MIX_ASSERT( m_Pos > index );

			Mix::Memory::Copy( &( m_pBuffer[index] ), &( m_pBuffer[index + 1] ), sizeof( T* ) * ( m_Pos - index - 1 ) );

			m_Pos--;
		}

		void FastRemoveByIndex( UInt32 index )
		{
			MIX_ASSERT( m_Pos > index );

			UInt32 lastIndex = m_Pos - 1;
			T* pTemp = m_pBuffer[index];

			m_pBuffer[index] = m_pBuffer[lastIndex];
			m_pBuffer[lastIndex] = pTemp;

			m_Pos--;
		}

		void Reduction( UInt32 count )
		{
			MIX_ASSERT( m_Pos >= count );

			m_Pos = count;
		}

		UInt32 GetCount( void ) const
		{
			return m_Pos;
		}

		UInt32 GetCapacity( void ) const
		{
			return m_Capacity;
		}

		T** GetBeginPtr( void ) const
		{
			MIX_ASSERT( m_pBuffer != NULL );

			return ( m_Pos > 0 )? m_pBuffer : NULL;
		}

		T** GetEndPtr( void ) const
		{
			MIX_ASSERT( m_pBuffer != NULL );

			return ( m_Pos > 0 )? ( m_pBuffer + m_Pos ) : NULL;
		}

		T* const* GetConstBeginPtr( void ) const
		{
			MIX_ASSERT( m_pBuffer != NULL );

			return ( m_Pos > 0 )? m_pBuffer : NULL;
		}

		T* const* GetConstEndPtr( void ) const
		{
			MIX_ASSERT( m_pBuffer != NULL );

			return ( m_Pos > 0 )? ( m_pBuffer + m_Pos ) : NULL;
		}

		T* operator[]( UInt32 index ) const
		{
			MIX_ASSERT( m_Pos > index );

			return m_pBuffer[index];
		}

		Boolean IsEmpty( void ) const
		{
			return ( m_Pos == 0 );
		}
	};
}
