// AIDisplayGraph.cpp: implementation of the AIDisplayGraph class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Simulator.h"
#include "AIDisplayGraph.h"
#include "AIRoutePlanner.h"
#include "AISetDirection.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

AIDisplayGraph::AIDisplayGraph()
{
	InitGraph();

	RCReset();

	GInitialize();
	/*GAddNodeSpecial(StartingPoint, East);
	GAddLandmarkNode(East, North, RateofChange, 10, 30);
	GAddLandmarkNode(East, North, RateofChange, 10, 30);
	GAddDecisionNode(East, North, 30);
	GAddLandmarkNode(North, West, RateofChange, 10, 30);
	GAddDecisionNode(North, West, 30);
	GAddLandmarkNode(West, South, RateofChange, 10, 30);
	GAddLandmarkNode(West, South, RateofChange, 10, 30);
	GAddDecisionNode(West, South, 30);
	GAddLandmarkNode(South, East, RateofChange, 10, 30);*/
	UpdateGraph();

	CurrentPosition.Node  = 1;

	RCEnableNormalPens();

	PrintZoomRatio = 1;


	IsUpdating = FALSE;	

	DisplayAutoCenter = TRUE;

	GlobalRendering.Radius = 6;

	NodeSelectedA = -1; // no node selected
	NodeSelectedB = -1; // no node selected
	TurnA = true;

	StreamMode = Off;

}

AIDisplayGraph::~AIDisplayGraph()
{

}

/************************************************************************
* Function RenderGDI(CDC &MemDC, CRect Screen)
*
* PURPOSE
* Basic rendering of the graph
* NOTE
* Un optimized,  will double draw link lines.
*************************************************************************/
void AIDisplayGraph::RenderGDI(CDC &MemDC, CRect Screen)
{
	if (IsUpdating == FALSE)
	{
		IsUpdating = TRUE;
		// get the newest graph
		UpdateGraph();
		// get the current position
		//UpdatePosition();	

		CDC DBufferDC;
		DBufferDC.CreateCompatibleDC(&MemDC);
		CBitmap DBufferBitmap;
		CBitmap *pOldBitmap;

		DBufferBitmap.CreateCompatibleBitmap(&MemDC,Screen.Width(),Screen.Height()+15);
		pOldBitmap = DBufferDC.SelectObject(&DBufferBitmap);

		GlobalRendering.Screen = Screen;

		// setup the board and rulers
		RenderSetupBorder(DBufferDC);
		
		int OldBkMode = DBufferDC.SetBkMode(TRANSPARENT);
  
		for (int NodeIndex = 1; NodeIndex < MAXNODE; NodeIndex++)
		{
			if (Heap[NodeIndex].NodeType != Empty)
			{
				RenderNode(DBufferDC,NodeIndex);

				// next render the links
				if (Heap[NodeIndex].LinkE != NULL)
					RenderLink(DBufferDC,Heap[NodeIndex].Location,Heap[Heap[NodeIndex].LinkE].Location);
				if (Heap[NodeIndex].LinkN != NULL)
					RenderLink(DBufferDC,Heap[NodeIndex].Location,Heap[Heap[NodeIndex].LinkN].Location);
				if (Heap[NodeIndex].LinkW != NULL)
					RenderLink(DBufferDC,Heap[NodeIndex].Location,Heap[Heap[NodeIndex].LinkW].Location);
				if (Heap[NodeIndex].LinkS != NULL)
					RenderLink(DBufferDC,Heap[NodeIndex].Location,Heap[Heap[NodeIndex].LinkS].Location);							
			
				// now render the landmarks
				CPen *OldPen = DBufferDC.SelectObject(&Pens[BLUEPEN]);
				if (Heap[NodeIndex].NodeType == Landmark)
					RenderLandMarks(DBufferDC,Heap[NodeIndex]); 
				DBufferDC.SelectObject(OldPen);
			}
		}

		GPOINT Position;
		// now render current position + links
		if (CurrentPosition.Node != 0)
		{
			CPen *OldPen = DBufferDC.SelectObject(&Pens[REDPEN]);

			Position = Heap[CurrentPosition.Node].Location;
			if (CurrentPosition.TDirection == North)
				Position.y -= CurrentPosition.Distance;
			else if (CurrentPosition.TDirection == East)
				Position.x += CurrentPosition.Distance;
			else if (CurrentPosition.TDirection == South)
				Position.y += CurrentPosition.Distance;
			else if (CurrentPosition.TDirection == West)
				Position.x -= CurrentPosition.Distance;

			if (DisplayAutoCenter)
				DisplayPointCenter = Position; // temp, for centering on screen

			// draw the position
			// first check if object is close to visible area
			CRect Circle;
			if (LAUtils.InRect(Position,GlobalRendering.ExpandedArea))
			{	
				Circle.top = (int)((Position.y-GlobalRendering.YTransform-GlobalRendering.Radius)*GlobalRendering.YScale);
				Circle.bottom = (int)((Position.y-GlobalRendering.YTransform+GlobalRendering.Radius)*GlobalRendering.YScale);
				Circle.left = (int)((Position.x-GlobalRendering.XTransform-GlobalRendering.Radius)*GlobalRendering.XScale);
				Circle.right = (int)((Position.x-GlobalRendering.XTransform+GlobalRendering.Radius)*GlobalRendering.XScale);

				DBufferDC.Rectangle(&Circle);		
			}		
			// now draw the link
		//	DBufferDC.SetBkMode(OldBkMode);

			RenderLink(DBufferDC,Heap[CurrentPosition.Node].Location,Position);

			DBufferDC.SelectObject(OldPen);			
			
		}

		// now render the shortest path distance if applicable
		RPSetupEnumD();
		unsigned short Node;		
		CPen *OldPen = DBufferDC.SelectObject(&Pens[SHORTESTPATH]);
		unsigned short PrevNode = 0; // initialize to zero
		unsigned short FirstNode = 0; // initialize to zero
		while (RPEnumD(&Node) == TRUE)
		{
			RenderNode(DBufferDC,Node,false);

			if (FirstNode == 0)
				FirstNode = Node;

			if (PrevNode != 0)
			{
				// next render the links
				RenderLink(DBufferDC,Heap[PrevNode].Location,Heap[Node].Location);
			}

			PrevNode = Node;

		}
		// render the link between the destination node, and the current position
		if (FirstNode != 0)
		{		
			RenderLink(DBufferDC,Heap[FirstNode].Location,Position);
		}
		DBufferDC.SelectObject(OldPen);


		DBufferDC.SetBkMode(OldBkMode);

		CRect OldScreen = GlobalRendering.OldScreen;

		CString tempo;
		tempo.Format("One Notch = %dcm",(int)((Screen.Width()-GlobalRendering.RulerDepth)/(ZoomRatio*10)));
		if (PrintZoomRatio == 1) // cheap way not to display if printing
		{
			DBufferDC.TextOut(0,OldScreen.Height(),tempo);
		}
		else
			PrintNotchSize = (int)((Screen.Width()-GlobalRendering.RulerDepth)/(ZoomRatio*10));

		MemDC.BitBlt(OldScreen.left,OldScreen.top,OldScreen.Width(),OldScreen.Height()+15,&DBufferDC,0,0,SRCCOPY);
		DBufferDC.SelectObject(pOldBitmap);

		IsUpdating = FALSE;
	}
	else
		AfxMessageBox("Warning could not update for render");
}

/************************************************************************
* Function void RenderLink(CDC &MemDC, GPoint Start, GPoint End)
*
* PURPOSE
* Helper function for rendering
* It draws a line on the screen performing all of the scaling and translation and clipping
*************************************************************************/
void AIDisplayGraph::RenderLink(CDC &MemDC, GPOINT Start, GPOINT End)
{
	long XStart = LAUtils.Round((Start.x-GlobalRendering.XTransform)*GlobalRendering.XScale);
	long YStart = LAUtils.Round((Start.y-GlobalRendering.YTransform)*GlobalRendering.YScale);
	long XEnd =  LAUtils.Round((End.x-GlobalRendering.XTransform)*GlobalRendering.XScale);
	long YEnd =  LAUtils.Round((End.y-GlobalRendering.YTransform)*GlobalRendering.YScale);

	LAUtils.ClipLine(GlobalRendering.Screen,XStart,YStart,XEnd,YEnd); 
	if ((XStart != -1) && (XEnd != -1))
	{	
		MemDC.MoveTo(XStart,YStart);
		MemDC.LineTo(XEnd,YEnd);
	}


}

/************************************************************************
* Function void RenderLink(CDC &MemDC, FPoint Start, FPoint End)
*
* PURPOSE
* Helper function for rendering
* It draws a line on the screen performing all of the scaling and translation and clipping
*************************************************************************/
void AIDisplayGraph::RenderLink(CDC &MemDC, FPoint Start, FPoint End)
{
	long XStart = LAUtils.Round((Start.x-GlobalRendering.XTransform)*GlobalRendering.XScale);
	long YStart = LAUtils.Round((Start.y-GlobalRendering.YTransform)*GlobalRendering.YScale);
	long XEnd =  LAUtils.Round((End.x-GlobalRendering.XTransform)*GlobalRendering.XScale);
	long YEnd =  LAUtils.Round((End.y-GlobalRendering.YTransform)*GlobalRendering.YScale);

	LAUtils.ClipLine(GlobalRendering.Screen,XStart,YStart,XEnd,YEnd); 
	
	if ((XStart != -1) && (XEnd != -1))
	{	
		MemDC.MoveTo(XStart,YStart);
		MemDC.LineTo(XEnd,YEnd);
	}


}


/************************************************************************
* Function EnterNode(char *ptr)
*
* PURPOSE
* Basically data is sent from the AIs graph, to this class.  This function
* Excepts data, and loads it into the graph.
*************************************************************************/
unsigned short AIDisplayGraph::EnterNode(char *ptr)
{
	// output information	
	unsigned short Index;

	// enter the information
	ChartoShort(ptr,Index);
	ChartoShort(ptr, (short &)Heap[Index].hasCloseLoopMarker);
	ChartoShort(ptr, Heap[Index].LandMarkE);
	ChartoShort(ptr, Heap[Index].LandMarkN);
	ChartoShort(ptr, Heap[Index].LandMarkS);
	ChartoShort(ptr, Heap[Index].LandMarkW);
	ChartoShort(ptr, Heap[Index].LinkE);
	ChartoShort(ptr, Heap[Index].LinkN);
	ChartoShort(ptr, Heap[Index].LinkS);
	ChartoShort(ptr, Heap[Index].LinkW);
	ChartoShort(ptr, Heap[Index].Location.x);
	ChartoShort(ptr, Heap[Index].Location.y);
	ChartoShort(ptr, (short &)Heap[Index].NodeType);
	ChartoShort(ptr, (short &)Heap[Index].Special);

	return Index;


}

/************************************************************************
* Function void InitGraph()
*
* PURPOSE
* Intializises the graph structure
*************************************************************************/
void AIDisplayGraph::InitGraph()
{
	int ix;

	// initialize the "heap"
	for (ix = 0; ix < MAXNODE; ix++)
	{
		Heap[ix].NodeType = Empty;
		Heap[ix].LinkN = ix+1;
		Heap[ix].Index = ix;
	}
	// the last one has a null link
	Heap[ix-1].LinkN = NULL;
	Heap[0].NodeType = NA; // the 0 can't be avialable

}

/************************************************************************
* Function void ChartoShort(char *&ptr, short &Output)
*
* PURPOSE
* Load utility
*************************************************************************/
void AIDisplayGraph::ChartoShort(char *&ptr, short &Output)
{
	unsigned char *ptr1 = &(unsigned char &)(Output);

	// copy over the two bytes
	*ptr1 = *ptr;
	ptr++;
	ptr1++;
	*ptr1 = *ptr;
	ptr++;
}

/************************************************************************
* Function void ChartoShort(char *&ptr, unsigned short &Output)
*
* PURPOSE
* Load utility
*************************************************************************/
void AIDisplayGraph::ChartoShort(char *&ptr, unsigned short &Output)
{
	unsigned char *ptr1 = &(unsigned char &)(Output);

	// copy over the two bytes
	*ptr1 = *ptr;
	ptr++;
	ptr1++;
	*ptr1 = *ptr;
	ptr++;
}

/************************************************************************
* Function void UpdateGraph()
*
* PURPOSE
* To load graph information from the main graph
*************************************************************************/
void AIDisplayGraph::UpdateGraph()
{
	GSetupEnum(); // set up the enum

	char Buffer[100];
	char *ptr = Buffer;
	while (GEnumGraph(ptr) == TRUE)
	{
		EnterNode(ptr);
		ptr = Buffer;
	}
}

/************************************************************************
* Function RCSetZoomPoint(CPoint Point)
*
* PURPOSE
* Sets the zoom point
*************************************************************************/
void AIDisplayGraph::RCSetZoomPoint(CPoint Point)
{
	DisplayPointCenter = RCScreentoReal(Point);
	DisplayPrevZoomPoint = Point;

}

/************************************************************************
* Function void RCZoom(CPoint Point)
*
* PURPOSE
* Zoom in or out.
*************************************************************************/
void AIDisplayGraph::RCZoom(CPoint Point)
{
	float ZoomFactor = (float)(1-(float)((Point.y-DisplayPrevZoomPoint.y))*ZOOMPERCENT);

    DisplayPrevZoomPoint = Point;

    ZoomRatio *= ZoomFactor;

}

/************************************************************************
* Function void CScreentoReal(CPoint In)
*
* PURPOSE
* Converts a screen point to a real point
*************************************************************************/
CPoint AIDisplayGraph::RCScreentoReal(CPoint In)
{
	CPoint tReturn;
	// first zero the point
	In.x -= DisplayRect.left + DisplayRect.Width()/2;
	In.y -= DisplayRect.top + DisplayRect.Height()/2;

	// next figure out the distance to the center point
	tReturn.x = (long)(DisplayPointCenter.x + (In.x)/ZoomRatio);
	tReturn.y = (long)(DisplayPointCenter.y + (In.y)/ZoomRatio);

	return tReturn;
	

}


/************************************************************************
* Function void RCScreentoRealF(CPoint In)
*
* PURPOSE
* Converts a screen point to a real point
*************************************************************************/
FPoint AIDisplayGraph::RCScreentoRealF(CPoint In)
{
	FPoint tReturn;
	FPoint tIn = In;
	// first zero the point
	tIn.x -= DisplayRect.left + DisplayRect.Width()/2.0f;
	tIn.y -= DisplayRect.top + DisplayRect.Height()/2.0f;

	// next figure out the distance to the center point
	tReturn.x = GlobalRendering.RulerDepth/2 + (DisplayPointCenter.x + (tIn.x)/ZoomRatio);
	tReturn.y = GlobalRendering.RulerDepth/2 + (DisplayPointCenter.y + (tIn.y)/ZoomRatio);

	return tReturn;
	

}

void AIDisplayGraph::RCReset()
{
	ZoomRatio = 1;
	DisplayPointCenter.x = 0;
	DisplayPointCenter.y = 0;


}

/************************************************************************
* Function void EnterCurrPosition()
*
* PURPOSE
* Function for simulater version to store current position information
*************************************************************************/
void AIDisplayGraph::EnterCurrPosition(short Distance, char TDirection, unsigned short Node)
{
	CurrentPosition.Distance = Distance;
	CurrentPosition.Node = Node;
	CurrentPosition.TDirection = TDirection;	
}

/************************************************************************
* Function void UpdatePosition()
*
* PURPOSE
* Function for simulater version to get current position information
* NOTE Obsolete
*************************************************************************/
void AIDisplayGraph::UpdatePosition()
{
	short Distance;
	unsigned short Node;
	char TDirection;

	AI->AISendCurrPosition(&Distance,&TDirection);
	Node = GSendCurrNode();

	EnterCurrPosition(Distance,TDirection,Node);
}

/************************************************************************
* Function void FileSaveGraph(CString TheFileName)
*
* PURPOSE
* Saves the current graph to a file, uses the real graph not the display graph though
*************************************************************************/
void AIDisplayGraph::FileSaveGraph(CString TheFileName)
{	
	CFile TheFile;
	TheFile.Open(TheFileName,CFile::modeWrite|CFile::typeBinary|CFile::modeCreate ,NULL);
	
	if (IsUpdating == FALSE)
	{
		IsUpdating = TRUE;

		GSetupEnum(); // set up the enum

		char Buffer[100];
		char *ptr = Buffer;
		while (GEnumGraph(ptr) == TRUE)
		{
			// each node is 28 bytes
			TheFile.Write(ptr,28);
			ptr = Buffer;
		}
		// time to save the status
		GEnumStatus(ptr);
		TheFile.Write(ptr,8);
		IsUpdating = FALSE;
	}
	else
		AfxMessageBox("Warning could not update for render");

	TheFile.Close();
}

/************************************************************************
* Function void FileOpenGraph(CString TheFileName)
*
* PURPOSE
* Opens a saved graph
*************************************************************************/
void AIDisplayGraph::FileOpenGraph(CString TheFileName)
{
	CFile NewFile;
    NewFile.Open(TheFileName,CFile::modeRead|CFile::typeBinary ,NULL);	

	InitGraph(); // reset the graph
	GSetupLoad(); // sets up a graph load	

	char Buffer[100];
	char *ptr = Buffer;

	BOOL Done = false;
	while (!Done)
	{
		int Num = NewFile.Read(ptr,28);

		if (Num != 28)
		{
			// time to enter the status
			GLoadStatus(ptr);
			Done = true;			
		}
		else
		{
			GLoadGraph(ptr);
		}

	}

	NewFile.Close();

	// update the local copy
	UpdateGraph();

	NodeSelectedA = 1;
	RCSetCurrentNode(); // default the current node to 1
}

/************************************************************************
* Function void RenderHorzRuler
*
* PURPOSE
* Draw the horizontal ruler
*************************************************************************/
void AIDisplayGraph::RenderRuler(CDC &MemDC, int XStart, int YStart, int Width, int Height, int NMarks)
{
	// draw the bounds
	MemDC.MoveTo(XStart,YStart);
	MemDC.LineTo(XStart,YStart+Height);
	MemDC.LineTo(XStart+Width,YStart+Height);
	MemDC.LineTo(XStart+Width,YStart);
	MemDC.LineTo(XStart,YStart);
	// draw each mark	
	if (Width > Height)
	{
		// draw a horizontal ruler
		for (int ix = 1; ix < NMarks; ix++)
		{
			MemDC.MoveTo(XStart+(ix*Width)/NMarks,YStart);
			MemDC.LineTo(XStart+(ix*Width)/NMarks,YStart+Height);
		}
	}
	else
	{
		// draw a vertical ruler
		for (int ix = 1; ix < NMarks; ix++)
		{
			MemDC.MoveTo(XStart,(ix*Height)/NMarks + YStart);
			MemDC.LineTo(XStart+Width,(ix*Height)/NMarks + YStart);
		}

	}
}

/************************************************************************
* Function void RCToggleAutoCenter()
*
* PURPOSE
* Toggle Auto center feature on the graph
*************************************************************************/
void AIDisplayGraph::RCToggleAutoCenter()
{
	if (DisplayAutoCenter)
		DisplayAutoCenter = false;
	else
		DisplayAutoCenter = true;

}

/************************************************************************
* Function void RenderLandMarks(CDC &MemDC, NODE *NodePtr)
*
* PURPOSE
* Render the information contained in a landmark node
* EFFECTS
* Away arrow, wall away from robot
* Toward arrow, wall closer to robot
* Away with line, lost wall contact
* Towards with line, gained wall contact
*************************************************************************/
void AIDisplayGraph::RenderLandMarks(CDC &MemDC, NODE &Node)
{
	short Landmark;
	int angle;

	// only one landmark valid per node
	if (Node.LandMarkE != 0)
	{
		Landmark = Node.LandMarkE;
		angle = 0;
	}
	else if (Node.LandMarkN != 0)
	{
		Landmark = Node.LandMarkN;
		angle = 90;
	}
	else if (Node.LandMarkS != 0)
	{
		Landmark = Node.LandMarkS;
		angle = 270;
	}
	else if (Node.LandMarkW != 0)
	{
		Landmark = Node.LandMarkW;
		angle = 180;
	}
	else
	{
		// should never happens, but it sometimes does
		return;
	}

	// form the 0 degree arrow and rotate if different angle
	FPoint Start,End,ArrowTop,ArrowBottom,Extra1,Extra2;

	int TLandmark = Landmark;
	if (RoCLostDetection == Landmark)
	{
		// add the extra line
		TLandmark = 30;
	}
	else if (RoCGainDetection == Landmark)
	{
		// add the extra line
		TLandmark = -30;
	}	

	// do the staff of the arrow
	Start.x = float(Node.Location.x + GlobalRendering.Radius);
	Start.y = Node.Location.y;
	End.x = Start.x + abs(TLandmark);
	End.y = Start.y;
	// now draw the arrow
	if (Landmark < 0)
	{
		// in arrow
		ArrowTop.x = Start.x + GlobalRendering.Radius;
		ArrowTop.y = Start.y - GlobalRendering.Radius;
		ArrowBottom.x = Start.x + GlobalRendering.Radius;
		ArrowBottom.y = Start.y + GlobalRendering.Radius;
	}
	else
	{
		// out arrow
		ArrowTop.x = End.x - GlobalRendering.Radius;
		ArrowTop.y = End.y - GlobalRendering.Radius;
		ArrowBottom.x = End.x - GlobalRendering.Radius;
		ArrowBottom.y = End.y + GlobalRendering.Radius;
	}

	BOOL ExtraValid;
	if ((RoCLostDetection == Landmark) || (RoCGainDetection == Landmark))
	{
		ExtraValid = true;
		// add the extra line
		Extra1.x = End.x;
		Extra2.x = End.x;
		Extra1.y = End.y - GlobalRendering.Radius;
		Extra2.y = End.y + GlobalRendering.Radius;
	}
	else 
	{
		ExtraValid = false;	
		Extra1.x = 0;
		Extra2.x = 0;
		Extra1.y = 0;
		Extra2.y = 0;
	}

	// now rotate if neccessary
//	angle -= 90;
	if (angle != 0)
	{
		FPoint Center;
		Center.x = Node.Location.x;
		Center.y = Node.Location.y;

		Start = LAUtils.RotatePoint(Start,Center,(double)angle);
		End = LAUtils.RotatePoint(End,Center,(double)angle);
		ArrowTop = LAUtils.RotatePoint(ArrowTop,Center,(double)angle);
		ArrowBottom = LAUtils.RotatePoint(ArrowBottom,Center,(double)angle);

		if (ExtraValid)
		{
			Extra1 = LAUtils.RotatePoint(Extra1,Center,(double)angle);
			Extra2 = LAUtils.RotatePoint(Extra2,Center,(double)angle);
		}
	}


	// now draw the lines on the screen.
	RenderLink(MemDC,Start,End);
	if (Landmark < 0)
	{
		RenderLink(MemDC,Start,ArrowTop);
		RenderLink(MemDC,Start,ArrowBottom);
	}
	else
	{
		RenderLink(MemDC,End,ArrowTop);
		RenderLink(MemDC,End,ArrowBottom);
	}
	if (ExtraValid)
	{
		RenderLink(MemDC,Extra1,Extra2);
	}

}

/************************************************************************
* Function void RCMouseDown(CPoint Point)
*
* PURPOSE
* The mouse has just clicked in the screen, and possible actions may occur
* USAGE
* Main window when the graph area was clicked on
*************************************************************************/
void AIDisplayGraph::RCMouseDown(CPoint Point)
{
	// get the real point out of the screen point
	FPoint RealPoint = RCScreentoRealF(Point);

	for (int ix = 1; ix < MAXNODE; ix++)
	{
		if (Heap[ix].NodeType != Empty)
		{
			FRect Bounds;
			Bounds.left = (float)(Heap[ix].Location.x - GlobalRendering.Radius);
			Bounds.right = (float)(Heap[ix].Location.x + GlobalRendering.Radius);
			Bounds.top = (float)(Heap[ix].Location.y - GlobalRendering.Radius);
			Bounds.bottom = (float)(Heap[ix].Location.y + GlobalRendering.Radius);
			if (LAUtils.InRect(RealPoint,Bounds))
			{
				if (TurnA)
				{
					NodeSelectedA = ix;
					TurnA = false;
				}
				else
				{
					NodeSelectedB = ix;
					TurnA= true;
				}

				return;
			}
		}
	}
	// nothing selected it.
	if (TurnA)
	{
		NodeSelectedA = -1;
		TurnA = false;
	}
	else
	{
		NodeSelectedB = -1;
		TurnA= true;
	}

}

/************************************************************************
* Function void RenderHallwaySymbol(CDC &MemDC, NODE &Node)
*
* PURPOSE
* If a decision node has a hallway, and it isn't connected to anything, 
* Then a long arrow should be rendered to signify that it is a hallway,
* which hasn't been visited yet.
* USAGE
* During a rendering loop
*************************************************************************/
void AIDisplayGraph::RenderHallwaySymbol(CDC &MemDC, NODE &Node)
{
	// must be a decision node
	if (Node.NodeType != Decision)
		return;

	// check if it is a hallway link, and there isn't anything linked to it
	if ((Node.LandMarkN == SNRHallway) && (Node.LinkN == 0))	
	{
		CPen *OldPen = MemDC.SelectObject(&Pens[HALLWAYPEN]);
		RenderHallwaySymbol2(MemDC,North,Node.Location);
		MemDC.SelectObject(OldPen);
	}
	if ((Node.LandMarkS == SNRHallway) && (Node.LinkS == 0))	
	{
		CPen *OldPen = MemDC.SelectObject(&Pens[HALLWAYPEN]);
		RenderHallwaySymbol2(MemDC,South,Node.Location);
		MemDC.SelectObject(OldPen);
	}
	if ((Node.LandMarkW == SNRHallway) && (Node.LinkW == 0))	
	{
		CPen *OldPen = MemDC.SelectObject(&Pens[HALLWAYPEN]);
		RenderHallwaySymbol2(MemDC,West,Node.Location);
		MemDC.SelectObject(OldPen);
	}
	if ((Node.LandMarkE == SNRHallway) && (Node.LinkE == 0))	
	{
		CPen *OldPen = MemDC.SelectObject(&Pens[HALLWAYPEN]);
		RenderHallwaySymbol2(MemDC,East,Node.Location);	
		MemDC.SelectObject(OldPen);
	}

}

/************************************************************************
* Function void RenderHallwaySymbol2(CDC &MemDC, short Direction, GPoint StartingPosition)
*
* PURPOSE
* Helper function for RenderHallwaySymbol. does the actual drawing after the decision
* has been made to draw the symbol
* USAGE
* During a rendering loop, called by RenderHallwaySymbol
*************************************************************************/
void AIDisplayGraph::RenderHallwaySymbol2(CDC &MemDC, short Direction, GPOINT StartingPosition)
{
	// O.K time to render a line and arrow
	int LineLength = 100;
	FPoint Start,End,ArrowTop,ArrowBottom;
		// do the staff of the arrow
	Start.x = float(StartingPosition.x + GlobalRendering.Radius);
	Start.y = StartingPosition.y;
	End.x = Start.x + LineLength;
	End.y = Start.y;

	// out arrow
	ArrowTop.x = End.x - GlobalRendering.Radius;
	ArrowTop.y = End.y - GlobalRendering.Radius;
	ArrowBottom.x = End.x - GlobalRendering.Radius;
	ArrowBottom.y = End.y + GlobalRendering.Radius;

	int Angle = 0; // 0 is east
	if (Direction == North)
		Angle = 90;
	else if (Direction == West)
		Angle = 180;
	else if (Direction == South)
		Angle = 270;

	FPoint Center;
	Center.x = StartingPosition.x;
	Center.y = StartingPosition.y;

	// rotate if neccessary
	if (Angle != 0)
	{
		Start = LAUtils.RotatePoint(Start,Center,(double)Angle);
		End = LAUtils.RotatePoint(End,Center,(double)Angle);
		ArrowTop = LAUtils.RotatePoint(ArrowTop,Center,(double)Angle);
		ArrowBottom = LAUtils.RotatePoint(ArrowBottom,Center,(double)Angle);
	}

	// now draw the lines on the screen.
	RenderLink(MemDC,Start,End);
	RenderLink(MemDC,End,ArrowTop);
	RenderLink(MemDC,End,ArrowBottom);
	RenderLink(MemDC,ArrowTop,ArrowBottom);

}

/************************************************************************
* Function GetShortestPath()
*
* PURPOSE
* Generates the shortest path*
* USAGE
* Temp function for debugging purposes
*************************************************************************/
void AIDisplayGraph::GetShortestPath()
{
	if ((NodeSelectedA != -1) && (NodeSelectedB != -1))
		RPGenerateShortestPath(NodeSelectedA,NodeSelectedB);

}

/************************************************************************
* Function GDIRenderNode(CDC &MemDC, int NodeIndex)
*
* PURPOSE
* to render a node
* USAGE
* for GDI rendering
*************************************************************************/
void AIDisplayGraph::RenderNode(CDC &MemDC, int NodeIndex, BOOL StandardPens)
{
		// o.k lets render it
	if (NodeIndex >= MAXNODE)
	{
		ASSERT(NodeIndex < MAXNODE);
		return;
	}
	if ((Heap[NodeIndex].NodeType == Landmark) || (Heap[NodeIndex].NodeType == Decision)
		|| (Heap[NodeIndex].NodeType == Special) || (Heap[NodeIndex].NodeType == Unknown))
		
	{
		// first check if object is close to visible area
		if (LAUtils.InRect(Heap[NodeIndex].Location,GlobalRendering.ExpandedArea))
		{
			CPen *OldPen;
			if (StandardPens)
			{
				if (NodeIndex == NodeSelectedA)
				{
					OldPen = MemDC.SelectObject(&Pens[SELECTPENA]);
				}
				else if (NodeIndex == NodeSelectedB)
				{
					OldPen = MemDC.SelectObject(&Pens[SELECTPENB]);
				}
			}
			

			CRect Circle;
			Circle.top = (int)((Heap[NodeIndex].Location.y-GlobalRendering.YTransform-GlobalRendering.Radius)*GlobalRendering.YScale);
			Circle.bottom = (int)((Heap[NodeIndex].Location.y-GlobalRendering.YTransform+GlobalRendering.Radius)*GlobalRendering.YScale);
			Circle.left = (int)((Heap[NodeIndex].Location.x-GlobalRendering.XTransform-GlobalRendering.Radius)*GlobalRendering.XScale);
			Circle.right = (int)((Heap[NodeIndex].Location.x-GlobalRendering.XTransform+GlobalRendering.Radius)*GlobalRendering.XScale);
			// render an extra square if it is a decision node
			if (Heap[NodeIndex].NodeType == Decision || Heap[NodeIndex].NodeType == Special)
			{
				// draw in a rectangle
				MemDC.Rectangle(&Circle);
				// render any possible hallways symbols
				RenderHallwaySymbol(MemDC,Heap[NodeIndex]);
			}								

			if (Heap[NodeIndex].NodeType != Unknown)
			{
				// render a circle
				MemDC.Ellipse(&Circle);
			}

			// render a triangle and square for an unknown node
			if (Heap[NodeIndex].NodeType == Unknown)
			{
				int TOffset = 0;

				// draw in a rectangle
				MemDC.Rectangle(&Circle);

				CPoint One,Two,Three;

				// the top of the triangle
				One.x = Circle.left + Circle.Width()/2;
				One.y = Circle.top + TOffset;
				// the left point
				Two.x = Circle.left + TOffset;
				Two.y = Circle.bottom - TOffset;
				// the right point
				Three.x = Circle.right - TOffset;
				Three.y = Circle.bottom - TOffset;
				
				// draw in a triangle
				MemDC.MoveTo(One);
				MemDC.LineTo(Two);
				MemDC.LineTo(Three);
				MemDC.LineTo(One);
			}

			if (StandardPens)
			{
				if ((NodeIndex == NodeSelectedA)|| (NodeIndex == NodeSelectedB))
				{
					 MemDC.SelectObject(OldPen);
				}
			}
		}
		
	}

}

/************************************************************************
* Function RenderSetupBorder(CDC &MemDC)
*
* PURPOSE
* Helper function for GDI render.  Draws the border and rulers.
* USAGE
* for GDI rendering
*************************************************************************/
void AIDisplayGraph::RenderSetupBorder(CDC &MemDC)
{
	CRect Screen, OldScreen;

	Screen = GlobalRendering.Screen;	

	CRect tRect(0,0,Screen.Width(),Screen.Height());

	MemDC.FillRect(tRect,&BlueBrush);

	CBrush WhiteBrush;
	WhiteBrush.CreateSolidBrush(RGB(255,255,255));

	CRect tRect2(0,Screen.Height(),Screen.Width(),Screen.Height()+15);
	MemDC.FillRect(tRect2,&WhiteBrush);

	// create a border
	MemDC.MoveTo(0,0);
	MemDC.LineTo(0,Screen.Height()-1);
	MemDC.LineTo(Screen.Width()-1,Screen.Height()-1);
	MemDC.LineTo(Screen.Width()-1,0);
	MemDC.LineTo(0,0);

	// draw in the rulers
	// draw vertical ruler
	int Depth = (int)(6*PrintZoomRatio);  // PrintZoomRatio is 1 except when printing.
	GlobalRendering.RulerDepth = (int)(6*PrintZoomRatio);
	GlobalRendering.OldScreen = GlobalRendering.Screen;
	RenderRuler(MemDC,0,0+Depth,Depth,Screen.Height()-Depth-1,10);
	// draw horizontal ruler
	RenderRuler(MemDC,Depth,0,Screen.Width()-Depth,Depth,10);

	// make room for the rulers
	GlobalRendering.Screen.left += (Depth);
	GlobalRendering.Screen.top += (Depth);

	DisplayRect = GlobalRendering.Screen;

	// use globals to reduce parameter passing
	GlobalRendering.XScale = ZoomRatio;
	GlobalRendering.YScale = ZoomRatio;

	// tranform e.i where to start the lines
	GlobalRendering.XTransform = DisplayPointCenter.x - Screen.Width()/ZoomRatio/2;
	GlobalRendering.YTransform = DisplayPointCenter.y- Screen.Height()/ZoomRatio/2;

	GlobalRendering.TransformedScreen.top = (long)(GlobalRendering.YTransform);
	GlobalRendering.TransformedScreen.bottom = (long)((GlobalRendering.YTransform +Screen.Height()/ZoomRatio));
	GlobalRendering.TransformedScreen.left = (long)(GlobalRendering.XTransform);
	GlobalRendering.TransformedScreen.right = (long)((GlobalRendering.XTransform +Screen.Width()/ZoomRatio));

	// render the node type
	
	GlobalRendering.ExpandedArea = GlobalRendering.TransformedScreen;
	GlobalRendering.ExpandedArea.left -= (long)(GlobalRendering.Radius*GlobalRendering.XScale);
	GlobalRendering.ExpandedArea.right += (long)(GlobalRendering.Radius*GlobalRendering.XScale);
	GlobalRendering.ExpandedArea.top -= (long)(GlobalRendering.Radius*GlobalRendering.YScale);
	GlobalRendering.ExpandedArea.bottom += (long)(GlobalRendering.Radius*GlobalRendering.YScale);

	GlobalRendering.Screen = Screen;
//	GlobalRendering.OldScreen = OldScreen;


}

/************************************************************************
* Function RCSetCurrentNode()
*
* PURPOSE
* Tell the navigator what its current position is
*************************************************************************/
void AIDisplayGraph::RCSetCurrentNode()
{
	char message[30]; // form the message to be sent
	unsigned short Node;

	if (NodeSelectedA != -1)
		Node = NodeSelectedA;
	else if (NodeSelectedB != -1)
		Node = NodeSelectedB;

	if (Node == -1)
		return;

	AISetDirection tDialog;
	if (tDialog.DoModal() == IDOK)
	{

		unsigned short Direction = tDialog.m_Direction;

		Direction++;	
	
		sprintf(message,"<8%d|%d>",Node,Direction);
		TQSend(message,strlen(message));
	}




	// old simulator way of doing things
	/*
	if (NodeSelectedA != -1)
		AI->AISetCurrNode(NodeSelectedA);
	else if (NodeSelectedB != -1)
		AI->AISetCurrNode(NodeSelectedB);

  */

	NodeSelectedA = -1;
	NodeSelectedB = -1;
}

/************************************************************************
* Function RCSetDestination()
*
* PURPOSE
* Tell the navigator were to go, based on which nodes are selected

*************************************************************************/
void AIDisplayGraph::RCSetDestination()
{
	if (NodeSelectedA != -1)
		AI->AISetDestination(NodeSelectedA);
	else if (NodeSelectedB != -1)
		AI->AISetDestination(NodeSelectedB);

	NodeSelectedA = -1;
	NodeSelectedB = -1;

}

/************************************************************************
* Function RCSendXPCommand(XPMessageStruct Message)
*
* PURPOSE
* Gives the explorer a command
*************************************************************************/
void AIDisplayGraph::RCSendXPCommand(XPMessageStruct Message)
{
	char ToSendMessage[30];
	unsigned short MessageType,Node,Direction,Side;


	if (Message.MappingMode == TRUE)
	{
		MessageType = 1;
		
		if (NodeSelectedA != -1)
			Node =  NodeSelectedA;
		else if (NodeSelectedB != -1)
			Node =  NodeSelectedB;
		else
			return;

		NodeSelectedA = -1;
		NodeSelectedB = -1;
		
		Direction = Message.Direction;
		if ( Message.LeftSideMapping == TRUE)
			Side = 2;
		else 
			Side = 1;
		sprintf(ToSendMessage,"<6%d|%d|%d|%d|%d>",MessageType,Node,Direction,Side);
		TQSend(ToSendMessage,strlen(ToSendMessage));

	}
	else // Navigating mode
	{
		MessageType = 2;

		if (NodeSelectedA != -1)
			Node = NodeSelectedA;
		else if (NodeSelectedB != -1)
			Node = NodeSelectedB;

		NodeSelectedA = -1;
		NodeSelectedB = -1;

		sprintf(ToSendMessage,"<6%d|%d>",MessageType,Node);
		TQSend(ToSendMessage,strlen(ToSendMessage));
	}

	// old way of doing things
	/*
	if (Message.MappingMode == TRUE)
	{
		if (NodeSelectedA != -1)
			Message.DecisionNode = NodeSelectedA;
		else if (NodeSelectedB != -1)
			Message.DecisionNode = NodeSelectedB;
		else
			return;

		NodeSelectedA = -1;
		NodeSelectedB = -1;
	}
	else // Navigating mode
	{
		if (NodeSelectedA != -1)
			AI->AISetDestination(NodeSelectedA);
		else if (NodeSelectedB != -1)
			AI->AISetDestination(NodeSelectedB);

		NodeSelectedA = -1;
		NodeSelectedB = -1;
	}


	AI->AISendCommand(Message);*/

}

/************************************************************************
* Function RCEnablePrintPens()
*
* PURPOSE
* Select all black pens for printing
*************************************************************************/
void AIDisplayGraph::RCEnablePrintPens()
{
	// detatch the object to avoid an assert
	Pens[BLACKPEN].DeleteObject();
	Pens[REDPEN].DeleteObject();
	Pens[BLUEPEN].DeleteObject();
	Pens[SELECTPENA].DeleteObject();
	Pens[SELECTPENB].DeleteObject();
	Pens[HALLWAYPEN].DeleteObject();
	Pens[SHORTESTPATH].DeleteObject();

	Pens[BLACKPEN].CreatePen(PS_SOLID,1,RGB(0,0,0));
	Pens[REDPEN].CreatePen(PS_SOLID,1,RGB(0,0,0));
	Pens[BLUEPEN].CreatePen(PS_SOLID,1,RGB(0,0,0));
	Pens[SELECTPENA].CreatePen(PS_SOLID,1,RGB(0,0,0));
	Pens[SELECTPENB].CreatePen(PS_SOLID,1,RGB(0,0,50));
	Pens[HALLWAYPEN].CreatePen(PS_SOLID,1,RGB(0,0,0));
	Pens[SHORTESTPATH].CreatePen(PS_SOLID,1,RGB(0,0,0));

	// set it to a white brush
	BlueBrush.DeleteObject();
	BlueBrush.CreateSolidBrush(RGB(255,255,255));

}

/************************************************************************
* Function RCEnableNormalPens()
*
* PURPOSE
* Select normal pens
*************************************************************************/
void AIDisplayGraph::RCEnableNormalPens()
{
	Pens[BLACKPEN].DeleteObject();
	Pens[REDPEN].DeleteObject();
	Pens[BLUEPEN].DeleteObject();
	Pens[SELECTPENA].DeleteObject();
	Pens[SELECTPENB].DeleteObject();
	Pens[HALLWAYPEN].DeleteObject();
	Pens[SHORTESTPATH].DeleteObject();

	Pens[BLACKPEN].CreatePen(PS_SOLID,1,RGB(0,0,0));
	Pens[REDPEN].CreatePen(PS_SOLID,1,RGB(255,0,0));
	Pens[BLUEPEN].CreatePen(PS_SOLID,1,RGB(0,0,255));
	Pens[SELECTPENA].CreatePen(PS_SOLID,1,RGB(255,255,0));
	Pens[SELECTPENB].CreatePen(PS_SOLID,1,RGB(200,200,50));
	Pens[HALLWAYPEN].CreatePen(PS_SOLID,1,RGB(255,50,50));
	Pens[SHORTESTPATH].CreatePen(PS_SOLID,1,RGB(0,255,0));

	BlueBrush.DeleteObject();
	BlueBrush.CreateSolidBrush(RGB(200,255,255));

}

/************************************************************************
* Function RCSetPrintZoom(CRect OldRect, CRect PrintRect)
*
* PURPOSE
* Need to change the zoom factor so the graph prints on the right size,
* in the increased print space
*************************************************************************/
void AIDisplayGraph::RCSetPrintZoom(CRect OldRect, CRect PrintRect)
{
	// increase zoom factor to fill out the print rectangle
	PrintPrevZoom = ZoomRatio;
	PrintZoomRatio = (float)PrintRect.Width()/(float)OldRect.Width();
	ZoomRatio = ZoomRatio * PrintZoomRatio;


}

/************************************************************************
* Function RCRestoreZoom())
*
* PURPOSE
* Reset zoom from a print command
*************************************************************************/
void AIDisplayGraph::RCRestoreZoom()
{
	ZoomRatio = PrintPrevZoom;
	PrintZoomRatio = 1;

}

/************************************************************************
* Function RCGetNotchSize()
*
* PURPOSE
* Returns the print notch size
*************************************************************************/
int AIDisplayGraph::RCGetNotchSize()
{
	return PrintNotchSize;

}

/************************************************************************
* Function GParseMessage()
*
* PURPOSE
* Parses incoming messages from the AI
* NOTE
* the char ptr consists of one complete, whole message
*************************************************************************/
void AIDisplayGraph::DGParseMessage(char *ptr)
{
	// make sure it is an actual message
	if (*ptr != '<')
		return;

	// get to the message type
	ptr++;

	if (StreamMode == Streaming)
	{
		ptr++;
		ptr++;
		if (*ptr == '5')
		{
			// it is an ack continue
			DGRunSendMap(false);
		}
	}
	else if (StreamMode == Ending)
	{
		ptr++;
		ptr++;
		if (*ptr == '5')
		{
			StreamMode = Off;
			AfxMessageBox("Map successfully loaded");
		}
	}
/*	if (StreamMode == TRUE)
	{
		ptr++;
		unsigned short Node = EnterNode(ptr); 
		// send the confirmation message
		char ReturnMessage[30];		
		sprintf(ReturnMessage,"<%d>",Node);
		TQSend(ReturnMessage,strlen(ReturnMessage));
	}*/
	else if (*ptr == 'C')
	{
		// confirmation from the robot that it recieved the last command message
		AfxMessageBox("Message confirmed from Robot");
	}
	else if (*ptr == '9')
	{
		// a new map node has been sent over
		ptr+=2; // get rid of the overhead
		EnterNode(ptr); // now enter it into the graph
	}
	else if (*ptr == 'A')
	{	
		char tDirection;
		unsigned short CurrNode,CurrDirection,CurrDistance;
		ptr++;
		sscanf(ptr,"%d|%d|%d>",&CurrNode,&CurrDirection,&CurrDistance);
		if (CurrDirection == 1)
			tDirection = North;
		else if (CurrDirection == 2)
			tDirection = East;
		else if (CurrDirection == 3)
			tDirection = South;
		else 
			tDirection = West;

		// don't want exceptions in case this happens
		if (CurrNode > MAXNODE)
			CurrNode = 0;
		EnterCurrPosition(CurrDistance,tDirection,CurrNode);
	}
	else if (*ptr == 'B')
	{
		ptr++;
		ptr++;
		// it is a stream command
		if (*ptr == '5')
		{
			// general ack
			if (StreamMode == Starting)
			{
				StreamMode = Streaming;
				DGRunSendMap(false);
			}
		}
	}
	else if (*ptr == '5')
	{
		// it is the status messages
		int S1,S2,S3,S4;
		ptr++;
		sscanf(ptr,"%d|%d|%d|%d>",&S1,&S2,&S3,&S4);
			
		 if (S1 == 1)
		 {
			 State1 = "Initial";
		 }
		 else if (S1 == 2)
		 {
			 State1 = "FollowWall";
		 }
		 else if (S1 == 3)
		 {
			 State1 = "TurnInside";
		 }
		 else if (S1 == 4)
		 {
			 State1 = "TurnOutside";
		 }
		 else if (S1 == 5)
		 {
			 State1 = "XPDecision";
		 }
		 else if (S1 == 6)
		 {
			 State1 = "NavUnknownTo";
		 }
		 else if (S1 == 7)
		 {
			 State1 = "GotoDecision";
		 }
		 else if (S1 == 8)
		 {
			 State1 = "NavUnknownFrom";
		 }

		if (S2 == 1)	
			State2 = "North";
		else if (S2 == 2)	
			State2 = "East";
		else if (S2 == 3)	
			State2 = "South";
		else if (S2 == 4)	
			State2 = "West";   

		 if (S3 == 1)
		 {
			 State3 = "FollowWallLeft";
		 }
		 else if (S3 == 2)
		 {
			 State3 = "FollowWallRight";
		 }
		 else
		 {
			 State3 = "Follow ?";
		 }

		 if (S4 == 1)
		 {
			 State4 = "Navigating";
		 }
		 else if (S4 == 2)
		 {
			 State4 = "Mapping";
		 }
	}


}	

/************************************************************************
* Function DGSetupSendMap()
*
* PURPOSE
* Starts the send message procedure
*************************************************************************/
void AIDisplayGraph::DGSetupSendMap()
{
	char message[30];

	GSetupEnum(); // startup the enum
	StreamMode = Starting;

	// tell the robot to start the enum
	sprintf(message,"<BB1>");
	TQSend(message,strlen(message));	

}

/************************************************************************
* Function DGRunSendMap(BOOL TimeOut)
*
* PURPOSE
* Continues sending the map, on a successful recieve, or on a timeout
*************************************************************************/
void AIDisplayGraph::DGRunSendMap(BOOL TimeOut)
{
	char message[32];

	if (StreamMode == Streaming)
	{
		if (TimeOut)
		{
			GRollBackEnum(); // roll back the num to send the last node
			// if a timeout occured
		}
		char *ptr = message;
		message[0] = '<';
		ptr++;
		if (GEnumGraph(ptr))
		{		
            TQSend(message,strlen(message));
		}
		else
		{
			// send an end transmission request
			StreamMode = Ending;			
		}
	}
	
	if (StreamMode == Ending)
	{
		sprintf(message,"<BB2>");
		TQSend(message,strlen(message));
	}

}

/************************************************************************
* Function AIGetStates(CString &S1, CString &S2, CString &S3, CString &S4)
*
* PURPOSE
* The display graph keeps the states, so the main render want them
*************************************************************************/
void AIDisplayGraph::AIGetStates(CString &S1, CString &S2, CString &S3, CString &S4)
{
	S1 = State1;
	S2 = State2;
	S3 = State3;
	S4 = State4;

}

/************************************************************************
* Function ileSaveGraphAscii(CString FileName)
*
* PURPOSE
* Saves a graph, as an array in ascii format
*************************************************************************/
void AIDisplayGraph::FileSaveGraphAscii(CString FileName)
{
	CFile TheFile;
	BOOL FirstEntry = TRUE;
	char tempo[50];
	char BigArray[50000];
	short TempNum;
	char *tPtr = &(char &)TempNum;
	int Count = 0;
	int BigCount = 0;
	int LineCount = 1;

	BigArray[0] = '\0';

	TheFile.Open(FileName,CFile::modeWrite|CFile::typeBinary |CFile::modeCreate ,NULL);
	
	if (IsUpdating == FALSE)
	{
		IsUpdating = TRUE;

		GSetupEnum(); // set up the enum

		// write a [ to the file
		strcat(BigArray,"{");
		BigCount++;
	
		char Buffer[100];
		char *ptr = Buffer;
		while (GEnumGraph(ptr) == TRUE)
		{
			// 14 shorts in one node
			for (int ix = 0; ix < 14; ix++)
			{
				tPtr = &(char &)TempNum;
				*tPtr = *ptr;
				tPtr++;
				ptr++;
				*tPtr = *ptr;
				tPtr++;
				ptr++;
				if (FirstEntry)
				{
					sprintf(tempo,"%d",TempNum);
					FirstEntry = FALSE;
				}
				else
				{
					sprintf(tempo,",%d",TempNum);
				}
				if (LineCount > 13)
				{
					// add in a carrage return
					sprintf(tempo,"%s\n",tempo);
					LineCount = 0;
				}
				// write each number in seperatly;
				strcat(BigArray,tempo);				
				BigCount += strlen(tempo);
				LineCount ++;				
				Count++;
			}
			ptr = Buffer;
		}

		IsUpdating = FALSE;

		BigArray[BigCount-1] = '}';
		BigArray[BigCount] = ';';
		BigCount++;
		BigArray[BigCount] = '\0';

		char define[100];
		sprintf(define,"#define GraphArraySize %d\n\n",Count);

		// now write out the array name an size;
		sprintf(tempo,"const short %s[%d] = \n","GGraph",Count);

		
		TheFile.Write(define,strlen(define));

		TheFile.Write(tempo,strlen(tempo));

		TheFile.Write(BigArray,BigCount);

		// time to save the status
		short status[4];

		GEnumStatus4(status);

		sprintf(define,"\n\nconst short GStatus[4] = {%d,%d,%d,%d};",status[0],status[1],status[2],status[3]);		
		
		TheFile.Write(define,strlen(define));


	}
	else
		AfxMessageBox("Warning could not update for render");

	TheFile.Close();


}


