/* -----------------------------------------------------------------------------
	GSFramework
	Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */


		#include <stdio.h>
		#include "core/raster_font.h"
		#include "core/render_resource_factory.h"
		#include "metafile/nml.h"
		#include "log/log.h"

		using namespace GS;
		using namespace GS::Render;


//------------------------------------------------------------------------------
float				RasterFont::GetHeight(bool normalized) const
{
	if	(normalized)
		return height;
	return GetPage(0) ? height * GetPage(0)->GetWidth() : -1;
}
float				RasterFont::GetBaseline(bool normalized) const
{
	if	(normalized)
		return baseline;
	return GetPage(0) ? baseline * GetPage(0)->GetWidth() : -1;
}
Vector2				RasterFont::ComputeLineRect(const char *s, bool normalized) const
{
	Vector2 r(0, height);
	for	( ; s[0] && s[0] != '\n'; ++s)
		if	(const Glyph *c = GetGlyphInfos(s[0]))
			r.x += c->step;

	if	(!normalized)
	{
		if	(GetPage(0))
		{
			r.x *= GetPage(0)->GetWidth();
			r.y *= GetPage(0)->GetHeight();
		}
		else
			r.Set(-1, -1);
	}
	return r;
}
Vector2			RasterFont::ComputeStringRect(const char *s, bool normalized) const
{
	Vector2 r(0, 0);

	forever
	{
		float w = 0;		// Line width.
		for	( ; s[0] && s[0] != '\n'; ++s)
			if	(const Glyph *c = GetGlyphInfos(s[0]))
				w += c->step;

		if	(w > r.x)		// Largest width.
			r.x = w;
		r.y += height;		// Line height.

		if	(!s[0])
			break;
		++s;				// Jump over the line feed.
	}

	if	(!normalized)
	{
		if	(GetPage(0))
		{
			r.x *= GetPage(0)->GetWidth();
			r.y *= GetPage(0)->GetHeight();
		}
		else
			r.Set(-1, -1);
	}
	return r;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
Texture				*RasterFont::GetPage(uint page) const
{	return (page < pages.GetCount()) ? pages.ObjectAt(page) : NULL;	}
const RasterFont::Glyph *RasterFont::GetGlyphInfos(uchar index) const
{	return glyph[index].available ? &glyph[index] : NULL;	}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
bool				RasterFont::Load(ResourceFactory &rf, const char *nml, const char *base)
{
	Unload();

	//-----------------------------------------------------------
	#define	RFL_ERROR(l)	{	(l); Unload(); return false;	}
	//-----------------------------------------------------------

	using namespace GS::NML;

	File file;
	if	(!Parser::Load(nml, file))
		RFL_ERROR(__LOG_E__ << "Failed to load raster font description file '" << nml << "'.\n")

	// Load font settings.
	Tag *root = file.GetTag("Font:Common;");
	if	(!root)
		RFL_ERROR(__LOG_E__ << "Missing base tag in font description ('" << nml << "').\n")

	uint page_count = 1;

	NMLTagForeach(tag, *root)
	{
				if	(tag->name == "Height")
				height = tag->GetReal();
		else	if	(tag->name == "BaseLine")
				baseline = tag->GetReal();
		else	if	(tag->name == "PageCount")
				page_count = tag->GetInteger();
		else	__LOG_W__ << "Unexpected tag in font description header ('" << tag->name << "').\n";
	}

	// Parse glyphs...
	root = file.GetTag("Font;");

	NMLTagForeach(tag, *root)
		if	(tag->name == "Char")
		{
			Tag *wrk = tag->GetTag("Id;");
			if	(!wrk || (wrk->GetType() != Variant::VariantInteger))
			{
				__LOG_W__ << "Glyph with no or invalid ID in font '" << nml << "', skipping.\n";
				continue;
			}

			int	glyphidx = wrk->GetInteger();
			if	(glyphidx > 255)
				continue;

			Glyph *pglyph = &glyph[glyphidx];
			pglyph->page = 0;
			pglyph->available = true;

			NMLTagForeach(wrk, *tag)
			{
						if	(wrk->name == "U")
						pglyph->u = wrk->GetReal();
				else	if	(wrk->name == "V")
						pglyph->v = wrk->GetReal();
				else	if	(wrk->name == "W")
						pglyph->w = wrk->GetReal();
				else	if	(wrk->name == "H")
						pglyph->h = wrk->GetReal();
				else	if	(wrk->name == "OffsetU")
						pglyph->offx = wrk->GetReal();
				else	if	(wrk->name == "OffsetV")
						pglyph->offy = wrk->GetReal();
				else	if	(wrk->name == "Step")
						pglyph->step = wrk->GetReal();
				else	if	(wrk->name == "Page")
				{
					if	((wrk->GetType() == Variant::VariantInteger) && ((uint)wrk->GetInteger() < page_count))
						pglyph->page = wrk->GetInteger();

					else
					{
						__LOG_W__ << "Invalid glyph page in font '" << nml << "' (Glyph #" << glyphidx << "), skipping.\n";
						pglyph->available = false;
						break;
					}
				}
			}
		}

	// Sanity check...
	if	(!glyph[' '].available)
		__LOG_W__ << "No space character in font '" << nml << "'.\n";

	// Load font pages.
	for	(uint n = 0; n < page_count; n++)
		if	(Texture *t = rf.LoadTexture(String::Format("%s_%02d.tga", base, n)))
			pages.Add(t);

	name = nml;
	return true;
}
void				RasterFont::Unload()
{
	pages.Clear();
	for	(uint n = 0; n < 256; n++)
		glyph[n].Reset();
}
//------------------------------------------------------------------------------
