#pragma once

#include <map>
#include <vector>

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

#include "../Renderer/RuRenderer.h"
#include "../Renderer/RendererNode/RuRendererNode_UI.h"

#pragma managed(push, off)

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)	();

// --------------------------------------------------------------------------------------
struct RuFontBase
{	
	int						index;
	char*					fontStr;	
	RuFontOutline			outline;
	RuFontWeight			weight;

	// Windows-based font variables
	HFONT					hFont;

	// FreeType-based font variables
	CRuMemoryStream*		m_fontStream;
};

// --------------------------------------------------------------------------------------
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 outline );

	// member function
	void					PaintToMem(const WCHAR wchar, const WCHAR* toneSymbol, IRuTexture *dstTexture, INT32 x, INT32 y, SIZE &size);
	const char*				GetFontName()					{ return m_fontBase->fontStr; }
	RuFontWeight			GetWeight()						{ return m_fontBase->weight; }
	RuFontOutline			GetOutLine()					{ return m_fontBase->outline; }
	int						GetFontBaseIndex()				{ return m_fontBase->index; }
	int						GetSerial()						{ return m_serial; }
	int						GetHeight()						{ return m_height; }
	void					GetFontSize(WCHAR wchar, WCHAR* toneSymbol, SIZE& outSize);
	
	int						GetRealHeight()					{ return GetHeight(); }

protected:
	static	bool						s_useFreeType;
	static	CRuArrayList<CRuFontType*>	s_fontType;
	static	vector<RuFontBase*>			s_fontBase;

	// Windows-based font variables
	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;		//!< Image sampler

	// FreeType-based font variables
	static void*						s_fontLibrary;			//!< FreeType font library

	// Common variables
	RuFontBase*							m_fontBase;				//!< Base font
	int									m_serial;				//!< Serial number
	int									m_height;				//!< Font height

	// FreeType-based font variables
	void*								m_fontFace;				//!< FreeType font face handle
};

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

	// static function
	static	bool			Initialize( RuFontTextureCallBack func );
	static	void			Shutdown();
	static	void			ReleaseAllFontIndex();

	static	void			PaintBegin();
	static	int				GetFreeFontCapacity()				{ return s_freeFont.Count(); }
	static	IRuTexture*		GetRuTextureD3D()					{ return s_pRuTexture; }
	static	INT32			GetRuTextureWidth()					{ return s_pRuTexture->GetLevelWidth(0); }
	static	INT32			GetRuTextureHeight()				{ return s_pRuTexture->GetLevelHeight(0); }	
	static	CRuFontTexture*	GetRuFontTexture(CRuFontType* fontType, WCHAR wchar, WCHAR* toneSymbol=NULL);
	static	CRuFontTexture* GetBlockTexture()					{ return s_blockTexture; }

	// member function
	void					Clear();
	void					SetToneSymbol(const WCHAR* toneSymbol);
	CRuRectangle			GetRectangle()						{ return m_rect; }

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

protected:
	static	CRuHashMap<INT64, CRuFontTexture*>	s_fontTexIndex;
	static	CRuStack<CRuFontTexture*>			s_freeFont;
	static	CRuFontTexture*						s_unitTexture;
	static	IRuTexture*							s_pRuTexture;
	static	bool								s_isLockRally;
	static	RuFontTextureCallBack				s_rallyFunc;
	static	DWORD*								s_pPixels;
	static	CRuArrayList<INT64>					s_removedFontTexList;
	static	CRuFontTexture*						s_blockTexture;
	
	WCHAR*										m_toneSymbol;
	CRuRectangle								m_rect;
};

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

	// static function
	static	void			Initialize( RuFontTextureCallBack func );
	static	void			Shutdown();
	static	int				GetToneSymbolNumber( WCHAR *toneSymbol );
	static	CRuFontChar*	GetFontChar( CRuFontType *pFontType, WCHAR wchar, WCHAR *toneSymbol=NULL );
	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
	void					Paint( float x, float y, float scale, DWORD color, RuFontShadow *pShadow = NULL, DWORD blockColor=0,bool bOutline = false );	
	const CRuFontType*		GetFontType()			{ return m_pFontType; }
	WCHAR					GetChar()				{ return m_char; }	
	float					GetXSize()				{ return m_x; }
	float					GetYSize()				{ return m_y; }
	CRuFontTexture*			GetFontTexture()		{ return CRuFontTexture::GetRuFontTexture(m_pFontType, m_char, m_toneSymbol); }

protected:
	static	CRuHashMap<INT64, CRuFontChar *>	s_fontChar;	
	CRuFontType*							m_pFontType;
	float									m_x, m_y;
	WCHAR									m_char;
	WCHAR*									m_toneSymbol;

	// Run-time
	CRuRectangle							m_runtime_SrcRects[6];
	CRuRectangle							m_runtime_DestRects[6];
	DWORD									m_runtime_Colors[6];
};

extern RUAPI char* TransToChar(const WCHAR* text);
extern RUAPI WCHAR* TransToWChar(const char* text);
extern RUAPI WCHAR* Utf8ToWChar(const char* text);
extern RUAPI WCHAR* MultiByteToWChar(const char* s);
extern RUAPI bool IsToneSymbol(WCHAR wch);

#pragma managed(pop)
