// WheelchairDlg.cpp : implementation file

/*! \file WheelchairDlg.cpp
	\brief CWheelchairDlg class implementation.
*/

/* July 2011
Modifications made by Radhika for implementation of Shared Control 
are explicity mentioned with comments labelled "radhika"
*/

#include "stdafx.h"
#include "WheelchairDlg.h"




#ifdef _DEBUG
#define new DEBUG_NEW
#endif


//! \name Dialog sections
//@{
#define CDS_SERVER 1
#define CDS_ROBOT  2
#define CDS_CONTROL 4
#define CDS_INFO   8
#define CDS_LOG    16
//@}




/*************************************************************************/
// CAboutDlg dialog used for App About
// Currently, we do not display the About box. This is just a placeholder.

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()

//! Generates the C++ code necessary for a dynamic CObject-derived class with run-time access to the class name and position within the hierarchy. (MSDN)
IMPLEMENT_DYNAMIC(CWheelchairDlg, CDialog);





/**************************************************************************/
// CWheelchairDlg dialog

//! Class Constructor
/*! \param pParent pointer to parent application
Performs default MFC initialisation. All non-GUI attributes are also initialised here. */
CWheelchairDlg::CWheelchairDlg(CWheelchairApp* pParent)
	: CDialog(CWheelchairDlg::IDD)
	, m_radioControl(0)
	, m_logType(0)
	, m_model(_T(""))
	, m_host(_T(""))
	, m_map(_T(""))
	, m_tag(_T(""))
	, m_logstr(_T(""))
	, m_strArTags(NULL)
	, m_strArPoses(NULL)
	, m_strArRots(NULL)
	, msgCounter(0)
	, yCursor(0)
	, xCursor(0)
	, xVelAvg(0)
	, yVelAvg(0)
{
	m_pMainApp = pParent;
	
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
//!Destructor
CWheelchairDlg::~CWheelchairDlg()
{
	if (m_strArTags!=NULL)
		delete[] m_strArTags;
	if (m_strArPoses!=NULL)
		delete[] m_strArPoses;
	if (m_strArRots!=NULL)
		delete[] m_strArRots;
}

//! DDX/DDV Support. Exchanges data between GUI elemants and attributes that control them.
void CWheelchairDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Radio(pDX, IDC_KBRDMOUSE, m_radioControl);
	DDV_MinMaxInt(pDX, m_radioControl, 0, 1);
	DDX_Radio(pDX, IDC_FILELOG, m_logType);
	DDV_MinMaxInt(pDX, m_logType, 0, 1);
	DDX_CBString(pDX, IDC_comboModel, m_model);
	DDX_Text(pDX, IDC_editHost, m_host);
	DDX_Control(pDX, IDC_START, m_cStart);
	DDX_Control(pDX, IDC_SETTINGS, m_cSettings);
	DDX_Control(pDX, IDC_SHOW, m_cShow);
	DDX_Control(pDX, IDC_SPAWN, m_cSpawn);
	DDX_CBString(pDX, IDC_COMBO_TAG, m_tag);
	DDX_Text(pDX, IDC_TEXT_POS, m_position);
	DDX_Text(pDX, IDC_FPS, m_fps);
	DDX_Check(pDX, IDC_CHECK1, m_startUT);
	DDX_Check(pDX, IDC_CHECK2, m_startSimWnd);
	DDX_Check(pDX, IDC_SHAREDCONTROL, m_startSharedCtrl); //radhika
	DDX_CBString(pDX, IDC_COMBO_MAP, m_map);
	DDX_Text(pDX, IDC_LOG, m_logstr);
}

BEGIN_MESSAGE_MAP(CWheelchairDlg, CDialog)
	ON_WM_SYSCOMMAND()
	ON_WM_CREATE() 
	ON_WM_CLOSE()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_START, OnStart)
	ON_BN_CLICKED(IDOK, OnOk)
	ON_BN_CLICKED(IDC_SHOW, OnShow)
	ON_BN_CLICKED(IDC_SPAWN, &CWheelchairDlg::OnSpawn)
	ON_BN_CLICKED(IDC_CONTROL, &CWheelchairDlg::OnControl)
	ON_BN_CLICKED(IDC_CLEAR, &CWheelchairDlg::OnClear)
	ON_BN_CLICKED(IDC_SAVELOG, &CWheelchairDlg::OnSaveLog)
	ON_BN_CLICKED(IDC_SAVEIMG, &CWheelchairDlg::Saveimg)
	ON_BN_CLICKED(IDC_SETTINGS, &CWheelchairDlg::OnOpenSettings)
	ON_BN_CLICKED(IDC_CONFIG, &CWheelchairDlg::OnOpenConfiguration)
	ON_BN_CLICKED(IDC_BTN_READ, &CWheelchairDlg::OnRead)
	ON_CBN_SELCHANGE(IDC_COMBO_TAG, &CWheelchairDlg::OnChangeStartPose)
	ON_WM_TIMER()
END_MESSAGE_MAP()


//! Initialises GUI elements.
BOOL CWheelchairDlg::OnInitDialog()
{
	CDialog::OnInitDialog(); //! Calls base-class function first.

	/*************************************************************
	 * This block is from the class wizard. Currently not needed *
	 * as no "About..." box is used                              *
	 *************************************************************/
	/*
	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	} */

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	

	
	/**********************
	 * GUI Initialisation *
	 **********************/
	m_startUT = TRUE;
	m_startSimWnd = TRUE;
	m_startSharedCtrl = FALSE; //radhika
	m_fps = 0.0f;
	m_radioControl = 0;
	m_logType = 0;
	m_Control = false;
	
	// Read in default values from configuration file:
	CAppConfig::getProperty("DefaultMap", m_map);
	CAppConfig::getProperty("DefaultModel", m_model);
	CAppConfig::getProperty("DefaultHost", m_host);
	//! The dafault map, model and host are read from the config file. 
	
	CString path;
	CAppConfig::getProperty("UTPath", path);
	path.Append("\\Maps\0");
	// Fill the combo box with all .ut2 files from the specified directory
	CHAR cpath[512] ;
	strcpy_s(cpath,path);
	DlgDirListComboBox(cpath, IDC_COMBO_MAP, 0, DDL_READWRITE);

	UpdateData(FALSE);
	AddToLog(BEGIN_LOG, "");


	switch(m_pMainApp->m_CtrlDev){
	case 1:
		RegisterJoystick();
		break;
	case 2:
		RegisterRawInput();
		break;
	}


	PostMessage(DM_SETDEFID,(WPARAM)IDC_START,0);

	return TRUE;  // return TRUE  unless you set the focus to a control
}

// This function was created by the wizard. It lets the (not used) AboutDlg process System Commands.
/*
void CWheelchairDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}
*/
// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

//! Called when Windows or an applications makes request to (re)paint (part of) the window.
/*! This function comes from the MFC Wizard. For now it has no use as the minimize button is diabled. */
void CWheelchairDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

//! The system calls this function to obtain the cursor to display while the user drags the minimized window.
//*! This function was generated by the MFC Wizard.*/
HCURSOR CWheelchairDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

//! Evoked when the start button is pressed. Starts (or stops) the UT2004 server and/or the simulation window.
void CWheelchairDlg::OnStart()
{
	UpdateData(TRUE); // Retrieve data from GUI.

	CString tmp;
	GetDlgItemText(IDC_START, tmp);
	/* Since the text changes from "start" to "stop" and back everytime the
	 * button is clicked, the block below checks what the current text is, 
	 * and accordingly either starts or stops the server and/or the simulation
	 * window (depending on the state of the checkboxes
	 */
	if (tmp != "Start") {
		/* Means that either the server or the simulation window is running 
		 * and we need to stop them. */

		// Prevent new frames being acquired.
		m_pMainApp->StopTimer(); 
		// Reset buffers and close socket.
		m_pMainApp->CloseConnection();
		// Close simulation window.
		m_pMainApp->StopSimWnd();
		// close UT Client
		m_pMainApp->CloseUT();	
		//Change the button text
		tmp = "Start";
		SetDlgItemText(IDC_START, tmp);
		//disable the control group of controls
		EnableSettings(CDS_ROBOT | CDS_CONTROL, false);	
	} else {
		if (m_startUT) { //this is the checkbox for the server
			if (!m_pMainApp->LoadUT(m_map))
				return;			// Error dialog is displayed in LoadUT. Nothing to do here.

			// Set the size of the UT2004 window
			m_pMainApp->ShowUT();
		}	

		//Change the button text
		tmp = "Stop";
		SetDlgItemText(IDC_START, tmp);
		if (m_startUT){
			m_pMainApp->Connect(m_host);
			// PopulateStartPose();
		}
		if (m_startSimWnd) {
			m_pMainApp->StartSimWnd();
			if (m_startUT) {
				// starts the timer. Only makes sense if both UT and SimWnd are running.
				m_pMainApp->StartTimer();
				//! This is where the timer is started. The timer frequncy is determined by the FPS value in configuration file.
				// If we got here means we're testing - starting the sim window, but not UT2004
			} else {
				m_pMainApp->TestSimWnd();
			}
		}
		EnableSettings(CDS_ROBOT, true); // enable the robot control group of controls

	}
	
	UpdateData(false); // update the GUI 
	
	PostMessage(DM_SETDEFID,(WPARAM)IDC_SPAWN,0);
	//PostMessage(WM_NEXTDLGCTL, (WPARAM) IDC_comboModel,TRUE);

	::SetFocus(::GetDlgItem(m_hWnd,IDC_comboModel)); 

	SetForegroundWindow(); // the UT2004 window has the focus. Give it back to the main app.
	
	return;
}

//! Enables and disables groups of controls.
/*! \param control a DWORD control group identificator
	\param enable enables if TRUE, disables if FALSE */
void CWheelchairDlg::EnableSettings(DWORD control, bool enable)
{
	if ((CDS_ROBOT & control) == CDS_ROBOT) {
		GetDlgItem(IDC_comboModel)->EnableWindow(enable);
		GetDlgItem(IDC_comboPosition)->EnableWindow(enable);
		GetDlgItem(IDC_SPAWN)->EnableWindow(enable);
    }
	if ((CDS_CONTROL & control) == CDS_CONTROL) {
		GetDlgItem(IDC_SHOW)->EnableWindow(enable);
		GetDlgItem(IDC_KBRDMOUSE)->EnableWindow(enable);
		GetDlgItem(IDC_JOYSTICK)->EnableWindow(enable);
		GetDlgItem(IDC_CONTROL)->EnableWindow(enable);
		GetDlgItem(IDC_SHAREDCONTROL)->EnableWindow(enable);//radhika for shared control
	}
	if ((IDC_SETTINGS & control) == IDC_SETTINGS) {
		GetDlgItem(IDC_SETTINGS)->EnableWindow(enable);
	}
}

//! Evoked when closing the GUI
void CWheelchairDlg::OnOk()
{
	if (m_strArTags != NULL){
		delete[] m_strArTags;
		m_strArTags = NULL;
	}
	if (m_strArPoses != NULL){
		delete[] m_strArPoses;
		m_strArPoses = NULL;
	}
	if (m_strArRots != NULL){
		delete[] m_strArRots;
		m_strArRots = NULL;
	}
	CDialog::OnOK(); 
}

//! Evoked when the HideUT button is clicked. Hides or restores the UT2004 window.
/*! This function is adopted from the SimpleUI sample in USARSim*/
void CWheelchairDlg::OnShow()
{
	CString str;
	m_cShow.GetWindowText(str); //get the current button text
	if (str=="Hide UT") {
		m_pMainApp->HideUT();
		str = "Show UT";	//change the button string
	}
	else {
		//restore UT2004 in the visible area
		m_pMainApp->ShowUT();
		str = "Hide UT";	//change the button string
	}
	m_cShow.SetWindowText(str);	//display the new button string
}

//! Evoked when the "Spawn" button is pressed. Places a vehicle in the game.
/*! This function is adopted from the SimpleUI sample in USARSim*/
void CWheelchairDlg::OnSpawn()
{
	 //retrieve data from GUI.
	
	CString str;
	m_cSpawn.GetWindowText(str); //get the current button text
	if (str=="Spawn") {
		UpdateData(true);
		m_pMainApp->Spawn(m_model, m_position, m_rotation);
		
		xCursor = 0;
		yCursor = 0;
		EnableSettings(CDS_CONTROL, true);	//enable the robot control group of controls

		PostMessage(DM_SETDEFID,(WPARAM)IDC_START,0);
		str = "Remove";
	} else {
		m_pMainApp->CloseConnection();
		m_pMainApp->Connect(m_host);
		str  = "Spawn";
	}
	m_cSpawn.SetWindowText(str);
}

//!Evoked when the "Control" Button is pressed. 
/*! Starts capturing keyboard and mouse. Released with right-click.*/
void CWheelchairDlg::OnControl()
{
	CString tmp;
	UpdateData(true); // retrieve data from GUI

	if (!m_Control) {
		m_Control = true;

		m_pMainApp->OnSharedControl(m_startSharedCtrl); //radhika

		//start capturing
		SetCapture();
		//change buton text
		tmp = "RClick2STOP";
		SetDlgItemText(IDC_CONTROL, tmp);
	} else {
		//release capture
		ReleaseCapture();
		m_Control = false;
		//change button text
		tmp = "Control";
		SetDlgItemText(IDC_CONTROL, tmp);
	}
}
//! If "Control" is on, this redirects keyboard and mouse messages to KMove() function.
/*! This function is adopted from the Usar_UI sample in USARSim*/
BOOL CWheelchairDlg::PreTranslateMessage(MSG* pMsg) 
{
	int processed; // indicates if variable was processed by KMove (i.e. was one of the 
				// steering keys. If not, the message is passed on for normal processing

	// only process messages if m_Control is on
	if (!m_Control) return CDialog::PreTranslateMessage(pMsg);
	// pass keyboard messages to KMove()
	switch(pMsg->message) {
		case WM_KEYDOWN:
			processed = m_pMainApp->KMove(pMsg->wParam, pMsg->lParam, 1);
			break;
		case WM_KEYUP:
			processed = m_pMainApp->KMove(pMsg->wParam, pMsg->lParam, 0);
			break;
		default:
			processed = 0;
	}
	if (processed) {
		return true;
	}
	else {
		return CDialog::PreTranslateMessage(pMsg);
	}
}


//! Overriden function. Interpets Joystick messages.
/*! This function is adopted from the Usar_UI sample in USARSim*/
LRESULT CWheelchairDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
{
    switch(message)
    {	
		case WM_INPUT: 
		{
			
			
			UINT dwSize = m_pMainApp->m_RawInputDataSize;
			
			//GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, 
			//                   sizeof(RAWINPUTHEADER));
			LPBYTE lpb = new BYTE[dwSize];
			if (lpb == NULL) return 0;
		
			if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, 
				 sizeof(RAWINPUTHEADER)) != dwSize )
				 OutputDebugString (TEXT("GetRawInputData doesn't return correct size !\n")); 

			RAWINPUT* raw = (RAWINPUT*)lpb;
	
			if (raw->header.dwType == RIM_TYPEMOUSE) 
			{
			
				HANDLE hDevice = raw->header.hDevice;
				GetRawInputDeviceInfo(hDevice,RIDI_DEVICENAME,NULL, &dwSize);
				char* szDevName = (char*) malloc(sizeof(char) * dwSize);
				GetRawInputDeviceInfo(hDevice,RIDI_DEVICENAME,szDevName, &dwSize);
				if(strcmp(szDevName, m_pMainApp->m_Device.GetString()) == 0) {
					//Beep( 750, 5 );
					switch(m_pMainApp->m_CtrlMode) {
						case REL_CTRL:
							{
							SetTimer(IDT_RAWINPUTSTOPPED,200,NULL);
							xVelAvg+=raw->data.mouse.lLastX;
							yVelAvg+=raw->data.mouse.lLastY;
							msgCounter++;
							if (msgCounter ==4){ //4
								//TRACE2("Input: %f, %f\r\n",xVelAvg, yVelAvg);
								m_pMainApp->MMove(xVelAvg/5, yVelAvg/5,6.25 );//1.14
		
								//m_pMainApp->MMove(raw->data.mouse.lLastX*4, raw->data.mouse.lLastY*4,1.14);
								msgCounter = 0;
								xVelAvg = 0;
								yVelAvg = 0;
							}
							//	RID_DEVICE_INFO* devinf = new(RID_DEVICE_INFO);
							//	devinf->cbSize = sizeof(RID_DEVICE_INFO);
							//	UINT disize = sizeof(RID_DEVICE_INFO);
							//	GetRawInputDeviceInfo(dev,RIDI_DEVICEINFO,devinf,&disize);
							//	delete devinf;
							break;
						}
						case ABS_CTRL:
						{
							xCursor+=raw->data.mouse.lLastX / 10.0;
							yCursor+=raw->data.mouse.lLastY / 10.0;
							xCursor=xCursor>20?20:xCursor;
							yCursor=yCursor>20?20:yCursor;
							xCursor=xCursor<-20?-20:xCursor;
							yCursor=yCursor<-20?-20:yCursor;
							msgCounter++;
							if (msgCounter ==4 || clock() - m_lastClock > 0.2 * CLOCKS_PER_SEC){
								m_pMainApp->MMove(xCursor, yCursor);
								msgCounter = 0;
								m_lastClock = clock();
							}
							
							break;
						}
					}
				}
				free(szDevName);
			}
			delete lpb;
			return 0;
		} 
        case MM_JOY1MOVE :
			m_pMainApp->JMove();
            break;
		case WM_RBUTTONDOWN:
			if (m_Control) 
				OnControl();
			break;
		case WM_ACTIVATE:
			if (LOWORD(wParam)==WA_INACTIVE)
				ReleaseCapture();
			break;
        case WM_DESTROY:
            /* We're shutting down. Release capture on the joystick, 
             * make sure any sounds that are playing are stopped.
             */
            if (m_bHasJoystick) joyReleaseCapture(JOYSTICKID1);
            PostQuitMessage(0);
            break;
	}
	return CDialog::WindowProc(message, wParam, lParam);

}


//! Calls CWheelchairApp::ProcessStartPoses and populates the GUI
bool CWheelchairDlg::PopulateStartPose(CString msg)
{

	UpdateData(true);

	int n_poses = 0;
	if (!m_pMainApp->ProcessStartPoses(msg, n_poses, m_strArTags, m_strArPoses, m_strArRots)){
		AddToLog(ERRORMSG, "Processing startposes failed.");
		return false;
	}
	

	bool first = true;

	SendDlgItemMessage(IDC_comboPosition, CB_RESETCONTENT, 0, 0);

	for (int i = 0; i < n_poses; i++) {

		SendDlgItemMessage(IDC_comboPosition, CB_INSERTSTRING, i, (LPARAM) (LPCSTR) m_strArTags[i]);
		if (first) {
			m_tag = m_strArTags[i];
			m_position = m_strArPoses[i];
			m_rotation = m_strArRots[i];
			first = false;
		}
	}
	UpdateData(false);
	return true;
}
//! Evoked when selected position is changed in the dropdown control
void CWheelchairDlg::OnChangeStartPose( ){
	UpdateData(true);
	//find out which item is selected
	int index = 0;
	//index = (int) ::SendMessage(GetDlgItem(IDC_COMBO_TAG)->m_hWnd, CB_GETCURSEL,0,0); 
	index = (int) SendDlgItemMessage(IDC_comboPosition,CB_GETCURSEL,0,0);
	TRACE1("Index = %d\r\n",index);
	TRACE3("%s %s %s\r\n",m_strArTags[0], m_strArTags[1], m_strArTags[2]);
	//synchronise with the postion text
	m_position = m_strArPoses[index];
	m_rotation = m_strArRots[index];
	m_tag = m_strArTags[index];
	UpdateData(false);
}

//! Provides logging capability.
/*! \param type indicates type of message and determines how it is treated
	\param logmsg the log message
	\sa See #LogMsgType for currently supported types and the actions taken for each type.
*/
void CWheelchairDlg::AddToLog(LogMsgType type, CString logmsg)
{	
	UpdateData(true);
	GetLocalTime(&m_systime);
	switch (type) {
		case INCOMING:
			logmsg.Format("%u:%u:%u:%u > %s",  
				m_systime.wHour, m_systime.wMinute, 
				m_systime.wSecond, m_systime.wMilliseconds,
				logmsg);
			break;
		case OUTGOING:
			logmsg.Format("%u:%u:%u:%u < %s",  
				m_systime.wHour, m_systime.wMinute, 
				m_systime.wSecond, m_systime.wMilliseconds,
				logmsg);
			break;
		case INFO:
			logmsg.Insert(0, "INFO: ");
			break;
		case ERRORMSG:
			logmsg.Insert(0, "ERROR: ");
			break;
		case BEGIN_LOG:
			CTime theTime = CTime::GetCurrentTime();
			CString logbeg("\r\n========================================");
			logbeg.Append("========================================\r\n");
			logbeg.Append(theTime.Format( "%c" ));
			logbeg.Append(" -- Wheelchair Simulation log started.\r\n");
			if (logmsg.GetLength()!=0){
				logbeg.Append(logmsg);
				logbeg.Append("\r\n");
			}
			logbeg.Append("\r\n========================================");
			logbeg.Append("========================================");
			logmsg = logbeg;
			break;
	}
	logmsg.Append("\r\n");
	if (m_logType == 1) {
		m_logstr.Append(logmsg);
	}
	else {
		
		m_pMainApp->AppendToLog(logmsg);
	}

	//if (SendDlgItemMessage(IDC_LOG, EM_GETLINECOUNT, 0, 0) > 8) 
//		LRESULT res = SendDlgItemMessage(IDC_LOG, EM_LINESCROLL, 0, 1);
	
	UpdateData(false);
	//Scroll to the bottom
	CEdit* log = (CEdit*)GetDlgItem(IDC_LOG);
	int n_lines = log->GetLineCount() ;
	log->LineScroll(n_lines); // the current line is always zero

}
//! Evoked upon pressing the "Clear" button. Clears the log view.
void CWheelchairDlg::OnClear()
{
	UpdateData(true);
	m_logstr = "";		//empty the log
	UpdateData(false);	//update the GUI
}

//! Evoked upon pressing the "Save" button. Saves the log to file.
void CWheelchairDlg::OnSaveLog()
{
	UpdateData(true);
	m_pMainApp->SaveLog(m_logstr);
}

//! Evoked when the "Save Img" button is pressed. Saves the current frame from UT2004. \sa FrameData_t
void CWheelchairDlg::Saveimg()
{
	m_pMainApp->SaveImg();	
}

//! Evoked upon pressing "Settings". Shows the SPI Settings dialog. 
void CWheelchairDlg::OnOpenSettings()
{
	m_pMainApp->m_bSPISettingsChange = true;
	m_pMainApp->OpenSettings();
}
//! Evoked upon pressing "Configuration". Shows the Configuration dialog. 
void CWheelchairDlg::OnOpenConfiguration()
{
	m_pMainApp->OpenConfiguration();
}
//! Sets the FPS edit control
void CWheelchairDlg::setFPS(float fps)
{
	UpdateData(true);
	m_fps = fps;
	UpdateData(false);
}

//! Used to reset the dialog after lost connection.
void CWheelchairDlg::ConnectionLost(void)
{	
	UpdateData(true);
	// Set the Start/Stop button back to "Start"
	SetDlgItemText(IDC_START, "Start");
	// Disable controls as appropriate
	EnableSettings(CDS_ROBOT | CDS_CONTROL, false);
	m_Control = false;
	UpdateData(false);
}

//! Sends a "stop" message to the robot when the IDT_RAWINPUTSTOPPED timer lapses. 
/** This is a fix for the mouse replacement joystick not sending a message when it stops moving. 
	The IDT_RAWINPUTTIMER's period is 200ms and it lapses only once (i.e. it is killed here). */
void CWheelchairDlg::OnTimer(UINT_PTR nIDEvent){
	switch(nIDEvent){
		case IDT_RAWINPUTSTOPPED:
			TRACE0("Raw Input Stopped");
			m_pMainApp->MMove(0,0); // send a STOP message
			KillTimer(nIDEvent); 
			break;
	}
}

//! Sets Joystick capture.
bool CWheelchairDlg::RegisterJoystick(){
	/* Capture the joystick. If this fails, beep and display
     * error.
     */
    if(joySetCapture(m_hWnd, JOYSTICKID1, 100, TRUE))
    {
        MessageBeep(MB_ICONEXCLAMATION);
        MessageBox("Couldn't capture joystick", NULL, MB_OK | MB_ICONEXCLAMATION);
        m_bHasJoystick = false;
    }
    else m_bHasJoystick = true;

	return m_bHasJoystick;
}
//! Registers the dialog as an input sink for mouse RawInput messages.
bool CWheelchairDlg::RegisterRawInput(){
	/**************************
	 * Raw Input Registration *
	 **************************/

	RAWINPUTDEVICE Rid[1];
	Rid[0].usUsagePage = 0x01; 
	Rid[0].usUsage = 0x02; // adds HID mouse 
	Rid[0].dwFlags = RIDEV_INPUTSINK;   // will recieve input even if not in focus
	Rid[0].hwndTarget = m_hWnd;

	if (RegisterRawInputDevices(Rid, 1, sizeof (Rid [0])) == FALSE) {
		MessageBox("Registering Raw Input device failed.","Error",MB_OK|MB_ICONSTOP);
		return false;
	}
	return true;
	
}
//! Overriden function. Opens the configuration dialog on start, if configured.
/** The Configuration Dialog (CConfigurationDlg) is open if the application is ran
	for the first time, or the configuration option "ShowConfig" is set to true.
	\sa \ref CWheelchairApp::m_bFirstRun, \ref CWheelchairApp::m_bShowConfig */
int CWheelchairDlg::OnCreate(LPCREATESTRUCT lpRes){
	int res = CDialog::OnCreate(lpRes);

	if (m_pMainApp->m_bFirstRun){
		MessageBox("This seems to be the first time you run this application. Please take a while to review the configuration.","Welcome",MB_ICONINFORMATION);
		m_pMainApp->OpenConfiguration();
		CAppConfig::saveProperty("FirstRun", false);
	}
	else if (m_pMainApp->m_bShowConfig)
		m_pMainApp->OpenConfiguration();

	return res;


}
void CWheelchairDlg::OnRead(){
	TRACE0("+ + + + + + + + + + + + + + + + + + + + +");
	m_pMainApp->ProcessMessage(true);
}