#ifndef _RUUI_FONT_H_
#define _RUUI_FONT_H_

#include <map>
#include <vector>

#include "../Engine/Base/RuCore.h"
#include "../Scene/Base/RuSceneBase.h"

// Direct3D dependency -- BAD!
#include "../Direct3D/Engine/RuEngineD3D.h"

using namespace std;

// --------------------------------------------------------------------------------------
//
// 字型陰影參數
typedef struct
{
	DWORD color;
	short x, y;
} RuFontShadow;

// --------------------------------------------------------------------------------------
// 字型寬度
enum RuFontWeight
{
	ruFONTWEIGHT_THIN		= 0,
	ruFONTWEIGHT_NORMAL,
	ruFONTWEIGHT_BOLD,
};

enum RuFontOutline
{
	ruFONTOUTLINE_NONE		= 0,
	ruFONTOUTLINE_NORMAL,
	ruFONTOUTLINE_THICK
};

typedef void (*RuFontTextureCallBack)	();

// --------------------------------------------------------------------------------------
class CRuFontType
{
public:
	CRuFontType();
	virtual ~CRuFontType();

	// static function
	static	void			Initialize();
	static	void			Shutdown();	
	static	CRuFontType*	GetFontType( const char *fontNameStr, int height, RuFontWeight weight, RuFontOutline RuFontOutline );

	// member function
	void					PaintToMem(const WCHAR wchar, DWORD *pPixels, SIZE &size);
	const char*				GetFontName()					{ return m_fontStr; }
	HFONT					GetFontHandle()					{ return m_hFont; }
	RuFontWeight			GetWeight()						{ return m_weight; }
	RuFontOutline			GetOutLine()					{ return m_outLine; }
	int						GetSerial()						{ return m_serial; }
	int						GetHeight()						{ return m_height; }
	int						GetRealHeight()					{ return GetHeight(); }

protected:
	static	CRuArrayList<CRuFontType*>	s_fontType;		

	static	HDC							s_hDC;					// DC Handle
	static	HFONT						s_hCurrentFont;			// Font Handle
	static	HBITMAP						s_hbmBitmap;			// Bitmap Handle
	static	DWORD*						s_pBitmapBits;			// Bitmap Pointer

	static	CRuImageFX_Resampler_32		s_imageResampler;

	HFONT								m_hFont;
	char*								m_fontStr;
	int									m_serial;
	int									m_height;
	RuFontOutline						m_outLine;
	RuFontWeight						m_weight;

	int									m_realHeight;
};

// --------------------------------------------------------------------------------------
class CRuFontChar;
class CRuFontTexture
{
public:
	CRuFontTexture();
	virtual ~CRuFontTexture();	

	// static function
	static	bool			Initialize( RuFontTextureCallBack func );
	static	void			Shutdown();
	static	bool			ReadFontTexture( CRuFontChar *pFontChar );
	static	void			PaintBegin();
	static	int				GetFreeFontCapacity()				{ return s_freeFont.Count(); }
	static	CRuTextureD3D*	GetRuTextureD3D()					{ return s_pRuTexture; }
	static	INT32			GetRuTextureWidth()					{ return s_pRuTexture->GetLevelWidth(0); }
	static	INT32			GetRuTextureHeight()				{ return s_pRuTexture->GetLevelHeight(0); }

	// member function
	inline	void			Paint( float x, float y, float scale, DWORD color, RuFontShadow *pShadow = NULL );
	CRuRectangle			GetRectangle()						{ return m_rect; }

protected:
	static	CRuFontTexture*	GetFreeFontTexture();
	static	bool			Recycle( CRuFontTexture* pTexture );
	static	void			Rally();
	static	BOOL			RallyCallback(const void *key, const void *data, void *userData);

protected:
	static	CRuHashMap<int, CRuFontTexture*>	s_fontTexIndex;
	static	CRuStack<CRuFontTexture*>			s_freeFont;
	static	CRuFontTexture*						s_unitTexture;
	static	CRuTextureD3D*						s_pRuTexture;
	static	bool								s_isLockRally;
	static	RuFontTextureCallBack				s_rallyFunc;
	static	DWORD*								s_pPixels;
	static	CRuArrayList<int>					s_removedFontTexList;

	CRuFontChar*								m_pFontChar;	
	CRuRectangle								m_rect;
};

// --------------------------------------------------------------------------------------
class CRuFontChar
{
public:
	CRuFontChar();
	virtual ~CRuFontChar();

	// static function
	static	void			Initialize( RuFontTextureCallBack func );
	static	void			Shutdown();
	static	CRuFontChar*	GetFontChar( CRuFontType *pFontType, WCHAR wchar );
	static	void			PaintBegin()			{ CRuFontTexture::PaintBegin(); }	
	static	bool			DrawText( CRuFontType* pFontType, float x, float y, int color, const WCHAR* textStr );
	static	bool			DrawTextA( CRuFontType* pFontType, float x, float y, int color, const char* textStr );

	// member function
	inline	void			Paint( float x, float y, float scale, DWORD color, RuFontShadow *pShadow = NULL );
	inline	CRuFontTexture*	GetFontTexture();
	const CRuFontType*		GetFontType()			{ return m_pFontType; }
	WCHAR					GetChar()				{ return m_char; }
	float					GetXSize()				{ return m_x; }
	float					GetYSize()				{ return m_y; }

protected:
	friend class CRuFontTexture;

	static	CRuHashMap<int, CRuFontChar *>	s_fontChar;

	CRuFontTexture*							m_pFontTex;
	CRuFontType*							m_pFontType;
	float									m_x, m_y;
	WCHAR									m_char;	
};

// --------------------------------------------------------------------------------------
inline void CRuFontTexture::Paint( float x, float y, float scale, DWORD color, RuFontShadow *pShadow )
{
	if ( m_pFontChar )
	{
		CRuRectangle dest;

		dest.m_left		= x;
		dest.m_top		= y;
		dest.m_right	= x + m_pFontChar->m_x * scale;
		dest.m_bottom	= y + m_pFontChar->m_y * scale;

		if ( pShadow && (pShadow->color >> 24) > 0x08 )
		{
			CRuRectangle shadowRect = dest;
			DWORD col = pShadow->color & 0xFFFFFF;
			shadowRect.m_left	+= (float)pShadow->x;
			shadowRect.m_right	+= (float)pShadow->x;
			shadowRect.m_top	+= (float)pShadow->y;
			shadowRect.m_bottom	+= (float)pShadow->y;
			
			col |= ((pShadow->color >> 24) * (color >> 24) / 255) << 24;
			g_ruSceneRenderer->Ru2D_Submit(1, &m_rect, &shadowRect, &col);
		}
		
		g_ruSceneRenderer->Ru2D_Submit(1, &m_rect, &dest, &color);
	}
}

// --------------------------------------------------------------------------------------
inline void CRuFontChar::Paint( float x, float y, float scale, DWORD color, RuFontShadow *pShadow )
{
	if ( m_pFontTex == NULL && !CRuFontTexture::ReadFontTexture(this) )
		return;

	m_pFontTex->Paint( x, y, scale, color, pShadow );
}

// --------------------------------------------------------------------------------------
inline CRuFontTexture* CRuFontChar::GetFontTexture()
{
	if ( m_pFontTex == NULL )
		CRuFontTexture::ReadFontTexture(this);
	return m_pFontTex;
}

extern RUAPI char *TransToChar(const WCHAR* text);
extern RUAPI WCHAR *TransToWChar(const char* text);

#endif //_FONTCHAR_H
