/*********************************************************************//**
*	\brief Fonts library.
*	Databaze fontu a definice objektu DString, coz predstavuje
*	retezec, ktery lze rovnou pomoci OpenGL vykreslit se zadanym fontem.
*
*	\author Michal Jirous
*	\date 14.7.2008
*	\file fonts.h
**********************************************************************/

//TODO je tu bordel, takze by bylo vhodny to trochu upravit

#ifndef __FONTS_H__
#define __FONTS_H__


#include "textureslib.h"
#include <map>
#include <list>

const int FREETYPE_FONT_NUM_CHARS		=	256;
const float LINE_HEIGHT_MULTIPLIKATOR	=	1.5f;
static const char*	FONT_DEFAULT		= "REGULAR";
enum
{
	FONT_IDENT = 1,
	FONT_LEFT_VINCULUM,
	FONT_RIGHT_VINCULUM,
	FONT_EQUAL,
	FONT_COMMA
};

enum
{
	FONT_ALIGN_LEFT = 0,
	FONT_ALIGN_CENTER,
	FONT_ALIGN_RIGHT
};

struct Font
{
	unsigned int m_iLetterWidth, m_iLetterHeight;
	GLuint m_iCharacterTable;
	std::string m_sName;
	std::string m_sFileName;
	virtual bool compile() = 0;
	virtual void decompile() = 0;
	virtual int draw(std::string &text, float x_pos, float y_pos) = 0;
	virtual unsigned int getCharacterWidth( unsigned char c) = 0;
	float getLineWidth()
	{
		return (float)m_iLetterHeight / 2.0f + (float)m_iLetterHeight * LINE_HEIGHT_MULTIPLIKATOR;
	}
};

struct TextureFont : public Font
{
	unsigned int m_iCharsPerRow;
	unsigned int m_iTextureWidth, m_iTextureHeight;

	TextureElement m_Texture;
	void setParameters( std::map<std::string,std::string> &params );
	virtual bool compile();
	virtual void decompile();
	int draw(std::string &text, float x_pos, float y_pos);
	unsigned int getCharacterWidth( unsigned char c)	{ return m_iLetterWidth; }
};

struct FreeTypeFont : public Font
{
	GLuint m_uiWidths[ FREETYPE_FONT_NUM_CHARS ];
	GLuint m_uiTextureIds[ FREETYPE_FONT_NUM_CHARS ];
	void setParameters( std::map<std::string,std::string> &params );
	virtual bool compile();
	virtual void decompile();
	int draw(std::string &text, float x_pos, float y_pos);
	unsigned int getCharacterWidth( unsigned char c)	{ return m_uiWidths[c]; }
};


namespace fontLibrary
{
	struct DString
	{
		struct TextLine
		{
			std::string m_sText;
			int width;
			int start_x;
			
			float compile( int ALIGN, Font *font );	//vraci vysku radku
			void reset();

			GLuint m_uiDListIndex;
			TextLine() : width(0), start_x(0), m_uiDListIndex(0) {}
			~TextLine()
			{
				glDeleteLists( m_uiDListIndex, 1 );
			}
		};
		Font *m_pFont;
		int m_iAlign;
		float m_iHeight;
		std::list<TextLine> *m_pLineList;
		int *m_iNumReferences;
		void draw( int x_pos, int y_pos );
		void draw( float x_pos, float y_pos );
		DString( std::string text, std::string fontName, int ALIGN = FONT_ALIGN_LEFT, int iMaxWidth = -1 );
		DString( std::string text, Font *font, int ALIGN = FONT_ALIGN_LEFT, int iMaxWidth = -1 );
		DString( std::string text );
		void init();
		DString( const DString & str )
		{ 
			m_iNumReferences = NULL;	
			m_pLineList = NULL;
			m_iAlign = 0;
			m_iHeight = 0;
			m_pFont = 0;
			operator=( str );
		}
		DString &operator=( const std::string text );
		DString &operator=( const DString & str );
		bool operator==( DString &dstring );
		void create( std::string text, std::string fontName, int ALIGN = FONT_ALIGN_LEFT, int iMaxWidth = -1, bool addonly = false );
		void create( std::string text, Font *font, int ALIGN = FONT_ALIGN_LEFT, int iMaxWidth = -1, bool addonly = false );
		void deepCopy();

		void add( std::string text, int iMaxWidth = -1 );
		void add( const char c, int iMaxWidth = -1 );
		bool empty()	{ return ( !m_pLineList || m_pLineList->empty() || !m_pFont );	}
		void destroy();
		void resize( int iNewMaxWidth );
		DString() { init(); }
		~DString()	{
			if( m_iNumReferences && m_pLineList)
			{
				(*m_iNumReferences)--;
				if( !(*m_iNumReferences) )
					destroy();
			}
		}
	};


	void loadFonts( std::string filename );
	Font *getFont( std::string name );
	void drawText( std::string &text, float x_pos, float y_pos, int ALIGN, Font *font );
	void drawText( std::string &text, float x_pos, float y_pos, int ALIGN, std::string name );
	void drawText( DString &ds, float x_pos, float y_pos );

	int simpleDrawText( std::string &line, float x_pos, float y_pos, Font *font );
	int simpleDrawText( std::string &line, float x_pos, float y_pos, std::string fontName );
	int simpleDrawTextFloated( std::string &line, float x_pos, float y_pos, Font *font );
	void destructor();
};
#endif
