#include "Leggi.h"

#define MakeID(a,b,c,d)  ( (ULONG)(a)<<24L | (ULONG)(b)<<16L | (c)<<8 | (d) )
#define FORM    MakeID('F','O','R','M')
#define ID_FTXT MakeID('F','T','X','T')
#define ID_CHRS MakeID('C','H','R','S')
#define ID_FONS MakeID('F','O','N','S')
#define CHUNKID(x) (*((ULONG *)(x)))
#define CHUNKLEN(x) (*((ULONG *)((x)+4)))

typedef struct {
	UBYTE id;
	UBYTE pad1;
	UBYTE proportional;
	UBYTE serif;
	char name[100];
} FontSpecifier;


/*
*
* SetHeights()
*
* takes a DisplayStatus *, sets correctly Heights and Baselines
* and returns the total length.
*
*/

__regargs int SetHeights(DisplayStatus *D) {

	register char *l;
	register LDesc *LineDesc = D->Buffer;
	register short int i;
	register int n=0;

	while(l = LineDesc->Line) {
		LineDesc->Height = LineDesc->Baseline = 0;
		if (!*(l+2) && *(l+3)!=-1) l+=3;

		while(*l != ENDOFSTREAM) {

			if (*l != TABCHAR) {
				i = FONTNUMBER(*l);
				if (LineDesc->Height < D->FontTable[i]->tf_YSize) LineDesc->Height = D->FontTable[i]->tf_YSize;
				if (LineDesc->Baseline < D->FontTable[i]->tf_Baseline) LineDesc->Baseline = D->FontTable[i]->tf_Baseline;
				l += strlen(l+2)+3;
			}
			else l++;
	   }
		n += (LineDesc->Height += D->LineSpacing);
		LineDesc++;
	}

	return(n);
}

/*
*
* IsFTXT()
*
* takes a char *, and tells you if the file is FTXT.
*
*/

__regargs int IsFTXT(char *p) {
	return( (CHUNKID(p) == FORM) && (CHUNKID(p+8) == ID_FTXT) );
}

/*
*
*
* OpenAndCrunch()
*
* Opens an IFF or ASCII file, converting it to Leggi's internal buffer;
* Writes through BufPointer the LineDesc's array; returns zero if error,
* otherwise a valid RememberKey to dealloc the file. The FontTable is set
* up if it's an FTXT file. Some of the internal value are set up, but NOT
* the heights!
*/


__regargs int OpenAndCrunch(DisplayStatus *D) {

	long int h, l, WordWrapOffset;
	register short int newlines = 0, tabs = 0;
	register char *p, *q;
	LDesc *L;

	if (h = Open(D->Arg, MODE_OLDFILE)) {
		Seek(h, 0, OFFSET_END);
		l = Seek(h, 0, OFFSET_BEGINNING);

		if (q = AllocMem(l+1, MEMF_CLEAR | MEMF_PUBLIC)) {
			Read(h, q, l);
			for (p=q; p<q+l; p++)
				if (*p == '\n') newlines++;
				else if (*p == '\t') tabs++;

			WordWrapOffset = (D->WordWrap ? l/D->WordWrap : 0);

			if (D->Buffer = (void *)AllocRemember(&D->RememberKey, (newlines+3+WordWrapOffset)*sizeof(LDesc), MEMF_PUBLIC | MEMF_CLEAR))
				if (p = AllocRemember(&D->RememberKey, l+tabs*3+(newlines+2+WordWrapOffset)*3, MEMF_PUBLIC | MEMF_CLEAR)) {

/*				Printf("Allocati: linee:%ld  caratteri: %ld\n", (newlines+3+WordWrapOffset), l+tabs*3+(newlines+2+WordWrapOffset)*3);*/

					InitAutomaton(D->Buffer, p);
					SetWordWrap(D->WordWrap);
					SetTabSize(D->TabSize);

					if (IsFTXT(q)) ParseFTXTFile(q+12, l-12, D->FontTable);
					else {
						q[l] = '\n';
						ParseASCIIChars(q, l+1);
					}

					EndAutomaton();
					D->OldTLine = D->TLine = D->Buffer;
					L = D->Buffer;
					while((++L)->Line);
					D->LineLen = L-D->Buffer-1;
				}
			else FreeRemember(&D->RememberKey, TRUE);

/*			Printf("Usati: linee: %ld  caratteri: %ld\n", D->LineLen+2, (L-1)->Line-p+1);*/

			FreeMem(q, l+1);
		}
		Close(h);

		if (D->RememberKey) return(1);
	}
}

/*
*
* ParseFTXTFile()
*
* takes a pointer to a read buffer, the len of the buffer and a pointer to a
* FontTable. It parses the buffer as a IFF file and sets up the FontTable.
*
*/

__regargs void ParseFTXTFile(char *source, int len, struct TextFont **FontTable) {

	char *q = source;
	int chunklen;
	FontSpecifier *FontS;
	struct TextFont *TFont;


	while(q-source<len) {

		chunklen = CHUNKLEN(q);

		if (CHUNKID(q) == ID_FONS) {
			FontS = (FontSpecifier *)(q+8);
			if ((FontS->id>=0) && (FontS->id<MAXFONTS)) {

				TFont = FontTable[FontS->id];

				if ((FontTable[FontS->id] = OpenFontNamed(FontS->name, FontTable[MAXFONTS]->tf_YSize)) == NULL)
					FontTable[FontS->id] = TFont;
				else CloseFontSafely(&TFont, FontTable);
			}
		}
		else if (CHUNKID(q) == ID_CHRS) {
			ParseASCIIChars(q+8, chunklen);
		}

		q+=chunklen+chunklen%2+8;

	}

	ParseASCIIChars("\n", 1);
}


/*
*
* SaveAsASCII()
*
* saves the DisplayStatus pointed file in an ASCII format, with the name
* in D->Arg. Returns a non-NULL value is something is wrong.
*
*/

__regargs int SaveAsASCII(DisplayStatus *D) {

	int h, pos;
	LDesc *LineDesc;
	char *l, *tabs;

	if (tabs = ArpAlloc(D->TabSize)) memset(tabs, ' ', D->TabSize);

	if (h = Open(D->Arg, MODE_NEWFILE)) {

		LineDesc = D->Buffer;

		while(l = (LineDesc++)->Line) {

			pos = 0;

			while(*l != ENDOFSTREAM) {
				if (*l != TABCHAR) {
					l += 2;
					Write(h, l, strlen(l));
					pos += strlen(l);
					l += strlen(l);
				}
				else if (tabs) Write(h, tabs, D->TabSize-pos%D->TabSize);

				l++;
		   }

			Write(h, "\n", 1);
		}

		Close(h);
		if (tabs) FreeTrackedItem((void *)tabs);
		return(NULL);
	}
	else return(1);


}
