#include "Mix/Private/Scene/Common/ResourceManager.h"

#include "Mix/Graphics/IManager.h"
#include "Mix/Graphics/IDevice.h"
#include "Mix/Graphics/ITexture.h"
#include "Mix/Graphics/Utility/ITargetTextureChain.h"

namespace Mix{ namespace Scene{ namespace Common{

////////////////////////////////////////////////////////////////////////////////////////////////////
// ResoruceManager::BASE_OBJECT
////////////////////////////////////////////////////////////////////////////////////////////////////

ResourceManager::BASE_OBJECT::BASE_OBJECT( UInt32 _tag ) :
owner( 0x00000000 ),
tag( _tag )
{
}

ResourceManager::BASE_OBJECT::BASE_OBJECT( UInt32 _owner, UInt32 _tag ) :
owner( _owner ),
tag( _tag )
{
}

#ifdef _MIX_SCENE_RES_MGR_DEBUG
	ResourceManager::BASE_OBJECT::BASE_OBJECT( UInt32 _owner, UInt32 _tag, const wchar_t* pDebName ) :
	owner( _owner ), tag( _tag ), debName( pDebName ), debIndex( 0 )
	{
	}
#endif //_MIX_SCENE_RES_MGR_DEBUG

////////////////////////////////////////////////////////////////////////////////////////////////////
// ResoruceManager::TEXTURE_OBJECT
////////////////////////////////////////////////////////////////////////////////////////////////////

ResourceManager::TEXTURE_OBJECT::TEXTURE_OBJECT(	UInt32 _tag,
													const Mix::Point& _size,
													Mix::Graphics::FORMAT _format ) : BASE_OBJECT( _tag ),
size( _size ), format( _format )
{
}

ResourceManager::TEXTURE_OBJECT::TEXTURE_OBJECT(	UInt32 _owner,
													UInt32 _tag,
													const Mix::Point& _size,
													Mix::Graphics::FORMAT _format ) : BASE_OBJECT( _owner, _tag ),
size( _size ), format( _format )
{
}

#ifdef _MIX_SCENE_RES_MGR_DEBUG
	ResourceManager::TEXTURE_OBJECT::TEXTURE_OBJECT(	UInt32 _owner,
														UInt32 _tag,
														const Mix::Point& _size,
														Mix::Graphics::FORMAT _format,
														const wchar_t* pDebName ) : BASE_OBJECT( _owner, _tag, pDebName ),
	size( _size ), format( _format )
	{
	}
#endif //_MIX_SCENE_RES_MGR_DEBUG


bool ResourceManager::TEXTURE_OBJECT::operator == ( const TEXTURE_OBJECT& obj ) const
{
	if( ( tag != obj.tag ) ||
		( size != obj.size ) ||
		( format != obj.format ) )
	{
		return false;
	}

	return true;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// ResoruceManager::TARGET_TEXTURE
////////////////////////////////////////////////////////////////////////////////////////////////////

ResourceManager::TARGET_TEXTURE::TARGET_TEXTURE(	UInt32 _owner,
													UInt32 _tag,
													const Mix::Point& _size,
													Mix::Graphics::FORMAT _format,
													Mix::Graphics::ITexture* _pInterface ) : TEXTURE_OBJECT( _owner, _tag, _size, _format )
{
	pInterface = _pInterface;
}

#ifdef _MIX_SCENE_RES_MGR_DEBUG
	ResourceManager::TARGET_TEXTURE::TARGET_TEXTURE(	UInt32 _owner,
														UInt32 _tag,
														const Mix::Point& _size,
														Mix::Graphics::FORMAT _format,
														Mix::Graphics::ITexture* _pInterface,
														const wchar_t* pDebName ) : TEXTURE_OBJECT( _owner, _tag, _size, _format, pDebName )
	{
		pInterface = _pInterface;
	}
#endif //_MIX_SCENE_RES_MGR_DEBUG

////////////////////////////////////////////////////////////////////////////////////////////////////
// ResoruceManager::TARGET_TEXTURE_CHAIN
////////////////////////////////////////////////////////////////////////////////////////////////////

ResourceManager::TARGET_TEXTURE_CHAIN::TARGET_TEXTURE_CHAIN(	UInt32 _owner,
																UInt32 _tag,
																const Mix::Point& _size,
																Mix::Graphics::FORMAT _format,
																Mix::Graphics::Utility::ITargetTextureChain* _pInterface ) : TEXTURE_OBJECT( _owner, _tag, _size, _format )
{
	pInterface = _pInterface;
}

#ifdef _MIX_SCENE_RES_MGR_DEBUG
	ResourceManager::TARGET_TEXTURE_CHAIN::TARGET_TEXTURE_CHAIN(	UInt32 _owner,
																	UInt32 _tag,
																	const Mix::Point& _size,
																	Mix::Graphics::FORMAT _format,
																	Mix::Graphics::Utility::ITargetTextureChain* _pInterface,
																	const wchar_t* pDebName ) : TEXTURE_OBJECT( _owner, _tag, _size, _format, pDebName )
	{
		pInterface = _pInterface;
	}
#endif //_MIX_SCENE_RES_MGR_DEBUG

	////////////////////////////////////////////////////////////////////////////////////////////////////
// ResoruceManager
////////////////////////////////////////////////////////////////////////////////////////////////////

ResourceManager::ResourceManager( const wchar_t* pName, Mix::Graphics::IManager* pGraphicsMgr ) :
m_pGraphicsMgr( NULL ),
m_pGraphicsDev( NULL )
{
	MIX_ASSERT( pGraphicsMgr != NULL );

	m_Name = MIX_SAFE_NAME( pName );

	MIX_ADD_REF( pGraphicsMgr );
	m_pGraphicsMgr = pGraphicsMgr;

	m_pGraphicsMgr->GetDevice( &m_pGraphicsDev );
	MIX_ASSERT( m_pGraphicsDev != NULL );
}

ResourceManager::~ResourceManager( void )
{
	ReleaseAll();

	MIX_RELEASE( m_pGraphicsDev );
	MIX_RELEASE( m_pGraphicsMgr );
}

Mix::Graphics::ITexture* ResourceManager::CreateDepthTexture( UInt32 owner, UInt32 tag, const Mix::Point& size, Mix::Graphics::FORMAT format, const wchar_t* pDebugName )
{
	MIX_ASSERT( owner != 0 );
	MIX_ASSERT( m_pGraphicsDev != NULL );

	ResourceManager::TargetTextureList::iterator it = std::find( m_TargetTexList.begin(), m_TargetTexList.end(), ResourceManager::TEXTURE_OBJECT( tag, size, format ) );
	Mix::Graphics::ITexture* pTex = NULL;
	Mix::String name;

#ifdef _DEBUG
	if( it != m_TargetTexList.end() )
	{
		it->debIndex++;
		name.Sprintf( L"%s/%s( %s_%.2d )", m_Name.GetConstPtr(), MIX_SAFE_NAME( pDebugName ), it->debName.GetConstPtr(), it->debIndex );
	}
	else
	{
		name.Sprintf( L"%s/%s", m_Name.GetConstPtr(), MIX_SAFE_NAME( pDebugName ) );
	}
#else //_DEBUG
	name.Sprintf( L"%s/%s", m_Name.GetConstPtr(), MIX_SAFE_NAME( pDebugName ) );
#endif //_DEBUG

#ifdef _MIX_SCENE_RES_MGR_DEBUG

	if( m_pGraphicsDev->CreateDepthTexture( size.x, size.y, format, &pTex, name.GetConstPtr() ) == True )
	{
		MIX_ADD_REF( pTex );
		m_TargetTexList.push_back( ResourceManager::TARGET_TEXTURE( owner, tag, size, format, pTex, name.GetConstPtr() ) );
	}

#else //_MIX_SCENE_RES_MGR_DEBUG

	if( it != m_TargetTexList.end() )
	{
		MIX_ADD_REF( ( *it ).pInterface );
		pTex = ( *it ).pInterface;
	}
	else
	{
		if( m_pGraphicsDev->CreateDepthTexture( size.x, size.y, format, &pTex, name.GetConstPtr() ) == True )
		{
			MIX_ADD_REF( pTex );
			m_TargetTexList.push_back( ResourceManager::TARGET_TEXTURE( owner, tag, size, format, pTex ) );
		}
	}

#endif //_MIX_SCENE_RES_MGR_DEBUG

	return pTex;
}

Mix::Graphics::ITexture* ResourceManager::CreateTargetTexture( UInt32 owner, UInt32 tag, const Mix::Point& size, Mix::Graphics::FORMAT format, const wchar_t* pDebugName )
{
	MIX_ASSERT( m_pGraphicsDev != NULL );

	ResourceManager::TargetTextureList::iterator it = std::find( m_TargetTexList.begin(), m_TargetTexList.end(), ResourceManager::TEXTURE_OBJECT( tag, size, format ) );
	Mix::Graphics::ITexture* pTex = NULL;
	Mix::String name;

#ifdef _DEBUG
	if( it != m_TargetTexList.end() )
	{
		it->debIndex++;
		name.Sprintf( L"%s/%s( %s_%.2d )", m_Name.GetConstPtr(), MIX_SAFE_NAME( pDebugName ), it->debName.GetConstPtr(), it->debIndex );
	}
	else
	{
		name.Sprintf( L"%s/%s", m_Name.GetConstPtr(), MIX_SAFE_NAME( pDebugName ) );
	}
#else //_DEBUG
		name.Sprintf( L"%s/%s", m_Name.GetConstPtr(), MIX_SAFE_NAME( pDebugName ) );
#endif //_DEBUG

#ifdef _MIX_SCENE_RES_MGR_DEBUG

	if( m_pGraphicsDev->CreateTargetPlaneTexture( size.x, size.y, format, &pTex, name.GetConstPtr() ) == True )
	{
		MIX_ADD_REF( pTex );
		m_TargetTexList.push_back( ResourceManager::TARGET_TEXTURE( owner, tag, size, format, pTex, name.GetConstPtr() ) );
	}

#else //_MIX_SCENE_RES_MGR_DEBUG

	if( it != m_TargetTexList.end() )
	{
		MIX_ADD_REF( ( *it ).pInterface );
		pTex = ( *it ).pInterface;
	}
	else
	{
		if( m_pGraphicsDev->CreateTargetPlaneTexture( size.x, size.y, format, &pTex, name.GetConstPtr() ) == True )
		{
			MIX_ADD_REF( pTex );
			m_TargetTexList.push_back( ResourceManager::TARGET_TEXTURE( owner, tag, size, format, pTex ) );
		}
	}

#endif //_MIX_SCENE_RES_MGR_DEBUG

	return pTex;
}

Mix::Graphics::Utility::ITargetTextureChain* ResourceManager::CreateTargetTextureChain( UInt32 owner, UInt32 tag, const Mix::Point& size, Mix::Graphics::FORMAT format, const wchar_t* pDebugName )
{
	MIX_ASSERT( m_pGraphicsMgr != NULL );

	ResourceManager::TargetTextureChainList::iterator it = std::find( m_TargetTexChainList.begin(), m_TargetTexChainList.end(), ResourceManager::TEXTURE_OBJECT( tag, size, format ) );
	Mix::Graphics::Utility::ITargetTextureChain* pTexChain = NULL;
	Mix::String name;

#ifdef _DEBUG
	if( it != m_TargetTexChainList.end() )
	{
		it->debIndex++;
		name.Sprintf( L"%s/%s( %s_%.2d )", m_Name.GetConstPtr(), MIX_SAFE_NAME( pDebugName ), it->debName.GetConstPtr(), it->debIndex );
	}
	else
	{
		name.Sprintf( L"%s/%s", m_Name.GetConstPtr(), MIX_SAFE_NAME( pDebugName ) );
	}
#else //_DEBUG
		name.Sprintf( L"%s/%s", m_Name.GetConstPtr(), MIX_SAFE_NAME( pDebugName ) );
#endif //_DEBUG

#ifdef _MIX_SCENE_RES_MGR_DEBUG

	if( m_pGraphicsMgr->CreateTargetTextureChain( size.x, size.y, format, &pTexChain, name.GetConstPtr() ) == True )
	{
		MIX_ADD_REF( pTexChain );
		m_TargetTexChainList.push_back( ResourceManager::TARGET_TEXTURE_CHAIN( owner, tag, size, format, pTexChain, name.GetConstPtr() ) );
	}

#else //_MIX_SCENE_RES_MGR_DEBUG

	if( it != m_TargetTexChainList.end() )
	{
		MIX_ADD_REF( ( *it ).pInterface );
		pTexChain = ( *it ).pInterface;
	}
	else
	{
		if( m_pGraphicsMgr->CreateTargetTextureChain( size.x, size.y, format, &pTexChain, name.GetConstPtr() ) == True )
		{
			MIX_ADD_REF( pTexChain );
			m_TargetTexChainList.push_back( ResourceManager::TARGET_TEXTURE_CHAIN( owner, tag, size, format, pTexChain ) );
		}
	}

#endif

	return pTexChain;
}

void ResourceManager::ReleaseAll( void )
{
	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ターゲットテクスチャ
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_TargetTexList.size() > 0 )
	{
		for( ResourceManager::TargetTextureList::iterator it = m_TargetTexList.begin(); it != m_TargetTexList.end(); ++it )
		{
			MIX_RELEASE( ( *it ).pInterface );
		}

		m_TargetTexList.clear();
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ターゲットテクスチャチェイン
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_TargetTexChainList.size() > 0 )
	{
		for( ResourceManager::TargetTextureChainList::iterator it = m_TargetTexChainList.begin(); it != m_TargetTexChainList.end(); ++it )
		{
			MIX_RELEASE( ( *it ).pInterface );
		}
	}
}

void ResourceManager::ReleaseOwner( UInt32 owner )
{
	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ターゲットテクスチャ
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_TargetTexList.size() > 0 )
	{
		ResourceManager::TargetTextureList::iterator it = m_TargetTexList.begin();
		while( it != m_TargetTexList.end() )
		{
			if( MIX_TESTBIT( it->owner, owner ) == owner )
			{
				it->owner ^= owner;

				if( it->owner == 0 )
				{
					MIX_RELEASE( it->pInterface );
					it = m_TargetTexList.erase( it );
				}
				else
				{
					it++;
				}
			}
			else
			{
				it++;
			}
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ターゲットテクスチャチェイン
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_TargetTexChainList.size() > 0 )
	{
		ResourceManager::TargetTextureChainList::iterator it = m_TargetTexChainList.begin();

		while( it != m_TargetTexChainList.end() )
		{
			if( MIX_TESTBIT( it->owner, owner ) == owner )
			{
				it->owner ^= owner;

				if( it->owner == 0 )
				{
					MIX_RELEASE( it->pInterface );
					it = m_TargetTexChainList.erase( it );
				}
				else
				{
					it++;
				}
			}
			else
			{
				it++;
			}
		}
	}
}

UInt32 ResourceManager::CameraOwner( UInt32 index )
{
	return 1 << index;
}

}}}
