#include "gosgml.hpp"
#include "toc.h"

/*
struct TocItem
{
	char* Target;
	char* Name;
	unsigned char Level;
	TocItem* FirstChild;
	TocItem* NextSibling;
	bool Open;
};
*/
TocItem::TocItem()
{
	Target=NULL;
	Name=NULL;
	Level=0;
	FirstChild=NULL;
	NextSibling=NULL;
	Open=false;
}

TocItem::~TocItem()
{
	if(Target)
		delete[] Target;
	if(Name)
		delete[] Name;
	if(FirstChild)
		delete FirstChild;
	if(NextSibling)
		delete NextSibling;
}

Toc::Toc(char* Input, char* fontPath, char* imagePath, char* defaultPagePath, rect* DisplayTextArea, int tabwidth)
:Dim(DisplayTextArea)
{
	if(!Input)
		return;
	Interpret(Input);
	Text=MakeGML();
	DS=new GML(fontPath, imagePath, defaultPagePath, DisplayTextArea, tabwidth);
	//SB=new Scrollbar();
}

Toc::~Toc()
{
	if(Text)
		delete[] Text;
	delete Head;
	delete DS;
	//if(SB)
	//	delete SB;
}

char* Toc::Click(int x, int y)
{
	char* CR=DS->Click(x,y);
	if(!CR)
		return NULL;
	if(strlen(CR)==8 && *(CR)=='*' && *(CR+1)=='|')
	{
		TocItem* Tog=(TocItem*)sstoi((unsigned char*)CR+2);
		Tog->Open^=1;
		if(Text)
			delete[] Text;
		Text=MakeGML();
		return NULL;
	}
	return CR;
}

int Toc::Draw()
{
	return DS->DisplayGML(Text);
}

void Toc::SetScrollOffset(int x)
{
	DS->SetScrollOffset(x);
}

void Toc::Interpret(char* Data)
{
	char* Data2=Data;
	Head=new TocItem;
	SInterpret(Data2,Head,0);
	TocItem* Victim = Head;
	Head=Head->FirstChild;
	Victim->FirstChild=NULL;
	delete Victim;
}

void Toc::SInterpret(char*& Data, TocItem* Parent, int Level) //handle the children of this node
{
	TocItem* LastSibling=NULL;
	TocItem* Current=NULL;
	char* DataO;

	while(1)
	{
		if(*Data=='*')	//end of data marker
			return;
		DataO=Data;
		while(*DataO == '\t')
			DataO++;
		if(Level != DataO-Data)
			if(Level+1 == DataO-Data)
				if(LastSibling)
					SInterpret(Data,LastSibling,Level+1);
				else
					STOP(("Toc::SInterpret Corrupt data"));
			else
				if(Level > DataO-Data)
					return;
				else
					STOP(("Toc::SInterpret Corrupt data"));
		else
		{
			Current=new TocItem;
#pragma warning(disable:4244)
			Current->Level=Level;
#pragma warning(default:4244)
			Data=DataO;
			while(*DataO != '|')
				DataO++;
			Current->Name=MemToStr(Data,DataO-Data);
			do{
				DataO++;
			}while(*DataO=='\t');
			Data=DataO;
			while(*DataO != '\n')
				DataO++;
			Current->Target=MemToStr(Data,DataO-Data-1);
			if(!LastSibling)
				Parent->FirstChild=Current;
			else
				LastSibling->NextSibling=Current;
			LastSibling=Current;
			Data=DataO+1;
		}
	}
}

char* Toc::MakeGML()
{
	char* Buffer=new char[131072];	//128 K... I really hope we don't ever need more!!
	*(Buffer+131071)=3;
	char* SBuffer=Buffer;
	SMakeGML(SBuffer,Head);
	if(*(Buffer+131071)!=3)
		STOP(("Toc::MakeGML() Sadly, you have a TOC which is huge. The 128k buffer overflowed. Do you really need so many items?"));
	char* Buffer2=DupStr(Buffer);
	delete[] Buffer;			//don't cache 128 if you don't really need it ne
	return Buffer2;
}

void Toc::SMakeGML(char*& Data, TocItem* Item)
{
	int Temp1;
	memcpy(Data,"<p>               ",Item->Level+3);
	Data+=Item->Level+3;
	if(Item->FirstChild)
	{
		if(Item->Open)
			memcpy(Data,"<a name=\"plaintext\" href=\"*|      \">-</a>",41);
		else
			memcpy(Data,"<a name=\"plaintext\" href=\"*|      \">+</a>",41);
		itoss((int)Item,(unsigned char*)(Data+28));
		Data+=41;
	}
	else
	{
		*(Data)=' ';
		*(Data+1)=' ';
		Data+=2;
	}
	memcpy(Data,"<a name=\"plaintext\" href=\"",26);
	Data+=26;
	Temp1=strlen(Item->Target);
	memcpy(Data,Item->Target,Temp1);
	Data+=Temp1;
	memcpy(Data,"\">",2);
	Data+=2;
	Temp1=strlen(Item->Name);
	memcpy(Data,Item->Name,Temp1);
	Data+=Temp1;
	memcpy(Data,"</a></p>",8);
	Data+=8;
	if(Item->Open && Item->FirstChild)
		SMakeGML(Data,Item->FirstChild);
	if(Item->NextSibling)
		SMakeGML(Data,Item->NextSibling);
	*Data=0;
	return;
}

void Toc::itoss(int I, unsigned char* Dest)
{
	*(int*)(Dest+1)=I;
	*Dest='0';
	while(*(Dest+1)==0 || *(Dest+1)=='"' || *(Dest+1)=='>' || *(Dest+2)==0 || *(Dest+2)=='"'  || *(Dest+2)=='>' || *(Dest+3)==0 || *(Dest+3)=='"'  || *(Dest+3)=='>' || *(Dest+4)==0 || *(Dest+4)=='"' || *(Dest+4)=='>')
	{
		*Dest++;
		(*(Dest+1))++;
		(*(Dest+2))++;
		(*(Dest+3))++;
		(*(Dest+4))++;
	}
}

int Toc::sstoi(unsigned char* S)
{
	if(*S != '0')
	{
#pragma warning(disable:4244)
		unsigned char D = *S - '0';
		*(S+2)-=D;
		*(S+2)-=D;
		*(S+3)-=D;
		*(S+4)-=D;
#pragma warning(default:4244)
	}
	return *(int*)(S+1);
}