
#include <Spectre/System/File.h>
#include <Spectre/System/Log.h>
#include <Spectre/Graphics/Font.h>
#include <Spectre/Graphics/Image.h>
#include <Spectre/Graphics/Texture.h>
#include <Spectre/Math/Math.h>
#include "Font/FreeTypeDriver.h"

Font::Font() :
m_driver	(new FreeTypeDriver())
{
}

Font::~Font()
{
	delete m_driver;
}

bool Font::loadFromFile(const std::string& filename)
{
	if (!m_driver->loadFromFile(filename)) {
		return false;
	}

	if (!m_driver->setCharacterSize(22)) {
		return false;
	}

	m_cacheTextureA.shelf = 0;
	m_cacheTextureA.texpos = vec2u(0, 0);

	createTexture();

	return true;
}

bool Font::loadFromMemory(const void *data)
{
	return false;
}

Font::Glyph Font::getGlyph(unsigned int code) const
{
	if (m_charset.find(code) == m_charset.end()) {

		loadChar(code);
	}
	return m_charset[code];
}

void Font::loadChar(unsigned char code) const
{
	Image img;
	Font::Glyph glyph;

	if (!m_driver) {
		return;
	}

	glyph = m_driver->loadGlyph(code, img);

	if (glyph.size > vec2b(0, 0)) {

		Vector2u pos = findTextureRegion(img);

		m_cacheTextureA.texture.enable();
		m_cacheTextureA.texture.update(pos, img);

		glyph.texture = &m_cacheTextureA.texture;
		glyph.texture_origin = vec2u(pos.x, pos.y);
	} else {
		glyph.texture = NULL;
	}

	m_charset[code] = glyph;
}

void Font::createTexture()
{
	m_cacheTextureA.texture.create(128, 32, PixelFormat::PF_Alpha);
	m_cacheTextureA.texture.enable();
	m_cacheTextureA.texture.setSmooth(true);
	m_cacheTextureA.texture.disable();
}

void Font::resizeTexture() const
{
	Texture& tex = m_cacheTextureA.texture;
	unsigned int nextSize = math::nextPowerOfTwo(tex.getSize().y + 1);

	Image tmpImg = tex.copyToImage();

	// recreate texture.
	tex.create(tex.getSize().x, nextSize, tmpImg.getFormat());
	tex.update(vec2u(0, 0), tmpImg);
}

Vector2u Font::findTextureRegion(const Image& img) const
{
	Vector2u pos;

	if (m_cacheTextureA.texpos.x + img.getWidth() + 1 > m_cacheTextureA.texture.getSize().x) {
		m_cacheTextureA.texpos.y += m_cacheTextureA.shelf;
		m_cacheTextureA.texpos.x = 0;
		m_cacheTextureA.shelf = 0;
	}

	if (img.getHeight() + 1 > m_cacheTextureA.shelf) {
		m_cacheTextureA.shelf = img.getHeight() + 1;
		if (m_cacheTextureA.texpos.y + m_cacheTextureA.shelf > m_cacheTextureA.texture.getSize().y) {
			resizeTexture();
		}
	}
	
	pos = m_cacheTextureA.texpos;

	m_cacheTextureA.texpos.x += img.getWidth() + 1;

	return pos;
}

const Texture* Font::getTexture() const
{
	return &m_cacheTextureA.texture;
}
