#include "Font.h"
#include "Renderer/PngImage.h"
#include "Utility/Log.h"

#include <cassert>

//////////////////////////////////////////////////////////////
namespace Dubious {
namespace Panels {

//////////////////////////////////////////////////////////////
Font::Font( Utility::NativeAssetFilePtr pNativeFile, int FontHeight )
	: m_Height( FontHeight )
{
	m_Letters.resize( 128 );
	LOG_INFO( "Loading Font Image File" );
	m_Image.reset( new Renderer::PngImage( pNativeFile ) );
	unsigned long ClearColour = m_Image->Data()[0];
	int Start = 0;
	int End = 0;
	int yTop = 0;
	int yBottom = m_Height;
	// capitol letters
	LOG_INFO( "Finding capitol letter set" );
	for( int i=0, j='A'; i<26; ++i, ++j )
		m_Letters[j] = FindLetter( Start, End, yTop, yBottom, ClearColour );
	// numbers
	LOG_INFO( "Finding numbers set" );
	for( int i=0, j='0'; i<10; ++i, ++j )
		m_Letters[j] = FindLetter( Start, End, yTop, yBottom, ClearColour );
	// the space is a cheat, just some blank space at the end
	LOG_INFO( "Finding extra set" );
	m_Letters[':'] = FindLetter( Start, End, yTop, yBottom, ClearColour );
	m_Letters['-'] = FindLetter( Start, End, yTop, yBottom, ClearColour );
	m_Letters['+'] = FindLetter( Start, End, yTop, yBottom, ClearColour );
	m_Letters['?'] = FindLetter( Start, End, yTop, yBottom, ClearColour );
	m_Letters['!'] = FindLetter( Start, End, yTop, yBottom, ClearColour );
	m_Letters[' '] = Math::RectangleYDown( m_Letters['!'].Origin() + Math::Point( 35, 0 ), m_Letters['9'].Dimensions() );
}

//////////////////////////////////////////////////////////////
Font::~Font()
{
}

//////////////////////////////////////////////////////////////
unsigned int Font::StringWidth( const std::string &Sentance ) const
{
	int RetVal = 0;

	for( unsigned int i=0; i<Sentance.length(); ++i ){
		char Letter = Sentance[i];
		RetVal += m_Letters[Letter].Dimensions().X();
		RetVal += LetterPad();
	}

	return RetVal;
}

//////////////////////////////////////////////////////////////
Math::RectangleYDown Font::LetterRectangle( char Letter ) const
{
	assert( Letter >= 0 && "Can't pass a negative Letter" );
	return m_Letters[Letter];
}

namespace
{

//////////////////////////////////////////////////////////////
int FindLetterStart( Renderer::PngImagePtr pImage, int Start, int yTop, int yBottom, unsigned long Background )
{
	if (Start >= pImage->Dimensions().X()) {
		return -1;
	}
	const unsigned long *Data = pImage->Data();
	for (unsigned int x=Start; x<pImage->Dimensions().X(); ++x) {
		for (int y=yTop; y<yBottom; ++y) {
			unsigned long Current = Data[x + (y*pImage->Dimensions().X())];
			if (Current != Background) {
				return x;
			}
		}
	}

	return -1;
}

//////////////////////////////////////////////////////////////
int FindLetterEnd( Renderer::PngImagePtr pImage, int Start, int yTop, int yBottom, unsigned long Background )
{
	if (Start >= pImage->Dimensions().X()) {
		return -1;
	}
	const unsigned long *Data = pImage->Data();
	for (unsigned int x=Start; x<pImage->Dimensions().X(); ++x) {
		bool bAllClear = true;
		for (int y=yTop; y<yBottom; ++y) {
			unsigned long Current = Data[x + (y*pImage->Dimensions().X())];
			if( Current != Background ){
				bAllClear = false;
				break;
			}
		}
		if (bAllClear) {
			return x;
		}
	}

	return -1;
}
}

//////////////////////////////////////////////////////////////
Math::RectangleYDown Font::FindLetter( int &xStart, int &xEnd, int &yTop, int &yBottom, unsigned long ClearColour ) const
{
	xStart = FindLetterStart( m_Image, xEnd, yTop, yBottom, ClearColour );
	if( xStart == -1 ){
		yTop += m_Height;
		yBottom += m_Height;
		xEnd = 0;
		xStart = FindLetterStart( m_Image, xEnd, yTop, yBottom, ClearColour );
	}
	xEnd = FindLetterEnd( m_Image, xStart, yTop, yBottom, ClearColour );
//	LOG_INFO( "Found Letter: (" << xStart << ", " << yTop << ")  -  (" << xEnd << ", " << yBottom << ")" );
	return Math::RectangleYDown( Math::Point(xStart,yTop), Math::Size(xEnd-xStart,yBottom-yTop) );
}

}}
