//---------------------------------
// Name:			MainDialog.cpp
// Purpose:			Main dialog of firmware updater application
// Toolchain(s):	Microsoft Visual C++
// Creation date:	26-May-06
// Created by:		JJo
//---------------------------------

//---------------------------------
// Includes

#include "MainDialog.h"

//---------------------------------
// Message map
BEGIN_MESSAGE_MAP(MainDialog, CDialog)
	ON_BN_CLICKED(IDC_EXIT, OnExitClicked)
	ON_BN_CLICKED(IDC_BROWSE, OnBrowseClicked)
	ON_BN_CLICKED(IDC_UPGRADE, OnUpgradeClicked)
	ON_WM_CLOSE()
END_MESSAGE_MAP()

//---------------------------------
// Class

/**
 * Name:		MainDialog
 * Purpose:		Constructor for the MainDialog class
 */
MainDialog::MainDialog() {

	// Create MainDialog window
	this->Create(IDD_MAINDIALOG, NULL);
}

/**
 * Name:		~MainDialog
 * Purpose:		Destructor for the MainDialog class
 */
MainDialog::~MainDialog() {}

/**
 * Name:		OnExitClicked
 * Purpose:		Handler for single clicks on the exit button
 */
void MainDialog::OnExitClicked() {

	this->DestroyWindow();
}

/**
 * Name:		OnClose
 * Purpose:		Handle window close
 */
void MainDialog::OnClose() {

	this->DestroyWindow();
}

/**
 * Name:		OnBrowseClicked
 * Purpose:		Handles clicks on the browse button
 */
void MainDialog::OnBrowseClicked() {

	// Local variables
	CFileDialog fileDialog(TRUE,
						   NULL,
						   NULL,
						   OFN_HIDEREADONLY | OFN_PATHMUSTEXIST,
						   "Binary files (*.bin)|*.bin|Firmware files (*.frw)|*.frw|All files (*.*)|*.*||",
						   this);

	// Open file chooser window
	if (fileDialog.DoModal() == IDOK) {

		// Add selected file to combobox
		this->m_pFilename = (CComboBox *) this->GetDlgItem(IDC_FILENAME);
		this->m_pFilename->InsertString(0, fileDialog.GetFileName());
		this->m_pFilename->SetCurSel(0);
		this->m_pFilename->EnableWindow(TRUE);

		CString * path = new CString(fileDialog.GetPathName());
		this->m_pFilename->SetItemDataPtr(0, (void *) (LPCTSTR (*path)));

		// Enable upgrade button
		this->m_pUpgrade = (CButton *) this->GetDlgItem(IDC_UPGRADE);
		this->m_pUpgrade->EnableWindow(TRUE);
	}
}

/**
 * Name:		Upgrade
 * Purpose:		Sends the new firmware to the target device
 * Input:
 *	- Pointer to the MainDialog instance
 */
UINT MainDialog::Upgrade(LPVOID pParam) {

	// Local variables
	MainDialog * pMainDialog = (MainDialog *) pParam;
	Configuration configuration;
	CString filename;
	CString text;
	char * pData;
	unsigned long size;
	CFile * pFile;
	

	// Setup configuration
	// File
	try {

		pMainDialog->m_pFilename = (CComboBox *) pMainDialog->GetDlgItem(IDC_FILENAME);
		filename = (char *) pMainDialog->m_pFilename->GetItemDataPtr(pMainDialog->m_pFilename->GetCurSel());
		configuration.SetFile(filename);
	}
	catch (CFileException * e) {

		pMainDialog->m_pProgressDialog->Finish();
		e->ReportError();
		return 0;
	}

	// Media
	if (pMainDialog->SendDlgItemMessage(IDC_SERIALPORT, BM_GETCHECK, 0, 0) == BST_CHECKED) {

		CString port;
		unsigned long baudrate;
		unsigned char parity;
		unsigned char stopBits;

		pMainDialog->m_pPort = (CComboBox *) pMainDialog->GetDlgItem(IDC_PORT);
		pMainDialog->m_pPort->GetWindowText(port);

		pMainDialog->m_pBaudrate = (CComboBox *) pMainDialog->GetDlgItem(IDC_BAUDRATE);
		pMainDialog->m_pBaudrate->GetWindowText(text);
		baudrate = atoi(text.Left(text.GetLength()-6));

		pMainDialog->m_pParity = (CComboBox *) pMainDialog->GetDlgItem(IDC_PARITY);
		pMainDialog->m_pParity->GetWindowText(text);
		
		if (text == "No parity") {
			
			parity = NOPARITY;
		}
		else if (text == "Even parity") {

			parity = EVENPARITY;
		}
		else if (text == "Odd parity") {

			parity = ODDPARITY;
		}
		else if (text == "Mark parity") {

			parity = MARKPARITY;
		}
		else {

			parity = SPACEPARITY;
		}

		pMainDialog->m_pStopBits = (CComboBox *) pMainDialog->GetDlgItem(IDC_STOPBITS);
		pMainDialog->m_pStopBits->GetWindowText(text);

		if (text == "1 stop bit") {

			stopBits = ONESTOPBIT;
		}
		else if (text == "1.5 stop bits") {

			stopBits = ONE5STOPBITS;
		}
		else {

			stopBits = TWOSTOPBITS;
		}

		try {
			configuration.SetSerialPort(port, baudrate, parity, stopBits);
		}
		catch (CFileException * e) {

			pMainDialog->m_pProgressDialog->Finish();
			e->ReportError();
			return 0;
		}
	}

	// Protocol
	if (pMainDialog->SendDlgItemMessage(IDC_XONXOFF, BM_GETCHECK, 0, 0) == BST_CHECKED) {

		try {

			configuration.SetXonXoff();
		}
		catch (...) {

			pMainDialog->m_pProgressDialog->Finish();
			pMainDialog->MessageBox("Cannot initialize XON/XOFF protocol.", "Protocol error", MB_ICONERROR);
			return 0;
		}
	}

	try {

		// Retrieve file info & data
		pFile = configuration.GetFile();
		size = pFile->GetLength();
		pData = new char[size];
		pFile->Read(pData, size);

		// Setup progress bar
		pMainDialog->m_pProgressDialog->SetTitle("Upgrading ...");
		pMainDialog->m_pProgressDialog->SetRange(0, 20);
		pMainDialog->m_pProgressDialog->SetStep(1);

		// Send firmware
		configuration.GetCommunication()->Send(pData, size, pMainDialog->m_pProgressDialog, size/20);

		// Cleanup
		delete pData;
	}
	catch (CException * e) {

		pMainDialog->m_pProgressDialog->Finish();
		e->ReportError();
		e->Delete();
	}

	return 0;
}

/**
 * Name:		OnUpgradeClicked
 * Purpose:		Handles clicks on the upgrade button
 */
void MainDialog::OnUpgradeClicked() {

	try {

		// Display progress bar
		this->m_pProgressDialog =
			new ProgressDialog(this,
							   AfxBeginThread(MainDialog::Upgrade,
											 (LPVOID) this,
											 THREAD_PRIORITY_NORMAL,
											 0,
											 CREATE_SUSPENDED,
											 NULL));
		this->m_pProgressDialog->DoModal();

		delete this->m_pProgressDialog;
	}
	catch (CException * e) {

		e->ReportError();
		e->Delete();
	}
}

/**
 * Name:		OnInitDialog
 * Purpose:		Handles the initialization of the window
 */
BOOL MainDialog::OnInitDialog() {

	// Local variables
	CString name;
	HANDLE hPort;

	// Superclass initialization
	CDialog::OnInitDialog();
	
	// Retrieve controls handles
	this->m_pFilename = (CComboBox *) this->GetDlgItem(IDC_FILENAME);
	this->m_pUpgrade = (CButton *) this->GetDlgItem(IDC_UPGRADE);
	this->m_pSerialPort = (CButton *) this->GetDlgItem(IDC_SERIALPORT);
	this->m_pPort = (CComboBox *) this->GetDlgItem(IDC_PORT);
	this->m_pBaudrate = (CComboBox *) this->GetDlgItem(IDC_BAUDRATE);
	this->m_pParity = (CComboBox *) this->GetDlgItem(IDC_PARITY);
	this->m_pStopBits = (CComboBox *) this->GetDlgItem(IDC_STOPBITS);
	this->m_pXonXoff = (CButton *) this->GetDlgItem(IDC_XONXOFF);

	// Setup controls
	this->m_pFilename->EnableWindow(FALSE);
	this->m_pUpgrade->EnableWindow(FALSE);
	this->m_pSerialPort->SetCheck(1);
	this->m_pBaudrate->SetCurSel(9);
	this->m_pParity->SetCurSel(2);
	this->m_pStopBits->SetCurSel(0);
	this->m_pXonXoff->SetCheck(1);

	// Add COM ports to combobox
	for (unsigned int i=0; i < 128; i++) {

		name.Format("COM%d", i);
		hPort = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);

		if (hPort == INVALID_HANDLE_VALUE) {

			if (GetLastError() != ERROR_FILE_NOT_FOUND) {

				this->m_pPort->AddString(name);
			}
		}
		else {

			this->m_pPort->AddString(name);
			CloseHandle(hPort);
		}
	}
	this->m_pPort->SetCurSel(0);

	return TRUE;
}

/**
 * Name:		OnSerialPortClicked
 * Purpose:		Handles selection of the serial port radio button
 */
afx_msg void MainDialog::OnSerialPortClicked() {

	// Enable protocol options
	this->SendDlgItemMessage(IDC_PORT, WM_ENABLE, TRUE, 0);
	this->SendDlgItemMessage(IDC_BAUDRATE, WM_ENABLE, TRUE, 0);
	this->SendDlgItemMessage(IDC_PARITY, WM_ENABLE, TRUE, 0);
	this->SendDlgItemMessage(IDC_STOPBITS, WM_ENABLE, TRUE, 0);

	// Disable other protocol options
}

/**
 * Name:		OnXonXoffClicked
 * Purpose:		Handles selection of XON/XOFF radio button
 */
void MainDialog::OnXonXoffClicked() {

	// Disable other protocol options
}