#include"CFontCache.h"
#include"../Auxiliary/Debug/CAssert.h"
#include"../Auxiliary/Debug/CTrace.h"
#include"../Auxiliary/CString.h"

#include"CGraphic.h"
#include"CRenderMessageImpl3.h"
#include"Core/Driver/CPlaneTransiter.h"
#include"CResourceNameGenerator.h"

namespace Maid
{


/*!
 	@class	CTextureFont CFontCache.h
 	@brief	CFontCache 内で管理されるテクスチャ
 */

	int CFontCache::CTextureFont::s_AutoInc;

CFontCache::CTextureFont::CTextureFont()
{

}

CFontCache::CTextureFont::CTextureFont( const CTextureFont& rha )
{
	m_pInfo = rha.m_pInfo;
}


CFontCache::CTextureFont::~CTextureFont()
{
	Destroy();
}



void CFontCache::CTextureFont::Load( const SPSURFACEBUFFER& pBuff )
{
	Destroy();

	boost::shared_ptr<CTextureBufferMemory> pTex( new CTextureBufferMemory );

	const SIZE2DI		ImageSize	= pBuff->GetSize();
	const PIXELFORMAT	Format		= pBuff->GetPixelFormat();

	{
		pTex->Create( ImageSize, Format );

		const RECT2DI rc( POINT2DI(0,0), ImageSize );

		ISurfaceBuffer& dst = pTex->GetSurface(0);
		const ISurfaceBuffer& src = *pBuff;

		CPlaneTransiter::Blt( dst, &rc, src, &rc );
	}

	{
		const mstring id = TEXTURENAME::GeneratFont(s_AutoInc);

		GlobalPointer<CGraphic>::Get()->RegistTexture( id, pTex );

	}

	m_pInfo.reset( new INFO );
	m_pInfo->ImageSize = ImageSize;
	m_pInfo->Format = Format;
	m_pInfo->ID     = s_AutoInc;


	++s_AutoInc;
}

void CFontCache::CTextureFont::Destroy()
{
	if( m_pInfo.get()==NULL ) { return ; }

	if( m_pInfo.unique() )
	{
		const mstring id = TEXTURENAME::GeneratFont(m_pInfo->ID);
		GlobalPointer<CGraphic>::Get()->DeleteTexture( id );
	}

	m_pInfo.reset();

}

SIZE2DI		CFontCache::CTextureFont::GetSize()const
{
	MAID_ASSERT( m_pInfo.get()==NULL, MAIDTEXT("まだ作成されていません") );
	return m_pInfo->ImageSize;
}


PIXELFORMAT	CFontCache::CTextureFont::GetPixelFormat()const
{
	MAID_ASSERT( m_pInfo.get()==NULL, MAIDTEXT("まだ作成されていません") );
	return m_pInfo->Format;
}

mstring CFontCache::CTextureFont::GetID() const
{
	MAID_ASSERT( m_pInfo.get()==NULL, MAIDTEXT("まだ作成されていません") );
	return TEXTURENAME::GeneratFont(m_pInfo->ID);
}


CFontCache::CTextureFont& CFontCache::CTextureFont::operator = ( const CFontCache::CTextureFont& rha )
{
	Destroy();

	m_pInfo = rha.m_pInfo;

	return *this;
}



/*!
 	@class	CFontCache CFontCache.h
 	@brief	CTextureFont のキャッシュ管理クラス
\n			こいつがうまくやりくりする
 */

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! コンストラクタ
/*!
 */
CFontCache::CFontCache()
{
	m_CacheTable.SetCacheSize( 200 );
	m_CacheTable.SetGarbageState( CACHETABLE::GARBAGESTATE_MANUAL );
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! デストラクタ
/*!
 */
CFontCache::~CFontCache()
{

}


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! フォントテクスチャの取得
/*!
 	この関数を呼び出すだけで自動的に、キャッシュの破棄、作成、更新
\n	を行ってくれます
 
 	@param	pFont		[i ]	取得したいフォント
 	@param	FontCode	[i ]	取得したいフォントコード
 */
const CTexture& CFontCache::GetCache( const SPFONT& pFont, unt32 FontCode )
{
	CACHEKEY MapKey(pFont,FontCode);

	if( m_CacheTable.IsExist(MapKey) )
	{
		return m_CacheTable.GetData(MapKey);
	}

	CTextureFont tex;
	
	const SPSURFACEBUFFER pRaster = m_pFontDriver->Rasterize( pFont, FontCode );

	tex.Load( pRaster );

	m_CacheTable.Regist( MapKey, tex );
	return m_CacheTable.GetData(MapKey);
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! キャッシュをすべてクリアする
/*!
 */
void CFontCache::ClearCache()
{
	m_CacheTable.ClearAll();
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! キャッシュとして保持する数を変更する
/*!
 	@param	Size			[i ]	最低限キャッシュしておく数
 */
void CFontCache::SetCacheSize( int Size )
{
	m_CacheTable.SetCacheSize(Size);
}


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! キャッシュの掃除
/*!
 	@_CacheMax 個まで減少させます
 */
void CFontCache::Garbage()
{
	m_CacheTable.Garbage();
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! 初期化
/*!
 */
void CFontCache::Initialize( const SPFONTDRIVER& pFont )
{
	m_pFontDriver = pFont;
}

void CFontCache::Finalize()
{
	m_CacheTable.ClearAll();
	m_pFontDriver.reset();
}

CFontCache::CACHEKEY::CACHEKEY( const SPFONT& p, unt32 c )
{
	MAID_ASSERT( p.get()==NULL, "NULL" );
	FontName = p->GetFontName();
	Size = p->GetSize();

	IsAntialias = p->IsAntialias();
	IsBold      = p->IsBold();
	IsItalic    = p->IsItalic();

	Code   = c;
}

bool CFontCache::CACHEKEY::operator < ( const CACHEKEY& rhs ) const
{
	if( Code < rhs.Code ) { return true; }
	ef( Code > rhs.Code ) { return false; }

	if( FontName < rhs.FontName ) { return true; }
	ef( FontName > rhs.FontName ) { return false; }

	if( Size.w  < rhs.Size.w  ) { return true; }
	ef( Size.w  > rhs.Size.w  ) { return false; }

	if( Size.h < rhs.Size.h ) { return true; }
	ef( Size.h > rhs.Size.h ) { return false; }

	{
		const int a = IsAntialias? 0: 1;
		const int b = rhs.IsAntialias? 0: 1;

		if( a < b ) { return true; }
		ef( a > b ) { return false; }
	}

	{
		const int a = IsBold? 0: 1;
		const int b = rhs.IsBold? 0: 1;

		if( a < b ) { return true; }
		ef( a > b ) { return false; }
	}

	{
		const int a = IsItalic? 0: 1;
		const int b = rhs.IsItalic? 0: 1;

		if( a < b ) { return true; }
		ef( a > b ) { return false; }
	}
	return false;
}

}