#include "ToolOS.hpp"
#include "gosgml.hpp"
#include "Rollover.h"
#include "History.h"
#ifdef GosGML_InternalTest
#define TESTLOG		1	//set this to 0 if you want all GosGML_InternalTest_Fail calls
						//to PAUSE instead of logging to file...

ImageData* InitImageData(int x, int y, char* ImageName, int ImageID);
void RolloverCBTest(int x, int y, char* ImageName, int ImageID);
int RolloverCBCount;
char* LastRolloverFileName;

char szFileName[] = "\\GML-Log.txt";
char FileNamePath[1024];
HGOSFILE* hLog = 0;
char errMsg[8192];

void __stdcall GosGML_InternalTest_Fail(const char* msg);

bool InternalTest()
{
	///////////////////////
	//** Start logging **//
	///////////////////////
	//open or create a log file in the default directory
	if (TESTLOG)
	{
		hLog = new HGOSFILE;
		gos_GetCurrentPath(FileNamePath, 1024);
		strcat(FileNamePath,szFileName);
		gos_OpenFile(hLog, FileNamePath, APPEND);
		strcpy(errMsg,"\r\n====< ");
		strcat(errMsg,gos_GetFormattedDate(0));
		strcat(errMsg," >====| GML INTERNAL TEST |====< ");
		strcat(errMsg,gos_GetFormattedTime());
		strcat(errMsg," >====\r\n"); //I'm sure there is an easier way to assemble this string
		gos_SeekFile(*hLog, FROMEND, 0);
		gos_WriteFile(*hLog, errMsg, strlen(errMsg));
	}
	//testing fail function...
	//GosGML_InternalTest_Fail("testing 1... 2... 3...");

	//////////////////////////////////
	//test NameValuePair public API	//
	//////////////////////////////////

	//////////////////////////
	//test HASH public API	//
	//////////////////////////

	//////////////////////////////
	//test History public API	//
	//////////////////////////////
	/*
	//History design has been changed, this is temporarily commented out pending update
	History* HistoryP=new History();
	if (HistoryP->Back())
		GosGML_InternalTest_Fail("History::Back when History empty returned a value when none expected. 0-a");
	if (HistoryP->Forward())
		GosGML_InternalTest_Fail("History::Forward when History empty returned a value when none expected. 0-b");
	if (!HistoryP->BackEmpty())
		GosGML_InternalTest_Fail("History::BackEmpty returned FALSE when TRUE expected. 0-c");
	if (!HistoryP->ForwardEmpty())
		GosGML_InternalTest_Fail("History::ForwardEmpty returned FALSE when TRUE expected. 0-d");

	char* szTestHist01=new char[15];
	strcpy(szTestHist01,"testingHist0-1");

	HistoryP->Add(szTestHist01);
	if (strcmp(HistoryP->Back(), "testingHist0-1"))
		GosGML_InternalTest_Fail("History::Back failed to return value expected from add. 0-1");
	if (HistoryP->Back())
		GosGML_InternalTest_Fail("History::Back when History empty returned a value when not expected. 0-e");

	delete HistoryP;		//delete the History object

	HistoryP=new History();		//create a new History object then comfirm it does not contain any History
	if (HistoryP->Back())
		GosGML_InternalTest_Fail("History::Back when History empty returned a value when none expected. 1-a");
	if (HistoryP->Forward())
		GosGML_InternalTest_Fail("History::Forward when History empty returned a value when none expected. 1-b");
	if (!HistoryP->BackEmpty())
		GosGML_InternalTest_Fail("History::BackEmpty returned FALSE when TRUE expected. 1-c");
	if (!HistoryP->ForwardEmpty())
		GosGML_InternalTest_Fail("History::ForwardEmpty returned FALSE when TRUE expected. 1-d");

	char* szTestHist11=new char[15];
	strcpy(szTestHist11,"testingHist1-1");
	char* szTestHist12=new char[15];
	strcpy(szTestHist12,"testingHist1-2");

	HistoryP->Add(szTestHist11);
	HistoryP->Add(szTestHist12);
	if (strcmp(HistoryP->Back(), "testingHist1-2"))
		GosGML_InternalTest_Fail("History::Back failed to return value expected from add. 1-2");
	if (strcmp(HistoryP->Back(), "testingHist1-1"))
		GosGML_InternalTest_Fail("History::Back failed to return value expected from add. 1-1");
	if (HistoryP->Back())
		GosGML_InternalTest_Fail("History::Back when History empty returned a value when not expected. 1-e");

	HistoryP->Clear();
	if (HistoryP->Back())
		GosGML_InternalTest_Fail("History::Back when History empty returned a value when none expected. 2-a");
	if (HistoryP->Forward())
		GosGML_InternalTest_Fail("History::Forward when History empty returned a value when none expected. 2-b");
	if (!HistoryP->BackEmpty())
		GosGML_InternalTest_Fail("History::BackEmpty returned FALSE when TRUE expected. 2-c");
	if (!HistoryP->ForwardEmpty())
		GosGML_InternalTest_Fail("History::ForwardEmpty returned FALSE when TRUE expected. 2-d");

	char* szTestHist21=new char[15];
	strcpy(szTestHist21,"testingHist2-1");
	char* szTestHist22=new char[15];
	strcpy(szTestHist22,"testingHist2-2");
	char* szTestHist23=new char[15];
	strcpy(szTestHist23,"testingHist2-3");
	char* szTestHist24=new char[15];
	strcpy(szTestHist24,"testingHist2-4");
	char* szTestHist25=new char[15];
	strcpy(szTestHist25,"testingHist2-5");

	HistoryP->Add(szTestHist21);
	HistoryP->Add(szTestHist22);
	HistoryP->Add(szTestHist23);
	HistoryP->Add(szTestHist24);
	HistoryP->Add(szTestHist25);
	HistoryP->Back();
	HistoryP->Back();
	HistoryP->Back();
	HistoryP->Back();
	if (strcmp(HistoryP->Forward(), "testingHist2-2"))
		GosGML_InternalTest_Fail("History::Forward did not return value expected. 2-2");
	if (strcmp(HistoryP->Forward(), "testingHist2-3"))
		GosGML_InternalTest_Fail("History::Forward did not return value expected. 2-3");
	if (strcmp(HistoryP->Forward(), "testingHist2-4"))
		GosGML_InternalTest_Fail("History::Forward did not return value expected. 2-4");
	if (strcmp(HistoryP->Forward(), "testingHist2-5"))
		GosGML_InternalTest_Fail("History::Forward did not return value expected. 2-5");
	if (HistoryP->Forward())
		GosGML_InternalTest_Fail("History::Forward when Forward History empty returned a value when none expected.");

	HistoryP->Clear();
	if (HistoryP->Back())
		GosGML_InternalTest_Fail("History::Back when History empty returned a value when none expected. 3-a");
	if (HistoryP->Forward())
		GosGML_InternalTest_Fail("History::Forward when History empty returned a value when none expected. 3-b");

	char* szTestHist31=new char[15];
	strcpy(szTestHist31,"testingHist3-1");
	char* szTestHist32=new char[15];
	strcpy(szTestHist32,"testingHist3-2");
	char* szTestHist33=new char[15];
	strcpy(szTestHist33,"testingHist3-3");
	char* szTestHist34=new char[15];
	strcpy(szTestHist34,"testingHist3-4");
	char* szTestHist35=new char[15];
	strcpy(szTestHist35,"testingHist3-5");

	HistoryP->Add(szTestHist35);
	HistoryP->Add(szTestHist34);
	HistoryP->Add(szTestHist33);
	HistoryP->Add(szTestHist32);
	HistoryP->Add(szTestHist31);
	HistoryP->Back();
	HistoryP->Back();
	HistoryP->Back();
	if (HistoryP->BackEmpty())
		GosGML_InternalTest_Fail("History::BackEmpty returned TRUE when FALSE expected. 3-c");
	HistoryP->Back();
	HistoryP->Back();
	if (!HistoryP->BackEmpty())
		GosGML_InternalTest_Fail("History::BackEmpty returned FALSE when TRUE expected. 3-d");
	if (HistoryP->ForwardEmpty())
		GosGML_InternalTest_Fail("History::ForwardEmpty returned TRUE when FALSE expected. 3-e");
	HistoryP->Forward();
	HistoryP->Forward();
	HistoryP->Forward();
	HistoryP->Forward();
	if (strcmp(HistoryP->Forward(), "testingHist3-1"))
		GosGML_InternalTest_Fail("History::Forward did not return value expected. 3-1");
	if (!HistoryP->ForwardEmpty())
		GosGML_InternalTest_Fail("History::ForwardEmpty returned FALSE when TRUE expected. 3-f");
	if (HistoryP->Forward())
		GosGML_InternalTest_Fail("History::Forward when Forward History empty returned value when none expected. 3-g");
	HistoryP->Back();
	HistoryP->Back();
	if (strcmp(HistoryP->Back(), "testingHist3-3"))
		GosGML_InternalTest_Fail("History::Back did not return expected value after Back-Forward-Back. 3-3");

	HistoryP->Clear();
	if (HistoryP->Back())
		GosGML_InternalTest_Fail("History::Back when History empty returned a value when none expected. 4-a");
	if (HistoryP->Forward())
		GosGML_InternalTest_Fail("History::Forward when History empty returned a value when none expected. 4-b");
	
	HistoryP->Clear();
	if (HistoryP->Back())
		GosGML_InternalTest_Fail("History::Back when History empty returned a value when none expected. 5-a");
	if (HistoryP->Forward())
		GosGML_InternalTest_Fail("History::Forward when History empty returned a value when none expected. 5-b");
	if (!HistoryP->BackEmpty())
		GosGML_InternalTest_Fail("History::BackEmpty returned FALSE when TRUE expected. 5-c");
	if (!HistoryP->ForwardEmpty())
		GosGML_InternalTest_Fail("History::ForwardEmpty returned FALSE when TRUE expected. 5-d");

	delete HistoryP;*/
	//////////////////////////
	//test Link public API	//
	//////////////////////////
	Link* LinkP=new Link(500,2000);

	char* szDest01 = new char[13];
	strcpy(szDest01,"testLink 0-1");
	LinkBox* LBPtest01 = new struct LinkBox;
	LBPtest01->Bottom = 31;
	LBPtest01->Left = 1;
	LBPtest01->Right = 31;
	LBPtest01->Top = 1;
	LBPtest01->Dest = szDest01;
	
	LinkP->AddLink(*LBPtest01, 15);//(LBPtest01->Top - LBPtest01->Bottom));

	XYPair* Pxy = new struct XYPair;
	Pxy->x = 5;
	Pxy->y = 5;
		
	if (strcmp(LinkP->TestForHit(*Pxy),"testLink 0-1"))
		GosGML_InternalTest_Fail("Link::TestForHit did not return correct Dest string. 0-1");
	
	delete Pxy;
	delete LinkP;
	//////////////////////////////
	//test Region public API	//
	//////////////////////////////

	//////////////////////////////
	//test Rollover public API	//
	//////////////////////////////
	RolloverCBCount=0;
	LastRolloverFileName=0;
	Rollover* RolloverP = new Rollover;
	ImageData* ImageP1 = InitImageData(1,1,"First Image",1);
	ImageData* ImageP2 = InitImageData(73,19,"Second Image",2);
	ImageData* ImageP3 = InitImageData(44,86,"Third Image",3);
	ImageData* ImageP4 = InitImageData(91,3,"Fourth Image",4);
	(*RolloverCBTest)(1,2,"TESTING",3);
	if(strcmp(LastRolloverFileName,"TESTING"))
		GosGML_InternalTest_Fail("GML Test: RolloverCBTest() did not set values properly.");
	RolloverP->Add(ImageP1, &RolloverCBTest);
	RolloverP->Add(ImageP2, &RolloverCBTest);
	RolloverP->Add(ImageP3, &RolloverCBTest);
	RolloverP->Add(ImageP4, &RolloverCBTest);
	RolloverP->CallOn(ImageP4);
	if(strcmp(LastRolloverFileName,"Fourth Image"))
		GosGML_InternalTest_Fail("GML Test: Rollover::CallOn() did not perform expected callback.");
	RolloverP->CallOn(ImageP1);
	if(strcmp(LastRolloverFileName,"First Image"))
		GosGML_InternalTest_Fail("GML Test: Rollover::CallOn() did not perform expected callback.");
	RolloverP->CallOn(ImageP3);
	if(strcmp(LastRolloverFileName,"Third Image"))
		GosGML_InternalTest_Fail("GML Test: Rollover::CallOn() did not perform expected callback.");
	RolloverP->CallOn(ImageP2);
	if(strcmp(LastRolloverFileName,"Second Image"))
		GosGML_InternalTest_Fail("GML Test: Rollover::CallOn() did not perform expected callback.");

	if(LastRolloverFileName)
		delete[] LastRolloverFileName;
	delete RolloverP;
	delete ImageP1;
	delete ImageP2;
	delete ImageP3;
	delete ImageP4;
	//////////////////////////////////////
	//test Text Draw Buffer public API	//
	//////////////////////////////////////

	//////////////////////////////
	//test GQueue public API	//
	//////////////////////////////

	//////////////////////////////
	//test GStack public API	//
	//////////////////////////////

	GStack<int>* GStackP=new GStack<int>;	//create integer stack for test
	int* GStackDP;	//GStack Data Pointer

	if(GStackP->Pop())	//ensure Pop returns 0 when stack is first initialized and empty
		PAUSE(("GML Test: GStack::Pop() returned a value when none was expected."));

	if(!GStackP->IsEmpty())	//ensure IsEmpty returns true when stack is first initialized and empty
		PAUSE(("GML Test: GStack::IsEmpty() returned false when true was expected."));

	GStackDP=new int(400);
	GStackP->Push(GStackDP);
	if(GStackP->IsEmpty())	//ensure IsEmpty returns false when stack is first Pushed into
		PAUSE(("GML Test: GStack::IsEmpty() returned true when false was expected."));

	GStackDP=GStackP->Pop();//ensure Pop returns true when stack is first Pushed into
	if(!GStackDP || *GStackDP!=400)
		PAUSE(("GML Test: GStack::Pop() returned an incorrect value."));

	if(!GStackP->IsEmpty())	//ensure IsEmpty returns false when stack is emptied after containing item(s)
		PAUSE(("GML Test: GStack::IsEmpty() returned false when true was expected."));

	//by this point I am satisfied that IsEmpty() works.

	GStackP->Push(GStackDP);
	GStackDP=new int(401);
	GStackP->Push(GStackDP);
	GStackDP=new int(402);
	GStackP->Push(GStackDP);
	GStackDP=new int(403);
	GStackP->Push(GStackDP);
	GStackDP=new int(404);
	GStackP->Push(GStackDP);
	GStackDP=new int(405);
	GStackP->Push(GStackDP);
	GStackDP=new int(406);
	GStackP->Push(GStackDP);	//stack now has 7 items, should be PLENTY

	GStackDP=GStackP->FPop();
	if(!GStackDP || *GStackDP!=406)	//ensure FPop returns the right value immediately after executing Push(the following pops may error out other portions of this are broken)
		PAUSE(("GML Test: GStack::FPop() returned an incorrect value."));
	else
		delete GStackDP;

	GStackDP=GStackP->FPop();
	if(!GStackDP || *GStackDP!=405)	//ensure FPop returns the right value immediately after executing FPop
		PAUSE(("GML Test: GStack::FPop() returned an incorrect value."));
	GStackP->Push(GStackDP);	//back to 6 items

	GStackDP=GStackP->FPop();
	if(!GStackDP || *GStackDP!=405)	//ensure FPop returns the right value immediately after executing Push
		PAUSE(("GML Test: GStack::FPop() returned an incorrect value."));
	else
		delete GStackDP;

	GStackDP=GStackP->Pop();
	if(!GStackDP || *GStackDP!=404)	//ensure Pop returns the right value immediately after executing FPop(the following pops may error out other portions of this are broken)
		PAUSE(("GML Test: GStack::Pop() returned an incorrect value."));
	else
		delete GStackDP;

	GStackDP=GStackP->Pop();
	if(!GStackDP || *GStackDP!=403)	//ensure Pop returns the right value immediately after executing Pop
		PAUSE(("GML Test: GStack::Pop() returned an incorrect value."));

	GStackP->Push(GStackDP);
	GStackDP=GStackP->Pop();
	if(!GStackDP || *GStackDP!=403)	//ensure Pop returns the right value immediately after executing Push
		PAUSE(("GML Test: GStack::Pop() returned an incorrect value."));
	else
		delete GStackDP;

	GStackDP=GStackP->FPop();
	if(!GStackDP || *GStackDP!=402)	//ensure FPop returns the right value immediately after executing Pop
		PAUSE(("GML Test: GStack::FPop() returned an incorrect value."));
	else
		delete GStackDP;

	//by this point I am reasonably certain that both FPop and Pop return correct values and leave the internal data in an acceptable state when popping from "large" lists

	GStackDP=GStackP->FPop();
	if(!GStackDP || *GStackDP!=401)	//the real test here is if FPop leaves the internal data correct when the list is only 2 members
		PAUSE(("GML Test: GStack::FPop() returned an incorrect value."));
	else
		delete GStackDP;

	GStackDP=GStackP->Pop();
	if(!GStackDP || *GStackDP!=400)	//ensure that Pop returns a correct value on the last item
		PAUSE(("GML Test: GStack::Pop() returned an incorrect value."));
	else
		delete GStackDP;

	GStackDP=GStackP->Pop();
	if(GStackDP)	//final test of Pop
		PAUSE(("GML Test: GStack::Pop() returned a value when none was expected."));

	GStackP->Clear();	//clear GStack
	GStackDP=new int(500);
	GStackP->Push(GStackDP);
	GStackDP=new int(501);
	GStackP->Push(GStackDP);

	GStackDP=GStackP->FPop();
	if(!GStackDP || *GStackDP!=501)	//ensure that clear() worked on an empty list part 1/3
		PAUSE(("GML Test: GStack::FPop() returned an incorrect value due to clear()."));
	else
		delete GStackDP;

	GStackDP=GStackP->Pop();
	if(!GStackDP || *GStackDP!=500)	//ensure that clear() worked on an empty list part 2/3
		PAUSE(("GML Test: GStack::Pop() returned an incorrect value due to clear()."));
	else
		delete GStackDP;

	GStackDP=GStackP->Pop();
	if(GStackDP)	//ensure that clear() worked on an empty list part 3/3
		PAUSE(("GML Test: GStack::Pop() returned a value when none was expected."));

	GStackDP=new int(600);
	GStackP->Push(GStackDP);
	GStackDP=new int(601);
	GStackP->Push(GStackDP);
	GStackP->Clear();	//clear GStack

	GStackDP=GStackP->Pop();
	if(GStackDP)	//ensure that clear() worked on an empty list part 2/3
		PAUSE(("GML Test: GStack::Pop() returned a value when none was expected."));
	else
		delete GStackDP;


	delete GStackP;	//test finished, destroy

	//////////////////////////////
	//test GMLFont public API	//
	//////////////////////////////

	//////////////////////////////////////
	//test GmlImageParsedTag public API	//
	//////////////////////////////////////

	//////////////////////////////////////
	//test GmlParsedString public API	//
	//////////////////////////////////////

	//////////////////////////////////
	//test CacheString public API	//
	//////////////////////////////////

	//////////////////////////////////////////
	//test GmlParser public and private API	//
	//////////////////////////////////////////

	//////////////////////////////////////////////////
	//test GmlDisplaySystem public and private API	//
	//////////////////////////////////////////////////

	///////////////////
	//**End Logging**//
	///////////////////
	//if log file is open close it...
	if (hLog)
	{
		strcpy(errMsg,"\r\n=======< END >=======| GML INTERNAL TEST |=======< END >=======\r\n");
		gos_SeekFile(*hLog, FROMEND, 0);
		gos_WriteFile(*hLog, errMsg, strlen(errMsg));
		gos_CloseFile(*hLog);
		delete hLog;	
	}
	return true;
}

void __stdcall GosGML_InternalTest_Fail(const char* msg)
{
	if (TESTLOG && hLog)
	{
		char tmpmsg[8192];
		strcpy(tmpmsg,gos_GetFormattedDate(0));
		strcat(tmpmsg," <");
		strcat(tmpmsg,gos_GetFormattedTime());
		strcat(tmpmsg,"> ");
		strcat(tmpmsg,msg);
		strcat(tmpmsg,"\r\n");
		strcpy(errMsg, tmpmsg);

		gos_SeekFile(*hLog, FROMEND, 0);
		gos_WriteFile(*hLog, errMsg, strlen(errMsg));
	}
	else
	{
		PAUSE((msg));
	}
}

void RolloverCBTest(int x, int y, char* ImageName, int ImageID)
{
	if(LastRolloverFileName)
		delete[] LastRolloverFileName;
	LastRolloverFileName=new char[strlen(ImageName)+1];
	strcpy(LastRolloverFileName,ImageName);
	RolloverCBCount++;
}

ImageData* InitImageData(int x, int y, char* ImageName, int ImageID)
{
	ImageData* Img=new ImageData;
	Img->Name=new char[strlen(ImageName)+1];
	strcpy(Img->Name,ImageName);
	Img->x=x;
	Img->y=y;
	Img->Handle=ImageID;
	return Img;
}
#endif



