// ChildView.cpp : implementation of the CChildView class
//

#include "stdafx.h"
#include "Simulator.h"
#include "ChildView.h"
#include "RenderingOptions.h"
#include "AIExplorer.h"

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

/////////////////////////////////////////////////////////////////////////////
// CChildView

CChildView *GlobalPtr;

CChildView::CChildView()
{
    SRender.ModelPtr = &SModel;
    SRender.MapPtr = &SMap;
    SModel.MapPtr = &SMap;
    SModel.TheModel.Sensors.IRSensors.MapPtr = &SMap;
    SModel.TheModel.Sensors.SonarSensor.MapPtr = &SMap;

	GlobalPtr = this;

    #ifdef ENABLEDIRECTX 
        Options.GDIEnabled = false;
        Options.DirectXEnabled = true;
    #else
        Options.GDIEnabled = true;
        Options.DirectXEnabled = false;
    #endif

    ResetOptions();
    LoadCursors();

    // thread defaults
    ThreadInfo.EndSimThread=true;
    ThreadInfo.EndRenderThread=true;
    ThreadInfo.SimulationTime = 0;
    ThreadInfo.MaxSimulationTime = 0;
    ThreadInfo.ActualRenderPerSecond = 0;
    ThreadInfo.ActualSimsPerSecond = 0;
    ThreadInfo.SimsPerSecond = 100;
    ThreadInfo.RenderPerSecond = 50;    
    ThreadInfo.debug010sleeptime = 0;
    ThreadInfo.debug90100sleeptime = 0;
    ThreadInfo.RenderingTime = 0;
    ThreadInfo.SimLagTime = 0;
    ThreadInfo.RenderLagTime = 0;
	ThreadInfo.SimulationMultiplier = 0;

    Options.AI_Enabled = true;

	DebugPaint = 0; // paint debug information every 5th time


    Once = false;

    // create the simulation control dialog
    SimulationControlDLG.Create();
    SimulationControlDLG.m_pParent = this;
    SimulationControlDLG.ModifyStyleEx(0,WS_EX_TOPMOST,0);

    // create the Subsumption control dialog
	
	#ifdef BASICSUBAI
    SubControl.Create();
    SubControl.m_pParent = this;
    SubControl.ModifyStyleEx(0,WS_EX_TOPMOST,0);
	#endif

	#ifdef EXPLORERAI
	AIControl.Create();
    AIControl.m_pParent = this;
    AIControl.ModifyStyleEx(0,WS_EX_TOPMOST,0);
	#endif

	SDisplayGraphRect.left = 750;
	SDisplayGraphRect.right = 950;
	SDisplayGraphRect.top = 50;
	SDisplayGraphRect.bottom = 250;

	SDisplayGraphValid = TRUE;

	SDisplayGraph.AI = &AI;
  
}

CChildView::~CChildView()
{
}


BEGIN_MESSAGE_MAP(CChildView,CWnd )
	//{{AFX_MSG_MAP(CChildView)
	ON_WM_PAINT()
	ON_COMMAND(ID_FILE_OPENMODEL, OnFileOpenmodel)
	ON_COMMAND(ID_START_SIMULATOR, OnStartSimulator)
	ON_WM_DESTROY()
	ON_WM_LBUTTONDOWN()
	ON_WM_MOUSEMOVE()
	ON_COMMAND(ID_ENABLE_ZOOM, OnEnableZoom)
	ON_COMMAND(ID_RESET_VIEW, OnResetView)
	ON_WM_SETCURSOR()
	ON_WM_CHAR()
	ON_COMMAND(ID_FILE_OPENMAP, OnFileOpenmap)
	ON_COMMAND(ID_SIMCONTROL, OnSimcontrol)
	ON_COMMAND(ID_FILE_OPENSONARBEAM, OnFileOpensonarbeam)
	ON_COMMAND(ID_RESETOPTICALMOUSE, OnResetopticalmouse)
	ON_WM_SETFOCUS()
	ON_COMMAND(ID_PLACEROBOT, OnPlacerobot)
	ON_COMMAND(ID_TOGGLEAI, OnToggleai)
	ON_COMMAND(ID_SUBCONTROL, OnSubcontrol)
	ON_COMMAND(ID_RENDEROPTIONS, OnRenderoptions)
	ON_WM_CREATE()
	ON_WM_TIMER()
	ON_WM_HELPINFO()
	ON_COMMAND(ID_3DCAMERA, On3dcamera)
	ON_WM_KEYUP()
	ON_WM_KEYDOWN()
	ON_COMMAND(ID_RESETGRAPHVIEW, OnResetgraphview)
	ON_COMMAND(ID_SPEEDUPSIM, OnSpeedupsim)
	ON_COMMAND(ID_SLOWDOWNSIM, OnSlowdownsim)
	ON_COMMAND(ID_GRAPHOPTIONS_SAVEGRAPH, OnGraphoptionsSavegraph)
	ON_COMMAND(ID_GRAPHOPTIONS_OPENGRAPH, OnGraphoptionsOpengraph)
	ON_COMMAND(ID_TOGGLEGRAPHCENTER, OnTogglegraphcenter)
	ON_WM_RBUTTONUP()
	ON_COMMAND(ID_GRAPHOPTIONS_GENERATESHORTESTPATH, OnGraphoptionsGenerateshortestpath)
	ON_COMMAND(ID_GRAPHOPTIONS_SETCURRENTNODE, OnGraphoptionsSetcurrentnode)
	ON_COMMAND(ID_GRAPHOPTIONS_SETDESTINATIONNODE, OnGraphoptionsSetdestinationnode)
	ON_COMMAND(ID_GRAPHOPTIONS_PRINTGRAPH, OnGraphoptionsPrintgraph)
	ON_COMMAND(ID_DUMMYWRITE, OnDummywrite)
	ON_COMMAND(ID_GRAPHOPTIONS_SAVEGRAPHASCII, OnGraphoptionsSavegraphascii)
	ON_COMMAND(ID_GRAPHOPTIONS_LOADDEFAULTASCIIGRAPH, OnGraphoptionsLoaddefaultasciigraph)
	ON_COMMAND(ID_TOGGLEALTTEXTURE, OnTogglealttexture)
	//}}AFX_MSG_MAP
    ON_MESSAGE(WM_SIMOPTIONS,OnSimOptions)
    ON_MESSAGE(WM_USER_SET_FOCUS,OnUserSetFocus)
    ON_MESSAGE(WM_SUBOPTIONS,OnSubOptions)
	ON_MESSAGE(WM_XPOPTIONS,OnXPControlMessage)
	ON_MESSAGE(WM_UPDATE_MESSAGE,OnXPUpdateMessage)
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CChildView message handlers

BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs) 
{
	if (!CWnd::PreCreateWindow(cs))
		return FALSE;

	cs.dwExStyle |= WS_EX_CLIENTEDGE;
	cs.style &= ~WS_BORDER;
	cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS, 
		::LoadCursor(NULL, IDC_ARROW), HBRUSH(COLOR_WINDOW+1), NULL);

	return TRUE;
}

void CChildView::OnPaint() 
{

	if (Options.DirectXEnabled)
		DebugPaintPaint = 3;
	else
		DebugPaintPaint = 3;



    // get client rectangle
    CRect DBRect;
    GetClientRect(&DBRect);  

    // for differences in GDI (default) and DirectX rendering
    int TextOffset = 510;


    if (Options.DirectXEnabled)
    {
        TextOffset = 0;
    };

    FPoint CurrModel;
    CurrModel.x = SModel.TheModel.ModelState.x;
    CurrModel.y = SModel.TheModel.ModelState.y;

    // tell the renderer where the model is, in case is has to lock-on to it
    SRender.RCSetModelCoord(CurrModel);

	CPaintDC dc(this); // device context for painting

    CRect tScreen;
    tScreen.top = 10;
    tScreen.bottom = 510;
    tScreen.left = 10;
    tScreen.right = 710;

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

	if ((DebugPaint > DebugPaintPaint) || Options.GDIEnabled)
	{
		DBufferBitmap.CreateCompatibleBitmap(&dc,tScreen.Width(),tScreen.Height());
		pOldBitmap = DBufferDC.SelectObject(&DBufferBitmap);
	}


    // clear the stats debug area
    CRect StatsSpace;
    StatsSpace.left = 500;
    StatsSpace.right = 710;
    StatsSpace.top = 0;
    StatsSpace.bottom = 500;

    // directX
    CRect StatsSpace1;
    StatsSpace1.left = 0;
    StatsSpace1.right = 210;
    StatsSpace1.top = 0;
    StatsSpace1.bottom = 500;

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

    // do the main rendering
    if (Options.GDIEnabled)
    {         
        SRender.Render(DBufferDC);
		DBufferDC.FillRect(&StatsSpace,&WhiteBrush);
    }
    else if (Options.DirectXEnabled)
    {
        TextOffset = 0; 

		if (DebugPaint > DebugPaintPaint && Options.DirectXEnabled)
			DBufferDC.FillRect(&StatsSpace1,&WhiteBrush);
        
        #ifdef ENABLEDIRECTX
            DirectX.OnRender(CurrModel,SModel.TheModel.ModelState.CurrAngle);
        #endif
    }
    

    CString TextOut;

	if ((DebugPaint > DebugPaintPaint) || Options.GDIEnabled)
	{

		TextOut = "Average Simulation Time";
		DBufferDC.TextOut(TextOffset,10,TextOut);
		TextOut.Format("%8.6f",ThreadInfo.SimulationTime);
		DBufferDC.TextOut(TextOffset,25,TextOut);

		TextOut = "Maximum Simulation Time";
		DBufferDC.TextOut(TextOffset,40,TextOut);
		TextOut.Format("%8.6f",ThreadInfo.MaxSimulationTime);
		DBufferDC.TextOut(TextOffset,55,TextOut);

		TextOut = "Average Rendering Time";
		DBufferDC.TextOut(TextOffset,80,TextOut);
		TextOut.Format("%8.6f",ThreadInfo.RenderingTime);
		DBufferDC.TextOut(TextOffset,95,TextOut);

		TextOut = "Sims this Second";
		DBufferDC.TextOut(TextOffset,120,TextOut);
		TextOut.Format("%4.0f",ThreadInfo.ActualSimsPerSecond);
		DBufferDC.TextOut(TextOffset,135,TextOut);

		TextOut = "Renders this Second";
		DBufferDC.TextOut(TextOffset,160,TextOut);
		TextOut.Format("%4.0f",ThreadInfo.ActualRenderPerSecond);
		DBufferDC.TextOut(TextOffset,175,TextOut);

			TextOut = "Debug 0-10/ 90-100";
		DBufferDC.TextOut(TextOffset,200,TextOut);
		TextOut.Format("%4.0f / %4.0f",ThreadInfo.debug010sleeptime,ThreadInfo.debug90100sleeptime);
		DBufferDC.TextOut(TextOffset,215,TextOut);

			TextOut = "Lag Time";
		DBufferDC.TextOut(TextOffset,230,TextOut);
		TextOut.Format("%2.6f ",ThreadInfo.SimLagTime);
		DBufferDC.TextOut(TextOffset,245,TextOut);

		CPoint tPoint = SModel.TheModel.Sensors.OpticalMouse.GetDisplacement();

		TextOut.Format("X %d Y %d Angle %6.2f          ",tPoint.x,tPoint.y,SModel.TheModel.Sensors.OpticalMouse.GetAngle());
		DBufferDC.TextOut(TextOffset,280,TextOut);

		int TotalDistance = (int)(SModel.TheModel.Sensors.ShaftEncoders.SEGetTick3()
							/SModel.TheModel.Sensors.ShaftEncoders.TicksConst);

		TextOut.Format("Total Distance %d",TotalDistance);
		DBufferDC.TextOut(TextOffset,295,TextOut);

		long LTicks = SModel.TheModel.Sensors.ShaftEncoders.SEGetLeftTicks();
		long RTicks = SModel.TheModel.Sensors.ShaftEncoders.SEGetRightTicks();

		TextOut.Format("LeftSE %d RightSE %d           ", LTicks, RTicks);
		DBufferDC.TextOut(TextOffset,310,TextOut);

		  TextOut.Format("FIR %d RIR %d LIR %d          ", SModel.TheModel.Sensors.IRSensors.GetFrontIR(),
			  SModel.TheModel.Sensors.IRSensors.GetRightIR(),SModel.TheModel.Sensors.IRSensors.GetLeftIR());
		 DBufferDC.TextOut(TextOffset,330,TextOut);		 

		 

		#ifdef BASICSUBAI

		 if (AI.States == Initial)
			TextOut.Format("Initial State");
		 else if (AI.States == FollowWall)
			 TextOut.Format("Follow Wall State ");
		 else if (AI.States == Turning)
			 TextOut.Format("Turning  State");
		 else if (AI.States == Collision)
			 TextOut.Format("Collision State");
		 else if (AI.States == FWWithinError)
			 TextOut.Format("FWWithinError");
		 else if (AI.States == FWExceedError)
			 TextOut.Format("FWExceedError");
		 else if (AI.States == FWStraightenUp)
			 TextOut.Format("FWStraightenUp");
		 else if (AI.States == TurnArc)
			 TextOut.Format("Turning Arclike");

		 DBufferDC.TextOut(TextOffset,350,TextOut);
		#endif

		#ifdef EXPLORERAI

	    CString State1,State2,State3,State4;

	    SDisplayGraph.AIGetStates(State1,State2,State3,State4);
 

		DBufferDC.TextOut(TextOffset,350,State1);
		DBufferDC.TextOut(TextOffset,365,State2);
		DBufferDC.TextOut(TextOffset,380,State3);
		DBufferDC.TextOut(TextOffset,395,State4);

		#endif
	}


	// quick fix by putting stuff here
	if (Options.GDIEnabled)
	{ 
		dc.BitBlt(tScreen.left,tScreen.top,tScreen.Width(),tScreen.Height(),&DBufferDC,0,0,SRCCOPY);
		DBufferDC.SelectObject(pOldBitmap);
	}
	else if (Options.DirectXEnabled)
	{        
	   // DBufferDC.FillRect(&StatsSpace,&WhiteBrush);
		if (DebugPaint > DebugPaintPaint && Options.DirectXEnabled)
		{
			dc.BitBlt(StatsSpace.left+10,StatsSpace.top,StatsSpace.Width(),StatsSpace.Height(),&DBufferDC,0,0,SRCCOPY);
			DBufferDC.SelectObject(pOldBitmap);
		}
	}

	// render the graph in any case
	if (DebugPaint > DebugPaintPaint)
	{	
		SDisplayGraph.RenderGDI(dc,SDisplayGraphRect);
	}

	if (DebugPaint > DebugPaintPaint)
		DebugPaint = 0;
	else
		DebugPaint++;

}

// open up a new model
void CChildView::OnFileOpenmodel() 
{
	static char BASED_CODE szFilter[] = "Map Files (*.mpp)|*.mpp||";
	CFileDialog FileDialog(true,"*.mpp","*.mpp",OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szFilter);
    
    // change the dialog title appropriatly
    char temp[20] = "Open Model";
    FileDialog.m_ofn.lpstrTitle  = temp;


	       
    if (FileDialog.DoModal() == IDOK)
    {
        CString FileName = FileDialog.GetPathName();
        SModel.FileLoadModel(FileName);
    }

    Invalidate();
	
}

/************************************************************************
* Function SimulatorThread(LPVOID lpInfo)
* 
* PURPOSE
* This is the thread that causes the simulator to run.
* ALGORITHM
* The thread does two simple things.
* 1) It calls the function which runs the simulation
* 2) It tell the window to redraw itself
* However, at what speed?  A regulator is needed
* Regulator Algorithm (seconds based, 
* 1) After every simulation run, compute the time it took, plus the previous rendering time. Then compute the time
*    in between calls that are neccessary for it to run the predefined runs per second
* 2) The delay time is calculated and added to an incrementer variable, and the integer
*    component is used for the delay (because delays could only occur in ms
* 3) Go back to one 
*************************************************************************/
UINT CChildView::SimulatorThread(LPVOID lpInfo)
{
    THREADINFO *ThreadInfo = (THREADINFO *)lpInfo;

    LARGE_INTEGER frequency,starttime,endtime,CurrTime,BigStart,BigEnd,LagStart,LagEnd;  

    // keeps track of how much time to delay.  Used because can only sleep in milliseconds
    float DelayCounter = 0;

    // same idea, used to keep track if it is time to render, because rendering could happen
    // at some fraction of the simulation frequency
    float RenderDelayCounter = 0; 

    // goes from 0 to 1 keeps track of seconds passing by
    float Seconds = 1;
    LARGE_INTEGER SecondsStart;    

    float LoopTime = 0; // keeps track of how much time is took to simulate plus render.

    int SimsthisSecond = 0;

    // debug/stats variables
    float tSleep2 = 0;
    float tSleep1 = 0;

    // how much time extra time is sleeped
    float LagTime = 0;

    // used for the delta time to input to the simulator function
    float PreviousTime = 0;

    // used to calculate the average sim time
    float TotalSimTime = 0;

    CurrTime.QuadPart = 0;
    SecondsStart.QuadPart = 0;
    
    ::QueryPerformanceFrequency(&frequency);
    //::QueryPerformanceCounter(&CurrTime);

    ThreadInfo->RenderingTime = 0; // initilize
    
    while (!ThreadInfo->EndSimThread)
    {
      
        if (Seconds >= 1)
        {     
            // Setup Previous time because of the seconds roll over
            Seconds = (float)(CurrTime.QuadPart - SecondsStart.QuadPart)/(float)frequency.QuadPart;
            PreviousTime = Seconds - PreviousTime;

             ::QueryPerformanceCounter(&SecondsStart); 
             CurrTime = SecondsStart;
            ThreadInfo->ActualSimsPerSecond = (float)SimsthisSecond;
            ThreadInfo->SimulationTime = TotalSimTime/SimsthisSecond;
            TotalSimTime = 0;
            SimsthisSecond = 0;
            ThreadInfo->debug010sleeptime = tSleep1;
            ThreadInfo->debug90100sleeptime = tSleep2;
            ThreadInfo->SimLagTime = LagTime;
            LagTime = 0;

            tSleep1 = tSleep2 = 0;
            
        }   

        ///////////////////////////////////////////////////////////////////
        // Simulator Control                                              /
        ///////////////////////////////////////////////////////////////////

        ::QueryPerformanceCounter(&starttime);
        BigStart = starttime;

        // update Seconds
        Seconds = (float)(CurrTime.QuadPart - SecondsStart.QuadPart)/(float)frequency.QuadPart;

        float DeltaTime = Seconds - PreviousTime;
        PreviousTime = Seconds;

		// when debugging a large deltatime may occur right after exiting the restarted the program
		// so this prevents a huge movement from occuring
		if ((abs((int)DeltaTime) < .10) && DeltaTime > 0)
		{
			ThreadInfo->ParentPtr->SModel.RunSimulation(DeltaTime*ThreadInfo->SimulationMultiplier);
			// this is to simulator a kernel timer
			// adjust it for the simulation multiplier though
			short tempTicks = short(Seconds*1000*ThreadInfo->SimulationMultiplier);
			while (tempTicks >= 1000)
			{
				tempTicks -= 999;
			}			
			ThreadInfo->ParentPtr->SModel.MVStruct.KRNLTicks = tempTicks;
			if (ThreadInfo->ParentPtr->Options.AI_Enabled)
			{
			#ifdef  BASICSUBAI
				ThreadInfo->ParentPtr->AI.AIRun();
			#endif
			#ifdef  EXPLORERAI
				ThreadInfo->ParentPtr->AI.AIRun();
			#endif
			}
		}
        ::QueryPerformanceCounter(&endtime);
        SimsthisSecond++;

        float TempTime = (float)(endtime.QuadPart-starttime.QuadPart)/(float)frequency.QuadPart;

        TotalSimTime += TempTime;        
  

        // do the maximum rendering time for stats sake
        if (TempTime > ThreadInfo->MaxSimulationTime)
            ThreadInfo->MaxSimulationTime = TempTime;

        // Take the total time of the rendering plus simulation
       // LoopTime += ThreadInfo->SimulationTime;

 
        ::QueryPerformanceCounter(&endtime);
        BigEnd = endtime;

        ///////////////////////////////////////////////////////////////////
        // Figure out the sleep time                                      /
        ///////////////////////////////////////////////////////////////////

        ::QueryPerformanceCounter(&CurrTime);
         // update Seconds
        Seconds = (float)(CurrTime.QuadPart - SecondsStart.QuadPart)/(float)frequency.QuadPart;

        int SimsLefttoDo = (int)(ThreadInfo->SimsPerSecond - SimsthisSecond);

        // formula in english...
        // 1) Take the timeleft and subtract the time it will take to do the remaining sims
        //    plus rendering
        // 2) Divide that by the sims remaining to get the time given by each sim to complete
        //    which gives the time per sim to delay the sim by
        float Incrementer;

        // division with 0 when 0, beware
        if (SimsLefttoDo == 0)
        {
            Incrementer = 0;
        }
        else
        {
            LoopTime = (float)(BigEnd.QuadPart-BigStart.QuadPart)/(float)frequency.QuadPart; 
            Incrementer = ((float)((float)1.0-Seconds) - LoopTime*((float)SimsLefttoDo))/(float)SimsLefttoDo - ThreadInfo->SimLagTime/ThreadInfo->SimsPerSecond;
        } 
        LoopTime = 0; // A loop is complete reset time.


        ///////////////////////////////////////////////////////////////////
        // Time to Sleep                                                  /
        ///////////////////////////////////////////////////////////////////

        if (Incrementer < 0)
            Incrementer = 0;

        DelayCounter += Incrementer*1000; // in ms not seconds

        int Delay = (int)DelayCounter;
        DelayCounter -= Delay;



        ::QueryPerformanceCounter(&LagStart);

        if (Delay > 0)
        {
            ASSERT(Delay < 5000); // this can't be right
            Sleep(Delay);    
            
            ::QueryPerformanceCounter(&LagEnd);

            LagTime += (float)(LagEnd.QuadPart - LagStart.QuadPart)/(float)frequency.QuadPart - (float)Delay/1000;
        }        

        if (SimsthisSecond > ThreadInfo->SimsPerSecond-10)
            tSleep2 += Delay;
        else if (SimsthisSecond < 11)
            tSleep1 += Delay;   

    }

   // ThreadInfo->EndSimThread = false;

    return 0;
}

//kick off the simulator thread
void CChildView::OnStartSimulator() 
{
    if (ThreadInfo.EndSimThread)
    {
        ThreadInfo.ParentPtr = this;
        ThreadInfo.EndSimThread = false;  
        ThreadInfo.EndRenderThread = false;
        ::SetThreadPriority(this->m_hWnd,HIGH_PRIORITY_CLASS);
	    ThreadInfo.SimThreadPtr = AfxBeginThread(SimulatorThread,(LPVOID) &ThreadInfo, THREAD_PRIORITY_TIME_CRITICAL);
        ThreadInfo.RenderThreadPtr = AfxBeginThread(RenderThread,(LPVOID) &ThreadInfo, THREAD_PRIORITY_TIME_CRITICAL);

    }
    else
    {
        ThreadInfo.EndSimThread = true;
        ThreadInfo.EndRenderThread = true;
    }
	
}

// clean up the thread
void CChildView::OnDestroy() 
{
    if (ThreadInfo.EndSimThread == false)
    {
        HANDLE hThread[2];
        hThread[0] = ThreadInfo.SimThreadPtr->m_hThread;
        hThread[1] = ThreadInfo.RenderThreadPtr->m_hThread;

        // shut off the threads
        ThreadInfo.EndRenderThread = true;
        ThreadInfo.EndSimThread = true;

         // wait for the threads to end
        ::WaitForMultipleObjects(2,hThread,true,200);    
        
    }

	CWnd ::OnDestroy();   
	
}

void CChildView::OnLButtonDown(UINT nFlags, CPoint point) 
{
	if (Options.E_ZoomEnabled)
    {
		if (SDisplayGraphValid)
		{
			if (LAUtils.InRect(point,SDisplayGraphRect))
			{
				SDisplayGraph.RCSetZoomPoint(point);
			}
		}
        if (Options.GDIEnabled)
        {
            SRender.RCSetZoomPoint(point);
        }
        else if (Options.DirectXEnabled)
        {
            #ifdef ENABLEDIRECTX 
                DirectX.RCSetZoomPoint(point);                
            #endif
        }
    }
    else if (Options.E_PlaceRobotEnabled)
    {
        if (Options.GDIEnabled)
        {       
            // try to move the robot to this point, do it here
            CPoint MapPoint = SRender.ScreentoReal(point);

            if (!SModel.UDoSafetyCheck(MapPoint))
                AfxMessageBox("Can't move robot there");

            Invalidate(false);
        }
       
    }


    #ifdef ENABLEDIRECTX 
        DirectX.OnResetMouse();            
    #endif      
	
	CWnd ::OnLButtonDown(nFlags, point);
}

void CChildView::ResetOptions()
{
    Options.E_ZoomEnabled = false;
    Options.E_PlaceRobotEnabled = false;
    Options.DirectX3DMovementEnabled = false;
    Options.CurrCursor = 0;
}

void CChildView::OnMouseMove(UINT nFlags, CPoint point) 
{
	if ((nFlags == MK_LBUTTON) && Options.E_ZoomEnabled)
    {
		if (SDisplayGraphValid && LAUtils.InRect(point,SDisplayGraphRect))
		{
			SDisplayGraph.RCZoom(point);
		}
        else if (Options.GDIEnabled)
        {
            SRender.RCZoom(point);
        }
        else if (Options.DirectXEnabled)
        {        
        #ifdef ENABLEDIRECTX 
             DirectX.RCZoom(point);
        #endif
        }
    }
    if ((nFlags == MK_LBUTTON) && (Options.DirectXEnabled))
    {
		if (!(SDisplayGraphValid && LAUtils.InRect(point,SDisplayGraphRect)))
		{
        #ifdef ENABLEDIRECTX 
             DirectX.OnMouseMove(point);
        #endif
		}
    }

        Invalidate(false);
  
	CWnd ::OnMouseMove(nFlags, point);
}

void CChildView::OnEnableZoom() 
{
	ResetOptions();
    Options.E_ZoomEnabled = true;
    Options.CurrCursor = 1;
	
}

void CChildView::OnResetView() 
{    
    ResetOptions();
    if (Options.GDIEnabled)
    {
	    SRender.RCResetView();
    }
    else if (Options.DirectXEnabled)
    {
        #ifdef ENABLEDIRECTX 
             DirectX.ResetView();
        #endif
    }

    Invalidate(false);
	
}

// loads the cursors
void CChildView::LoadCursors()
{
    m_hCursor[0] =::LoadCursor( NULL, IDC_ARROW );
    m_hCursor[1] = AfxGetApp( )->LoadCursor(IDC_ZOOM);
    m_hCursor[2] = AfxGetApp( )->LoadCursor(IDC_PLACEROBOT);

}

BOOL CChildView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
{
	::SetCursor( m_hCursor[Options.CurrCursor] );
    return true;
	
	return CWnd ::OnSetCursor(pWnd, nHitTest, message);
}

void CChildView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	// TODO: Add your message handler code here and/or call default

    if (nChar >= 49 && nChar <= 57)
    {
        SModel.InputfromKeyboard(nChar);
    }
	
	CWnd ::OnChar(nChar, nRepCnt, nFlags);
}

void CChildView::OnFileOpenmap() 
{
	static char BASED_CODE szFilter[] = "Map Files (*.mpp)|*.mpp||";
	CFileDialog FileDialog(true,"*.mpp","*.mpp",OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szFilter);

    // change the dialog title appropriatly
    char temp[20] = "Open Map";
    FileDialog.m_ofn.lpstrTitle  = temp;
	       
    if (FileDialog.DoModal() == IDOK)
    {
        // can't run at the same time
        if (!ThreadInfo.EndSimThread)
        {
             HANDLE hThread[2];
            hThread[0] = ThreadInfo.SimThreadPtr->m_hThread;
            hThread[1] = ThreadInfo.RenderThreadPtr->m_hThread;

            // shut off the threads
            ThreadInfo.EndRenderThread = true;
            ThreadInfo.EndSimThread = true;

             // wait for the threads to end
            ::WaitForMultipleObjects(2,hThread,true,200); 
        }

		CRect RobotPlacement;

        CString FileName = FileDialog.GetPathName();
        RobotPlacement = SMap.FileOpenMap(FileName);

		CPoint Place;

		Place.x = RobotPlacement.left;
		Place.y = RobotPlacement.top;

		SModel.TheModel.ModelState.CurrAngle = (float)RobotPlacement.right;

		if (!SModel.UDoSafetyCheck(Place))
                AfxMessageBox("Warning Map Inital Placement intersects wall");

		AI.AIInitialize();
		SDisplayGraph.InitGraph();

		

         #ifdef ENABLEDIRECTX
         if (Options.DirectXEnabled)
               DirectX.LoadWalls(); // the class that handles all of the directX rendering       
         #endif


    }

    Invalidate();
    UpdateWindow();
	
}

UINT CChildView::RenderThread(LPVOID lpInfo)
{
    THREADINFO *ThreadInfo = (THREADINFO *)lpInfo;

    LARGE_INTEGER frequency,starttime,endtime,CurrTime,BigStart,BigEnd,LagStart,LagEnd;  

    // keeps track of how much time to delay.  Used because can only sleep in milliseconds
    float DelayCounter = 0;

    // same idea, used to keep track if it is time to render, because rendering could happen
    // at some fraction of the simulation frequency
    float RenderDelayCounter = 0; 

    // goes from 0 to 1 keeps track of seconds passing by
    float Seconds = 1;
    LARGE_INTEGER SecondsStart;    

    float LoopTime = 0; // keeps track of how much time is took to simulate plus render.

    // used to obtain the average rendering time
    int RendersthisSecond = 0;

    // how much time extra time is sleeped
    float LagTime = 0;

    float TotalRenderingTime = 0;
 
    ::QueryPerformanceFrequency(&frequency);

    ThreadInfo->RenderingTime = 0; // initilize
    
    while (!ThreadInfo->EndRenderThread)
    {
      
        if (Seconds >= 1)
        {     
             ::QueryPerformanceCounter(&SecondsStart);
            // reset some stats
            ThreadInfo->ActualRenderPerSecond = (float)RendersthisSecond;
            ThreadInfo->RenderingTime = TotalRenderingTime/RendersthisSecond;
            TotalRenderingTime = 0;
            RendersthisSecond = 0;  
            ThreadInfo->RenderLagTime = LagTime;
            LagTime = 0;
        }           
       
        ///////////////////////////////////////////////////////////////////
        // Render Control                                                 /
        ///////////////////////////////////////////////////////////////////

       
        ::QueryPerformanceCounter(&starttime);   
        BigStart = starttime;
        ThreadInfo->ParentPtr->Invalidate(false);
        ThreadInfo->ParentPtr->UpdateWindow();
        ::QueryPerformanceCounter(&endtime);
        BigEnd = endtime;

        TotalRenderingTime += (float)(endtime.QuadPart-starttime.QuadPart)/(float)frequency.QuadPart;                
       
        RendersthisSecond++;  

        ///////////////////////////////////////////////////////////////////
        // Figure out the sleep time                                      /
        ///////////////////////////////////////////////////////////////////

        ::QueryPerformanceCounter(&CurrTime);
         // update Seconds
        Seconds = (float)(CurrTime.QuadPart - SecondsStart.QuadPart)/(float)frequency.QuadPart;

        int RendersLefttoDo = (int)(ThreadInfo->RenderPerSecond - RendersthisSecond);

        // formula in english...
        // 1) Take the timeleft and subtract the time it will take to do the remaining sims
        //    plus rendering
        // 2) Divide that by the sims remaining to get the time given by each sim to complete
        //    which gives the time per sim to delay the sim by
        float Incrementer;

        // division with 0 when 0, beware
        if (RendersLefttoDo == 0)
        {
            Incrementer = 0;
        }
        else
        {
            LoopTime = (float)(BigEnd.QuadPart-BigStart.QuadPart)/(float)frequency.QuadPart;        
            Incrementer = ((float)((float)1.0-Seconds) - LoopTime*((float)RendersLefttoDo))/(float)RendersLefttoDo - ThreadInfo->RenderLagTime/ThreadInfo->RenderPerSecond;
        } 
        LoopTime = 0; // A loop is complete reset time.


        ///////////////////////////////////////////////////////////////////
        // Time to Sleep                                                  /
        ///////////////////////////////////////////////////////////////////

        if (Incrementer < 0)
            Incrementer = 0;

        DelayCounter += Incrementer*1000; // in ms not seconds

        int Delay = (int)DelayCounter;
        DelayCounter -= Delay;

        ::QueryPerformanceCounter(&LagStart);

        if (Delay > 0)
        {
            ASSERT(Delay < 500); // this can't be right
            Sleep(Delay);    
            
            ::QueryPerformanceCounter(&LagEnd);

            LagTime += (float)(LagEnd.QuadPart - LagStart.QuadPart)/(float)frequency.QuadPart - (float)Delay/1000;
        }     
       

    }

   // ThreadInfo->EndRenderThread = false;

    return 0;


}

// restore showing the control dialog box
void CChildView::OnSimcontrol() 
{
    if (SimulationControlDLG.IsWindowVisible())
    {
        SimulationControlDLG.ShowWindow(SW_HIDE);
    }
    
    else
    {
	    SimulationControlDLG.ShowWindow(SW_RESTORE);
        SimulationControlDLG.EnableWindow(true); // possibly disabled by a previous hide
        SimulationControlDLG.BringWindowToTop();
    }
}

// Some options have been changed in the dialog.  Change current settings
LRESULT CChildView::OnSimOptions(WPARAM SentMessage, LPARAM)
{
    SSimControl::SIMCONTROLMESSAGE *Message;

    Message = (SSimControl::SIMCONTROLMESSAGE *)SentMessage;

    ThreadInfo.RenderPerSecond = (float)Message->ActualRenderSpeed;
    ThreadInfo.SimsPerSecond = (float)Message->ActualSimSpeed; 
	ThreadInfo.SimulationMultiplier = Message->ActualSimMultiplier;
	SModel.SimMultiplier = Message->ActualSimMultiplier;

    if (Message->RealRenderingScale)
    {
        SRender.SensorRenderingScale = REALRENDERINGSCALE;
    }
    else
         SRender.SensorRenderingScale = BIGRENDERINGSCALE;

    SModel.TheModel.Sensors.SonarSensor.SetSpeedofSound(Message->SonarSpeedofSound);
    SModel.TheModel.Sensors.SonarSensor.SetBeamAngle(Message->SonarBeamAngle);
    SModel.TheModel.Sensors.SonarSensor.SetStreamAngle(Message->SonarStreamAngle);
    SModel.TheModel.Sensors.SonarSensor.SetMaximumDistance(Message->SonarMaximumDistance);
    SModel.TheModel.Sensors.SonarSensor.SetRenderOptions(Message->RenderPastSonarCollisions
        ,Message->RenderPastSonarBeams,Message->NumberofPastSonarCollisions, Message->ExtraSonarFlipping);


    SRender.RCSetFollowModel(Message->FollowModel);

      SModel.TheModel.Sensors.IRSensors.SetIRNonIdeality(Message->IRNonIdeality);


    



    Invalidate(false);


    return 0;

}

void CChildView::OnFileOpensonarbeam() 
{
		static char BASED_CODE szFilter[] = "Map Files (*.mpp)|*.mpp||";
	CFileDialog FileDialog(true,"*.mpp","*.mpp",OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szFilter);
    
    // change the dialog title appropriatly
    char temp[20] = "Open Sonar Beam";
    FileDialog.m_ofn.lpstrTitle  = temp;
	       
    if (FileDialog.DoModal() == IDOK)
    {
        CString FileName = FileDialog.GetPathName();
        SModel.TheModel.Sensors.SonarSensor.LoadSonarBeam(FileName);
    }

    Invalidate();
	
}

void CChildView::OnResetopticalmouse() 
{
	SModel.TheModel.Sensors.OpticalMouse.ClearDisplacement();
    SModel.TheModel.Sensors.ShaftEncoders.SEReset(true);
    AI.AIInitialize(); // reset the AI
	SModel.TheModel.Sensors.SonarSensor.SNRSet3PointScanA();
	
}

void CChildView::LoadDefaultSettings()
{
    CString Model,Map;
    
    // looks for the model file
    if (Settings.SearchforKey(INIMODEL,Model))
    {
        // check if the file exists
       
        CString FileName = ROOTDIRECTORY + Model;
        CFile NewFile;
        if (NewFile.Open(FileName,CFile::modeRead|CFile::typeBinary ,NULL))
        {
            NewFile.Close();
            SModel.FileLoadModel(FileName);
        }
        else
             AfxMessageBox("Unable to load Default Model");
    }
    else
        AfxMessageBox("Warning possible INI file corruptions, Default Model not loaded");
    
    // look for the map file
    if (Settings.SearchforKey(INIMAP,Map))
    {
           // check if the file exists
       
        CString FileName = ROOTDIRECTORY + Map;
        CFile NewFile;
        if (NewFile.Open(FileName,CFile::modeRead|CFile::typeBinary ,NULL))
        {
			NewFile.Close();
			CRect RobotPlacement;
			
			RobotPlacement = SMap.FileOpenMap(FileName);

			CPoint Place;

			Place.x = RobotPlacement.left;
			Place.y = RobotPlacement.top;

			SModel.TheModel.ModelState.CurrAngle = (float)RobotPlacement.right;

			if (!SModel.UDoSafetyCheck(Place))
					AfxMessageBox("Warning Map Inital Placement intersects wall");				


        }
        else
             AfxMessageBox("Unable to load Default Map");
    }
    else
         AfxMessageBox("Warning possible INI file corruptions, Default Map not loaded");



}

void CChildView::OnSetFocus(CWnd* pOldWnd) 
{
	CWnd ::OnSetFocus(pOldWnd);

	// TODO: Add your message handler code here
	
}

//manually set the focus
LRESULT CChildView::OnUserSetFocus(WPARAM, LPARAM)
{
    SetFocus();
    return 0;

}

// moves the robot to a new coordinate
void CChildView::OnPlacerobot() 
{
    ResetOptions();
	Options.E_PlaceRobotEnabled = true;
    Options.CurrCursor = 2;
    
	
}

void CChildView::OneTimeInit()
{
    // load stuff from the ini file
    LoadDefaultSettings();

    // let it set the defaults
    SimulationControlDLG.SendUpdateMessage();

    AI.TheModel = &SModel;
	AI.ParentPtr = this;
    AI.AIInitialize();


}

void CChildView::OnToggleai() 
{
    if (Options.AI_Enabled)
	    Options.AI_Enabled = false;
    else
        Options.AI_Enabled = true;
	
}

void CChildView::OnSubcontrol() 
{
	#ifdef BASICSUBAI
    if (SubControl.IsWindowVisible())
    {
        SubControl.ShowWindow(SW_HIDE);
    }
    
    else
    {
	    SubControl.ShowWindow(SW_RESTORE);
        SubControl.EnableWindow(true); // possibly disabled by a previous hide
        SubControl.BringWindowToTop();
    }
	#endif

	#ifdef EXPLORERAI
	if (AIControl.IsWindowVisible())
    {
        AIControl.ShowWindow(SW_HIDE);
    }
    
    else
    {
	    AIControl.ShowWindow(SW_RESTORE);
        AIControl.EnableWindow(true); // possibly disabled by a previous hide
        AIControl.BringWindowToTop();
    }
	#endif
	
}

LRESULT CChildView::OnSubOptions(WPARAM SentMessage, LPARAM)
{
    #ifdef BASICSUBAI
    Subsumption::SUBSUMPTIONOPTIONS *Message;

    Message = (Subsumption::SUBSUMPTIONOPTIONS *)SentMessage;

    AI.LoadSettings(*Message);
    #endif


    return 0;

}

void CChildView::OnRenderoptions() 
{
    RenderingOptions tDialog;
    tDialog.m_DirectXEnabled = Options.DirectXEnabled;
    tDialog.m_GDIEnabled = Options.GDIEnabled;

    #ifdef ENABLEDIRECTX
        tDialog.m_CameraType = (RenderingOptions::CAMERATYPE)DirectX.TheCamera.CameraMode;
    #endif

    if (tDialog.DoModal() == IDOK)
    {
        if (Options.GDIEnabled)
        {
            if (tDialog.m_DirectXEnabled)
            {
                #ifdef ENABLEDIRECTX
                    // do this before the redraw calls
                    Options.GDIEnabled = tDialog.m_GDIEnabled;
                    Options.DirectXEnabled = tDialog.m_DirectXEnabled;  

                    // time to enable directX
                    DirectX.Enabled = true;
                    DirectX.FrameWindow.ModifyStyle(0,WS_VISIBLE,0);
                    DirectX.FrameWindow.EnableWindow(true);
                    DirectX.FrameWindow.Invalidate(true); 
                    DirectX.FrameWindow.UpdateWindow();
                    DirectX.SetCameraType(tDialog.m_CameraType);
                    FramePtr->Invalidate(true);
                    FramePtr->UpdateWindow();
                    Invalidate(true);
                    UpdateWindow();
               #endif
            }
        }
        else if (Options.DirectXEnabled)
        {
                            // time to enabled the GDI
            #ifdef ENABLEDIRECTX
                DirectX.SetCameraType(tDialog.m_CameraType);
            #endif
            if (tDialog.m_GDIEnabled)
            {
                // do this before the redraw calls
                Options.GDIEnabled = tDialog.m_GDIEnabled;
                Options.DirectXEnabled = tDialog.m_DirectXEnabled;  

                // time to enabled the GDI
                #ifdef ENABLEDIRECTX
                    DirectX.Enabled = false;
                    DirectX.FrameWindow.ModifyStyle(WS_VISIBLE,0,0);
                    DirectX.FrameWindow.EnableWindow(false);
                #endif
                Invalidate(true);
                UpdateWindow();
                FramePtr->Invalidate(true);
                UpdateWindow();
                               
            }
        }
      
    }
	
}

int CChildView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CWnd ::OnCreate(lpCreateStruct) == -1)
		return -1;

    OneTimeInit();

    // create the extra directX window
    #ifdef ENABLEDIRECTX
        DirectX.Enabled = Options.DirectXEnabled;
        DirectX.FramePtr = FramePtr;
        DirectX.LParent = this;
        DirectX.Create();  
        DirectX.MapPtr = &SMap;
        DirectX.SModel = &SModel;
        DirectX.LoadWalls(); // the class that handles all of the directX rendering
        if (Options.DirectXEnabled)
          SetTimer(100,10,0);

    #endif


	
	// TODO: Add your specialized creation code here
	
	return 0;
}

void CChildView::OnTimer(UINT nIDEvent) 
{
	if (Options.DirectXEnabled)
          Invalidate(false);

    KillTimer(nIDEvent);
	
	CWnd ::OnTimer(nIDEvent);
}

BOOL CChildView::OnHelpInfo(HELPINFO* pHelpInfo) 
{
	CFile FileExists;

    if (FileExists.Open("..\\SimulatorHelp.chm",CFile::modeReadWrite | CFile::shareDenyNone))
    {
        FileExists.Close();
        if (HtmlHelp(this->m_hWnd,"..\\SimulatorHelp.chm",HH_DISPLAY_TOPIC,NULL) == NULL)
        {
            AfxMessageBox("Warning, Could not open help file");
        }
    }
    else if (FileExists.Open(".\\SimulatorHelp.chm",CFile::modeReadWrite | CFile::shareDenyNone))
    {
        FileExists.Close();
        if (HtmlHelp(this->m_hWnd,".\\SimulatorHelp.chm",HH_DISPLAY_TOPIC,NULL) == NULL)
        {
            AfxMessageBox("Warning, Could not open help file");
        }
    }
    else if (FileExists.Open(".\\hlp\\SimulatorHelp.chm",CFile::modeReadWrite | CFile::shareDenyNone))
    {
        FileExists.Close();
        if (HtmlHelp(this->m_hWnd,".\\hlp\\SimulatorHelp.chm",HH_DISPLAY_TOPIC,NULL) == NULL)
        {
            AfxMessageBox("Warning, Could not open help file");
        }
    }
    else if (FileExists.Open("..\\hlp\\SimulatorHelp.chm",CFile::modeReadWrite | CFile::shareDenyNone))
    {
        FileExists.Close();
        if (HtmlHelp(this->m_hWnd,"..\\hlp\\SimulatorHelp.chm",HH_DISPLAY_TOPIC,NULL) == NULL)
        {
            AfxMessageBox("Warning, Could not open help file");
        }
    }
    else
        AfxMessageBox("Warning, Could not open help file");

	return CWnd::OnHelpInfo(pHelpInfo); 

}

// enabled the keys and mouse to move the directX camera
void CChildView::On3dcamera() 
{
    
    if (!Options.DirectX3DMovementEnabled)
    {
        #ifdef ENABLEDIRECTX 
            ResetOptions();
            Options.DirectX3DMovementEnabled = true;
            Options.CurrCursor = 0;
            DirectX.OnResetMouse();
        #endif      
	    
    }
    else
    {
        #ifdef ENABLEDIRECTX 
           ResetOptions();
        #endif    
        
    }

}

void CChildView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	if (nChar == VK_ESCAPE)
	{
		ResetOptions();
	}

   #ifdef ENABLEDIRECTX  
            DirectX.OnResetChar();
   #endif  
	
	CWnd ::OnKeyUp(nChar, nRepCnt, nFlags);
}

void CChildView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
   #ifdef ENABLEDIRECTX 
        DirectX.OnChar(nChar);
   #endif  

	
	CWnd ::OnKeyDown(nChar, nRepCnt, nFlags);
}

void CChildView::OnResetgraphview() 
{
	if (SDisplayGraphValid)	
		SDisplayGraph.RCReset();
	
}

void CChildView::OnSpeedupsim() 
{
	if (SimulationControlDLG.m_hWnd != NULL)
	{
		::SendMessage(SimulationControlDLG.m_hWnd,WM_SPEEDUPSIM,0,0);
	}
}

void CChildView::OnSlowdownsim() 
{
	if (SimulationControlDLG.m_hWnd != NULL)
	{
		::SendMessage(SimulationControlDLG.m_hWnd,WM_SLOWDOWNSIM,0,0);
	}	
}

void CChildView::OnGraphoptionsSavegraph() 
{
	static char BASED_CODE szFilter[] = "Graph Files (*.mpg)|*.mpg||";
	CFileDialog FileDialog(false,"*.mpg","*.mpg",OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szFilter);

    // change the dialog title appropriatly
    char temp[20] = "Save Graph";
    FileDialog.m_ofn.lpstrTitle  = temp;
	
    if (FileDialog.DoModal() == IDOK)
    {
        // can't run at the same time
        if (!ThreadInfo.EndSimThread)
        {
             HANDLE hThread[2];
            hThread[0] = ThreadInfo.SimThreadPtr->m_hThread;
            hThread[1] = ThreadInfo.RenderThreadPtr->m_hThread;

            // shut off the threads
            ThreadInfo.EndRenderThread = true;
            ThreadInfo.EndSimThread = true;

             // wait for the threads to end
            ::WaitForMultipleObjects(2,hThread,true,200); 
        }	

        CString FileName = FileDialog.GetPathName();
		SDisplayGraph.FileSaveGraph(FileName);
    }

}

void CChildView::OnGraphoptionsOpengraph() 
{
	static char BASED_CODE szFilter[] = "Graph Files (*.mpg)|*.mpg||";
	CFileDialog FileDialog(true,"*.mpg","*.mpg",OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szFilter);

    // change the dialog title appropriatly
    char temp[20] = "Open Graph";
    FileDialog.m_ofn.lpstrTitle  = temp;
	       
    if (FileDialog.DoModal() == IDOK)
    {
        // can't run at the same time
        if (!ThreadInfo.EndSimThread)
        {
             HANDLE hThread[2];
            hThread[0] = ThreadInfo.SimThreadPtr->m_hThread;
            hThread[1] = ThreadInfo.RenderThreadPtr->m_hThread;

            // shut off the threads
            ThreadInfo.EndRenderThread = true;
            ThreadInfo.EndSimThread = true;

             // wait for the threads to end
            ::WaitForMultipleObjects(2,hThread,true,200); 
        }

	

        CString FileName = FileDialog.GetPathName();
		SDisplayGraph.FileOpenGraph(FileName);
    }

    Invalidate();
    UpdateWindow();
	
}

// global used for cheat position
void CChildView::GlobalSetZero()
{
	GlobalPosition.x = (short)SModel.TheModel.ModelState.x;
	GlobalPosition.y = (short)SModel.TheModel.ModelState.y;

}

GPOINT CChildView::GlobalGetPosition()
{
	GPOINT temp;
	temp.x = (short)(SModel.TheModel.ModelState.x - GlobalPosition.x);
	temp.y = (short)(SModel.TheModel.ModelState.y - GlobalPosition.y);
	return temp;
}

void CChildView::OnTogglegraphcenter() 
{
	SDisplayGraph.RCToggleAutoCenter();
	
}

void CChildView::OnRButtonUp(UINT nFlags, CPoint point) 
{
	if (SDisplayGraphValid)
	{
		if (LAUtils.InRect(point,SDisplayGraphRect))
		{
			SDisplayGraph.RCMouseDown(point);
			// force a redraw
			DebugPaint = DebugPaintPaint+1;
			Invalidate(false);
			UpdateWindow();
		}
	}

	
	CWnd ::OnRButtonUp(nFlags, point);
}

void CChildView::OnGraphoptionsGenerateshortestpath() 
{
	SDisplayGraph.GetShortestPath();
	
}

void CChildView::OnGraphoptionsSetcurrentnode() 
{
	SDisplayGraph.RCSetCurrentNode();
	
}

void CChildView::OnGraphoptionsSetdestinationnode() 
{
	SDisplayGraph.RCSetDestination();
	
}

LRESULT CChildView::OnXPControlMessage(WPARAM WParam, LPARAM)
{
	#ifdef EXPLORERAI
    XPMessageStruct *Message;

    Message = (XPMessageStruct *)WParam;

    SDisplayGraph.RCSendXPCommand(*Message);
    #endif	

	return 0;
}

void CChildView::OnGraphoptionsPrintgraph() 
{
	CPrintDialog  PrintDialog(false,PD_DISABLEPRINTTOFILE | PD_RETURNDC ,this);

    if (PrintDialog.DoModal() == IDOK)
    {
        CRect PrinterSize;
        PrinterSize.top = 10;
        PrinterSize.left = 10;
        PrinterSize.right = 2000;
        PrinterSize.bottom= 2200;
        HDC PrintHDC = PrintDialog.GetPrinterDC();   

        CDC *PrintDC;
        PrintDC = CDC::FromHandle(PrintHDC);



        DOCINFO DocInfo;
        DocInfo.cbSize = sizeof(DOCINFO);
        DocInfo.lpszDocName = "Graph Output";
        DocInfo.lpszDatatype = NULL;
        DocInfo.lpszOutput = NULL;
        PrintDC->StartDoc(&DocInfo);
        PrintDC->StartPage();    

                  // clear the DC
        CBrush WhiteBrush(RGB(255,255,255));
        PrintDC->FillRect(&PrinterSize,&WhiteBrush); 
		PrinterSize.bottom= 2000;
		SDisplayGraph.RCEnablePrintPens();
		SDisplayGraph.RCSetPrintZoom(SDisplayGraphRect,PrinterSize);
        SDisplayGraph.RenderGDI(*PrintDC,PrinterSize);
		SDisplayGraph.RCRestoreZoom();
		SDisplayGraph.RCEnableNormalPens();
		CString tempo;
		tempo.Format("Graph Output, One Notch is %dcm",SDisplayGraph.RCGetNotchSize());
        PrintDC->TextOut(0,2050,tempo);
        
        Print(PrintDC,PRF_CHILDREN);   
        PrintDC->EndPage();
        PrintDC->EndDoc();
        DeleteDC(PrintHDC);

    }
	
}

// incoming message
LRESULT CChildView::OnXPUpdateMessage(WPARAM Message, LPARAM)
{
	char *message = (char *)Message;
	SDisplayGraph.DGParseMessage(message);

	return 0;

}

void CChildView::OnDummywrite() 
{
	// do a test
	SDisplayGraph.DGSetupSendMap();
	
}

void CChildView::OnGraphoptionsSavegraphascii() 
{
	static char BASED_CODE szFilter[] = "C style header file (*.h)|*.h||";
	CFileDialog FileDialog(false,"*.h","*.h",OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szFilter);

    // change the dialog title appropriatly
    char temp[20] = "Save Graph Ascii";
    FileDialog.m_ofn.lpstrTitle  = temp;
	
    if (FileDialog.DoModal() == IDOK)
    {
        // can't run at the same time
        if (!ThreadInfo.EndSimThread)
        {
             HANDLE hThread[2];
            hThread[0] = ThreadInfo.SimThreadPtr->m_hThread;
            hThread[1] = ThreadInfo.RenderThreadPtr->m_hThread;

            // shut off the threads
            ThreadInfo.EndRenderThread = true;
            ThreadInfo.EndSimThread = true;

             // wait for the threads to end
            ::WaitForMultipleObjects(2,hThread,true,200); 
        }	

        CString FileName = FileDialog.GetPathName();
		SDisplayGraph.FileSaveGraphAscii(FileName);
    }

	
}

void CChildView::OnGraphoptionsLoaddefaultasciigraph() 
{
	GLoadGraphAscii();
	
}

void CChildView::OnTogglealttexture() 
{
	#ifdef ENABLEDIRECTX 
        DirectX.RCToggleAltTexture();
	#endif
	
}
