#include	<stdlib.h>
#include	<stdio.h>
#include	<string.h>
#include	"font.h"
#include	"picture.h"

int		ReadNumberList(char *str, long *out, int nout);
char	*NewLine(char *str);
int	ReadLongValue(char *str, char *key, long *out);

//******************************************************
//	GXLoadFont()
//******************************************************
//	Create font data out of a picture file and a text
//	file with cut data in it
//******************************************************
TXFONT	*TXLoadFont(GXPICTURE *fontpic, char *cutname, GXPALETTE *FrontColor)
{
	TXFONT		*f=0;
	size_t		size;
	char		*cuttxt=0,*temp=0,*loc,*pos;
	long		Values[8];
	TXCUTDATA	*cut;
	int			j,ix,iy,n;
	UBYTE		*flags=0,*to,*to2;
	GXPALETTE	*pal;
	GXPICTURE	*pic=0;
	GXPALETTE	BackColor={0,0,0,0};
	UBYTE		found[256];
	
	f=(TXFONT *)GXGetMem(sizeof(TXFONT), MEMF_ZERO|MEMF_ABORT);	
		
	//	Copy & remap picture palette
	pic=CopyPicture(fontpic);
	if(!pic)goto fail;
	
	flags=(UBYTE *)GXGetMem(pic->NPalette*sizeof(UBYTE), MEMF_ABORT);
	to=flags;
	pal=pic->Palette;
	for(j=pic->NPalette; j;  j--){
		*to=pal->Red||pal->Green||pal->Blue;
		to++;
		pal++;
	}
	to=(UBYTE *)pic->Data;
	for(iy=pic->Height; iy; iy--){
		to2=to;
		for(ix=pic->Width; ix; ix--){
			if(flags[*to2]){
				*to2++=1;
			}else{
				*to2++=0;
			}
		}	
		to+=pic->BytesAcross;
	}	
	GXFreeMem(flags);
	flags=0;
	GXFreeMem(pic->Palette);
	pic->NPalette=2;
	pic->Palette=(GXPALETTE *)GXGetMem(2*sizeof(GXPALETTE), 0);
	if(!pic->Palette)goto fail;
	pal=pic->Palette;
	pal[0]=BackColor;
	pal[1]=*FrontColor;
	
	//	Convert to image and get rid of picture data	
	f->Image=GXPictureToImage(pic, 1, 0);
	if(!f->Image)goto fail;
	KillPicture(pic);
	pic=0;
	
	//	Load in cut data text file for font and make sure theres a zero on the end
	temp=(char *)GXLoadFileToMemory(cutname, &size);
	if(!temp)goto fail;
	cuttxt=(char *)GXGetMem(size+1, MEMF_ABORT);
	memcpy(cuttxt, temp, size);
	cuttxt[size]=0;
	GXFreeMem(temp);
	temp=0;
	
	//	Check its the right sort of file
	loc=strstr(cuttxt,"PGFONT");
	if(!loc){
		GXPrintf("Couldnt find PGFONT string.\n");
	}
	if(loc!=cuttxt){
		GXPrintf("This file isnt a font file\n");
		goto fail;
	}

	//	Read in miscellaneous values
	if( !ReadLongValue(cuttxt,"HEIGHT=",&f->Height) )goto fail;
	if( !ReadLongValue(cuttxt,"ITALIC=",&f->Italic) )goto fail;
	if( !ReadLongValue(cuttxt,"PROPORTIONAL=",&f->Proportional) )goto fail;
	if( !ReadLongValue(cuttxt,"BOLD=",&f->Bold) )goto fail;
	if( !ReadLongValue(cuttxt,"UNDERLINED=",&f->Underlined) )goto fail;
	if( !ReadLongValue(cuttxt,"WIDTH=",&f->Width) )goto fail;
	if( !ReadLongValue(cuttxt,"BASELINE=",&f->BaseLine) )goto fail;

	GXPrintf("Height = %d\n", (int)f->Height);
	GXPrintf("Italic = %d\n", (int)f->Italic);
	GXPrintf("Proportional = %d\n", (int)f->Proportional);
	GXPrintf("Bold = %d\n", (int)f->Bold);
	GXPrintf("Underlined = %d\n", (int)f->Underlined);
	GXPrintf("Width = %d\n", (int)f->Width);
	GXPrintf("Base line = %d\n", (int)f->BaseLine);

		
	//	Read in the actual cut data
	loc=strstr(cuttxt, "\nCHARACTERDATA");
	if(!loc){
		GXPrintf("Couldnt find CHARACTERDATA\n");
		goto fail;
	}
	//	Read in characters defined in file
	memset(found, 0, sizeof(found));
	f->NCut=256;
	f->Cut=(TXCUTDATA *)GXGetMem( 256*sizeof(TXCUTDATA), MEMF_ABORT|MEMF_ZERO );
	pos=loc;
	while(1){
		pos=strstr(pos,"\n");
		if(!pos)goto fail;
		pos++;
		if(!*pos)goto fail;
		if(pos==strstr(pos,"ENDCHARACTERDATA")){
			GXPrintf("Reached ENDCHARACTERDATA\n");
			break;
		}
		if( !ReadNumberList(pos, Values, 8) ){
			GXPrintf("Failed to read data for character\n");
			goto fail;
		}
		n=Values[0];
		if( (n<256) && (n>=0) ){
			found[n]=1;
			cut=f->Cut + Values[0];
			cut->Oblong.X=Values[1];
			cut->Oblong.Y=Values[2];
			cut->Oblong.Width=Values[3];
			cut->Oblong.Height=Values[4];
			cut->XOffset=Values[5];
			cut->YOffset=Values[6];
			cut->XSpace=Values[7];
/*			if(n=='W'){
				GXPrintf("Char code = %d\n",n);
				GXPrintf("yoffset = %d\n",cut->YOffset);
				GXQuitCode("Done it\n");
			}
*/
		}
	}
	if(!found[0]){
		GXQuitCode("ERROR: Non print character not found in font\n");
	}
	//	Set non print characters
	for(j=0; j<256; j++){
		if(!found[n]){
			f->Cut[j]=f->Cut[0];
		}
	}
	
	//	Set data for control characters
	f->Cut[' '].Control=1;
	GXPrintf("Font successfully loaded!!\n");
	return	f;
fail:
	return	0;
}

//******************************************************
//	NewLine()
//******************************************************
//	Find position of first character past first return
//	Input:string
//	output: position found or zero
//******************************************************
char	*NewLine(char *str)
{
	char	letter;

	while(letter=*str++){
		if(letter=='\n'){
			return	str;
		}
	}
	GXPrintf("Couldnt find new line.\n");
	return	0;
}

//******************************************************
//	ReadNumberList()
//******************************************************
//	Read a series of numbers out of a string. The string
//	is terminated by 0 or new line and any non numerical
//	character is considered to be a seperator
//	Input: 	string to read,  output for values, number
//			of values wanted.
//	Output: Success?
//******************************************************
int		ReadNumberList(char *str, long *out, int nout)
{
	unsigned char	letter;
	long	        total=0,nread=0,sign=+1;
	
	while(letter = (unsigned char )*str++){
		if( (letter>='0') && (letter<='9') ){
			total=(total*10)+(letter-'0');
		}else if(letter=='-'){
			sign=-1;
		}else{
			*out++=(total*sign);
			total=0;
			sign=+1;
			nread++;
			if(nread==nout){
				return	1;
			}
			if(letter=='\n'){
				return	0;
			}		
		}
	}	
	*out++=total;
	nread++;
	return	(nread==nout);
}

//******************************************************
//	ReadLongValue()
//******************************************************
//	Search for the first occurence of 'key' in 'string'
//	and read the data following it as an ascii number.
//	input: string, key, output for result
//	output: Success?
//******************************************************
int	ReadLongValue(char *str, char *key, long *out)
{
	char 	*loc,letter;
	long	total;

	loc=strstr(str, key);
	if(!loc)return	0;
	loc+=strlen(key);
	total=0;
	while(1){
		letter=*loc++;
		letter-='0';
		if((letter>-0) && (letter<=9)){
			total=(total*10)+letter;
		}else{
			break;
		}
	}
	*out=total;
	return	1;
}

//******************************************************
//	TXFONTHeight()
//******************************************************
//	Returns height of font
//	input: font
//	output: height in pixels
//******************************************************
int		TXFONTHeight(TXFONT *f)
{
	return	f->Height;
}

//******************************************************
//	TXStringWidth()
//******************************************************
//	Returns pixel width of a string printed in the given
//	font.
//	input: string & font
//	output: width in pixels
//******************************************************
int		TXStringWidth(char *s, TXFONT *f)
{
	int			width=0;
	TXCUTDATA	*Cut,*CutData;
	ULONG		letter;

	CutData=f->Cut;
	while(letter=*s++){
		Cut=CutData+letter;
	
		if(Cut->Control){
			width+=f->Width;		
		}else{
			width+=(Cut->XOffset+Cut->Oblong.Width);
		}
	}
	return	width;
}

//******************************************************
//	TXPrintString()
//******************************************************
//	Print string onto an image
//	input: string, position, image & font 
//	output: none
//******************************************************
void	TXPrintString(char *s, int x, int y, GXIMAGE *i, TXFONT *f)
{
	GXBLITLIST	*Blit;
	ULONG		letter,nblit;
	TXCUTDATA	*Cut,*CutData;
	
	nblit=0;
	CutData=f->Cut;
	while(letter=*s++){
		Cut=CutData+letter;
		if(Cut->Control){
			x+=f->Width;
		}else{
			Blit=GXNextBlit();
			Blit->Type=BLIT_IMAGE;
			Blit->FromImage=f->Image;
			Blit->ToImage=i;
			Blit->From=Cut->Oblong;
			Blit->XTo=x+Cut->XOffset;
			Blit->YTo=y+Cut->YOffset;
			x += (Cut->XOffset+Cut->Oblong.Width);
		}
	}
}