// MenuHandler.cpp : implementation file
//

#include "stdafx.h"
#include "resource.h"
#include "MachDevice.h"
#include "MenuHandler.h"
#include ".\menuhandler.h"
#include "Mach4View.h"
#include "TrajectoryControl.h"
#include "Mach4View.h"
#include "Engine.h"
#include "rs274ngc.h"
#include "math.h"
#include "probeconfig.h"
#include "OkayToMove.h"
#include "XMLProfile.h"
 

extern EngraveThread* pThread;

extern CXMLProfile *DevProf;
extern EngraveSetup *monitor;

 
extern TrajectoryControl *MainPlanner; //used for most planner funcitons and program control 
extern CMach4View *MachView;   //used for most framework and configuration calls. 
extern TrajBuffer *Engine;     //Ring0 memory for printer port control and other device syncronisation
extern setup *_setup;          //Trajectory planners setup block. Always in effect

extern VoidLPCSTR         Code;         // void    Code( "G0X10Y10" );
extern OneShort           DoButton;     // void DoButton( code )
extern DoubleShort        GetDRO;       // Double GetDRO( code )
extern VoidShortDouble  SetDRO;         // void   SetDRO( short code, double value);
extern BoolShort          GetLED;       // bool   GetLED( short code );
extern VoidShortBool      SetLED;       //SetLED Fucntion
 
 
extern double m_YStepOver;
extern double m_length;
extern double m_height;
extern double m_feedrate;
extern double m_ImageX;
extern double m_ImageY;
extern double m_StepsX;
extern double m_StepsY;
extern int m_TriggerLen;
double estartx;
double estarty;
bool   edir;

EngraveImage import;

// MenuHandler

IMPLEMENT_DYNAMIC(MenuHandler, CWnd)
MenuHandler::MenuHandler()
{
	RangeStart = -1;
	SEQUENCE = SEQNONE; //no sequence in effect..
	 
}

MenuHandler::~MenuHandler()
{
}


BEGIN_MESSAGE_MAP(MenuHandler, CWnd)

  
 
END_MESSAGE_MAP()


int FindMenuItem(CMenu* Menu, LPCTSTR MenuString)
{
	ASSERT(Menu);
	ASSERT(::IsMenu(Menu->GetSafeHmenu()));

	int count = Menu->GetMenuItemCount();
	for (int i = 0; i < count; i++)
	{
		CString str;
		if (Menu->GetMenuString(i, str, MF_BYPOSITION) &&
			(strcmp(str, MenuString) == 0))
			return i;
	}

	return -1;
}



// MenuHandler message handlers
// Initialise and setup manu items for MAch3's menu control

void MenuHandler::InitMenus(void)
{

	if( RangeStart == -1 ) 
	{
		AfxMessageBox( " Error in Adding Menus " );
		return;
	}

	CFrameWnd *MachFrame = MachView->MachFrame;
	CMenu *menu = MachFrame->GetMenu();
	HMENU hSubmenu = CreatePopupMenu();
    //here we can add menu items to MAch3's menu..
	InsertMenu ( hSubmenu, 0, MF_BYPOSITION, RangeStart , _T("&Engrave Photo") );
	
	//we can add as many as we want up to the amount we requested in the implementation file..
	//here we add the menu to the Mach3 menu..
	InsertMenu( menu->m_hMenu , -1 , MF_POPUP, (UINT_PTR) hSubmenu, _T("&Impact/Laser Engraving") );  //this adds the probing menu item. 
	 m_YStepOver = atof( DevProf->GetProfileString("Engraving", "YStepOver", ".1" ));
	 m_length = atof( DevProf->GetProfileString("Engraving", "Length" , "8.0" ));
	 m_height = atof( DevProf->GetProfileString("Engraving", "Width", "10.0" ));
	 m_feedrate = atof( DevProf->GetProfileString("Engraving",  "FeedRate", "100.0" ));
}

void MenuHandler::CheckMenu(int PointSearch, bool done)
{
  //dont need this for the photo engraver..
 
}

//Activate Fucntions based on menu item selection.

void MenuHandler::DoMenuItem(int ID)  
{

 if( SEQUENCE != SEQNONE )
 {
   AfxMessageBox( "Previous SEQ not yet complete. ");
   return;
 }
 int sw = ID - RangeStart;

	switch( sw )
	{
	case( 0 ):    //here we call the engraving run ..
		          Engrave();
		          break;
 	}
}
 
 

void MenuHandler::Sequencer(void)
{
	
 static bool inseq = false;	
 if( inseq ) return;
 inseq = true;

 CString temp,Block; 
 static double var1,var2,var3,var4;

 if( !MainPlanner->MovementDone ) { inseq = false; return; }

 if ( SEQUENCE != SEQNONE )
 {
	 Engine->DisplayLine = 0;
	 MainPlanner->Line = 0;
 }
 switch (SEQUENCE )
	{
	  case ( SEQNONE ) :inseq = false;	
						return; //no sequence in operation..
	  case ( SEQ_START) :if( Engine->State == STOP ) { inseq = false; return; }
		                SEQUENCE = SEQ_WAITONLINE;
						SetMachError("Scanning Sequence Begins..");
						break;

      case( SEQ_WAITONLINE )://This stage will move, lin eby line till done.
		                FillLine();
						MoveNextLine();
		                break;
						
   	 
  }
 inseq = false;
}
void MenuHandler::FillLine()
{
 if( !MachView->m_PrinterOn ) 
 {
	 return;
 }
 int pos = 0;
 double PerPixel = ((double)m_TriggerLen) / m_ImageX; //amount of move per pixel..
 //get YLine position, shoudl be doign some morphing here..
 int ypos = (int)((estarty / m_height) * m_ImageY); 
 //clear the line.
 for( int x = 0; x < 32000; x++) MachView->Info.Time[x] = 0; //set the bits to zero.. not really required..

 for( int x = 1; x < m_ImageX; x++)
 {
    int pixel = ((int)(PerPixel * x)) - pos; //amount to add this pixel.. 
	int den;
	if( estartx == 0 )
		den = import.image->GetPixelGray( x, ypos);
	else
		den = import.image->GetPixelGray( m_ImageX - x , ypos); //reversed direction line data

	double per = den / 255.0; // what percentage of density from 0 - 1
	double greytot = 0;

    for( int y = 0; y < pixel; y++)
	{
      //so here we put a density through the series, adding to the pos position in the triggers..
	  int res = 0;
      greytot += ( per * pixel );
	  if( greytot >= pixel ) 
	  {
        res = 1;
		greytot -= pixel;
	  }
	  //now we need to fill the bits one at a time, so we need to iteratively fill 
	  //res with a 1 or a 0, in a density pattern reflecting the den variable from 0 - 255
	  SetInfoBit( pos++ , res);
	}
	if( pos >= 1024000) break;
 }
  Engine->DataOutByte = 0;
}

void MenuHandler::SetInfoBit( int pos , int state)
{
	int loc = pos / 32;
	int bit = pos % 32;
	if( loc >= 32000) 
		return;
	//get the current data
    int data = MachView->Info.Time[loc];
	if( state == 1 )
		 data = data | ( 1 << bit );
	else
	     data = data & ( 0xffffffff ^ ( 1 << bit));
	//set the updated data;
    MachView->Info.Time[loc] = data;

}


void MenuHandler::MoveNextLine()
{
   double x , y;
   // this will move line by line until the photo is done, then set SEQ to SEQNONE
	if( estarty < m_height)
	{
      if( estartx == 0 )
	  {
		  x = m_length;
	  }
	  else
	  {
		  x = 0;

	  }
      y = estarty + m_YStepOver;
	  estarty = y;
	  estartx = x;
	  CString line;
	  line.Format("G1 X%.4f F%.4f" ,x,m_feedrate);
	  Code( line );
	  line.Format("G1 Y%.4f" , y);
	  Code( line);
      MainPlanner->MovementDone = false;
	  return;
	}
	SEQUENCE = SEQNONE;
	SetMachError("Scanning Sequence Complete");
	Code("G0X0Y0 M5");
}

 

bool MenuHandler::OKtoStart(void)
{
	OkayToMove* start = new OkayToMove();
	start->DoModal();
	 bool result = start->m_IsOkayToMove;
	delete start;
    if( result ) return true;
	return false;
}

 

 
void MenuHandler::Engrave(void)
{

	if( !MachView->m_PrinterOn ) 
	{
		AfxMessageBox( "Printer Port operation only!");
		return;
	}
	if( abs( MainPlanner->XPosition) > .01 ||
							abs( MainPlanner->YPosition) > .01 )
						{
                            SEQUENCE = SEQNONE;
							AfxMessageBox( "X and Y Axis must be zeroed to proceed!");
							return;
						}
	if( MainPlanner->m_Loaded ) 
						{
                           SEQUENCE = SEQNONE;
							AfxMessageBox( "Please close current Gcode file before probing!");
							return;

						}
	 
	 //create and call a ProbeSetup thread..

	if( pThread != NULL ) 
	{
	  if( monitor != NULL ) return;
	  delete pThread;
	}
	pThread = new EngraveThread();
	pThread->CreateThread();
   
}
 
 
bool MenuHandler::Rest()
{ 
	if(Restcycles <= 0) return false;
	Restcycles--;
	return true;
}

void MenuHandler::SetMachError(CString Message)
{
	CString *err = &MainPlanner->LastError;
	if( err != NULL )
		*err = Message;

}