#include ".\gamefont.h"

GameFont::GameFont(Loader *loader, Display *display, Surface *strip, char *charset, Pixel transcolor)
{
	this->LOADER = loader;
	this->strip=strip;
	this->_mustFreeStrip=false;
	FONTS=NULL;
	this->transColor=transcolor;
	this->charset=(char *)malloc(strlen(charset)+1);
	strcpy(this->charset, charset);
	raster=NULL;
	_separator=3;
	if (this->strip)
		raster=display->CreateRasterizer(this->strip);
	// cacha larghezza caratteri
	this->_CacheFontsetWidths(display);
}

GameFont::GameFont(Loader *loader, Display *display, const TCHAR *datfile, const TCHAR *filename, char *charset, Pixel transcolor)
{
	this->LOADER = loader;
	this->strip=LoadImage(datfile, filename);
	this->_mustFreeStrip=true;
	FONTS=NULL;
	this->transColor=transcolor;
	this->charset=(char *)malloc(strlen(charset)+1);
	strcpy(this->charset, charset);
	raster=NULL;
	_separator=3;
	if (this->strip)
		raster=display->CreateRasterizer(this->strip);
	// cacha larghezza caratteri
	this->_CacheFontsetWidths(display);
}

GameFont::~GameFont(void)
{
	int a;

	// libera strip se richiesto
	if (this->_mustFreeStrip)
		delete this->strip;
	delete this->raster;
	// libera charset
	free(this->charset);
	// libera tutti i fonts cachati
	struct font *tmpf;
	while (FONTS) { 
		tmpf=FONTS;
		FONTS = FONTS->next;
		for(a=0; a < MAX_FONT_CACHABLE_CHARS; a++)
			delete tmpf->surf[a];
		delete tmpf;
	}
}

// cacha la larghezza dei caratteri (vita zuga!)
void GameFont::_CacheFontsetWidths(Display *display)
{
	// cicla la riga 0
	bool searchEnd=false;
	unsigned char code;
	unsigned int cx, startat, endat, ichar = 0;

	for (cx = 0; cx < MAX_FONT_CACHABLE_CHARS; cx++) {
		STARTX[cx]=0;
		ENDX[cx]=0;
	}

	// sanity
	if (!this->strip || !this->raster)
		return;

	for (cx=0; cx < this->strip->GetWidth(); cx++) {
		// trovato marker
		if (raster->GetPixel(cx, 0) != transColor) {
			if (!searchEnd) {
				startat=cx;
				searchEnd=true;
			}
		} else { 
			// è la trasparenza
			if (searchEnd) {
				searchEnd=false;
				// fine ricerca
				endat=cx;
				if (ichar < strlen(this->charset)) {
					code = (unsigned char)this->charset[ichar];
					// abbiamo il carattere e possiamo cacharlo 
					if ( code < MAX_FONT_CACHABLE_CHARS ) {
						STARTX[code] = startat;
						ENDX[code] = endat;
					}
					// incrementa conto caratteri
				}
				++ichar;
			}
		}
	}
	PFrogConsole::instance()->addconsole(0, "CACHED FONTDIRECT");

} // void GameFont::_CacheFontsetWidths(Display *display)

void GameFont::SetSeparator(unsigned char sep)
{
	this->_separator=sep;
}


// disegna il carattere specificato, nella posizione specificata usando la modalità directfont
int GameFont::_DrawCharDirect(Display *display, char c, int x, int y)
{
	// disegna il nostro carattere (qui abbiamo già cachato)
	tmprect.left =	STARTX[ (unsigned char)c ];
	tmprect.right = ENDX[ (unsigned char)c ];
	tmprect.top = 2;
	tmprect.bottom = this->strip->GetHeight();

	display->Blit(x, y, this->strip, &tmprect);

	return tmprect.GetWidth();
} // int GameFont::_DrawCharDirect(Display *display, char c, int x, int y)


// disegna il carattere specificato, nella posizione specificata col colore specificato
int GameFont::_DrawCharColor(Display *display, char c, int x, int y, Pixel color)
{
	// controlla che il carattere sia cachabile e che ci sia la surface
	if ((unsigned char)c >= MAX_FONT_CACHABLE_CHARS)
		return 0;

	// controlla se abbiamo già cachato quel colore
	struct font *cached=NULL, *tmpf=FONTS;
	while (tmpf) {
		if (tmpf->color==color) {
			// colore già cachato
			cached=tmpf;
			break;
		}
		tmpf=tmpf->next;
	}


	// se il colore non era ancora in cache, è necessario cacharlo ora!
	if (!cached) {
		// salva il livello di blending corrente e toglilo durante il caching
		// lo risettiamo alla fine del caching
		unsigned char oldBlending = LOADER->CurrentBlending();
		display->SetBlending(255);
		unsigned int a, cx, startat, endat, ichar=0, px, py, dx, dy;
		bool searchEnd;
		unsigned char code;

		cached = new font;
		cached->next = FONTS;
		FONTS=cached;
		cached->color=color;
		for(a=0; a < MAX_FONT_CACHABLE_CHARS; a++)
			cached->surf[a]=NULL;

		// processa la pic
		//Pixel transColor=Color(0,0,0);

		// la trasparenza è nella riga 1
		//if (this->strip->GetHeight() > 1) {
		//	transColor = raster->GetPixel(0, 1);
		//}
		// nope, passiamola

		// cicla la riga 0
		searchEnd=false;
		for (cx=0; cx < this->strip->GetWidth(); cx++) {
			// trovato marker
			if (raster->GetPixel(cx, 0) != transColor) {
				if (!searchEnd) {
					startat=cx;
					searchEnd=true;
				}
			} else { 
				// è la trasparenza
				if (searchEnd) {
					searchEnd=false;
					// fine ricerca
					endat=cx;
					if (ichar < strlen(this->charset)) {
						code = (unsigned char)this->charset[ichar];
						// abbiamo il carattere e possiamo cacharlo 
						// e non era già cachato
						if (code < MAX_FONT_CACHABLE_CHARS && !cached->surf[code]) {

							cached->surf[code]=new Surface(endat-startat, this->strip->GetHeight()-2);	
							Surface *oldtarget = display->SetRenderTarget( cached->surf[code] );

							for (dx = 0, px=startat; px < endat; dx++, px++) {
								for (dy = 0, py=2; py < this->strip->GetHeight(); dy++, py++) {
									if (raster->GetPixel(px, py) != transColor)
										display->SetPixel(dx, dy, color);
									else
										display->SetPixel(dx, dy, transColor);
								}
							}

							display->SetRenderTarget( oldtarget );
							cached->surf[code]->SetColorMask(transColor);
							//cached->x1[code]=startat;
							//cached->x2[code]=cx;
						}
						// incrementa conto caratteri
					}
					++ichar;
				}
			}
		}

		// ripristina vecchio blending dopo che hai finito di cachare
		display->SetBlending( oldBlending );

		PFrogConsole::instance()->addconsole(0, "CACHED COLOR: %ld", color);
	} // colore non ancora cachato

	// qui, cached contiene comunque il nostro font cachato da usare
	// (sia se ce l'avevamo sia se l'abbiamo cachato ora)
	if (cached->surf[(unsigned char)c]) {
		display->Blit(x, y, cached->surf[(unsigned char)c]);
		return cached->surf[(unsigned char)c]->GetWidth();
	} else {
		return 0;
	}
} // int GameFont::_DrawCharColor(Display *display, char c, int x, int y, Pixel color)

// recupera la larghezza di un carattere
unsigned long GameFont::GetTextWidth(const char *text)
{
	// sanity checks
	if (!strip || !raster || strlen(text) == 0)	// no strip or selected pen present or no text to print
		return 0;

	unsigned char c;
	unsigned long width = 0;

	// calcola larghezza stringa
	for (unsigned int s = 0; s < strlen(text); s++) {
		c = (unsigned char)(text[s]);

		if (s > 0) // aggiunge larghezza spazio a partire dal secondo carattere, per ogni carattere
			width+=this->_separator;

		if (c < MAX_FONT_CACHABLE_CHARS) // Aggiunge larghezza carattere
			width+=(ENDX[c]-STARTX[c]);
	}
	
	return width;

} // unsigned long GameFont::GetTextWidth(char *text)

void GameFont::DrawText(Display *display, int x, int y, Pixel color, bool directmode, char *fmt, ...)
{
	char finalstr[MAX_VARGS_BUFFER_FONT];
	va_list		args;
	va_start(args, fmt);
	vsprintf(finalstr, fmt, args);
	va_end(args);

	// sanity checks
	if (!strip || !raster || strlen(finalstr) == 0)	// no strip or selected pen present or no text to print
		return;

	// iterate through chars
	int lastWidth;
	unsigned int drawAt = x;
	unsigned char index;
	for (unsigned short c=0; c < strlen(finalstr); c++) {
		index = (unsigned char)(finalstr[c]);
		if ( directmode ) 
			lastWidth = this->_DrawCharDirect(display, index, drawAt, y);
		else
			lastWidth = this->_DrawCharColor(display, index, drawAt, y, color);
		drawAt += (lastWidth+_separator); // CharSeparation;
	}

}
