//---------------------------------
// Name:			Configuration.cpp
// Purpose:			Firmware updater configuration
// Toolchain(s):	Microsoft Visual C++
// Creation date:	26-May-06
// Created by:		JJo
//---------------------------------

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

#include "Configuration.h"

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

/**
 * Name:		Configuration
 * Purpose:		Constructor for the Configuration class
 */
Configuration::Configuration():
m_pMedia(NULL),
m_pCommunication(NULL),
m_pFirmware(NULL) {}

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

	if (this->m_pCommunication != NULL) {

		delete this->m_pCommunication;
	}

	if (this->m_pMedia != NULL) {

		delete this->m_pMedia;
	}

	if (this->m_pFirmware != NULL) {

		delete this->m_pFirmware;
	}
}

/**
 * Name:		SetSerial
 * Purpose:		Configure the firmware updater to use a serial port
 * Input(s):
 *	- Name of the port (COM1, COM2 ...)
 *  - Baud rate
 *  - Parity (NOPARITY, EVENPARITY, MARKPARITY, ODDPARITY, SPACEPARITY)
 *  - Number of stop bits (ONESTOPBIT, ONE5STOPBITS, TWOSTOPBITS)
 */
void Configuration::SetSerialPort(LPCTSTR name,
								  UINT baudRate,
								  BYTE parity,
								  BYTE stopBits) {

	if (this->m_pMedia != NULL) {

		delete this->m_pMedia;
		this->m_pMedia = NULL;
	}

	this->m_pMedia = new SerialPort(name, baudRate, parity, stopBits);
}

/**
 * Name:		SetXonXoff
 * Purpose:		Configure the firmware updater to use the XonXoff protocol
 */
void Configuration::SetXonXoff() {

	if (this->m_pCommunication != NULL) {

		delete this->m_pCommunication;
		this->m_pCommunication = NULL;
	}
	this->m_pCommunication = new XonXoff(this->m_pMedia);
}

/**
 * Name:		SetFile
 * Purpose:		Sets the input firmware
 * Input:
 *	- Firmware file to send to the target device
 */
void Configuration::SetFile(LPCTSTR filename) {

	// Open new file
	if (this->m_pFirmware != NULL) {

		delete this->m_pFirmware;
		this->m_pFirmware = NULL;
	}
	this->m_pFirmware = new CFile(filename, CFile::modeRead | CFile::shareExclusive);
}

/**
 * Name:		GetCommunication
 * Purpose:		Returns the current communication protocol
 * Output:		Current communication protocol
 */
Communication * Configuration::GetCommunication() {

	return this->m_pCommunication;
}

/**
 * Name:		GetFile
 * Purpose:		Returns the current firmware file
 * Output:		Current firmware file
 */
CFile * Configuration::GetFile() {

	return this->m_pFirmware;
}

/**
 * Name:		Parse
 * Purpose:		Parses command-line arguments
 * Input(s):
 *	- String containing the arguments
 */
void Configuration::Parse(LPCTSTR arguments) {

	// Local variables
	CString media("serial");
	CString serialPort("COM1");
	UINT serialBaudrate = 115200;
	BYTE serialParity = NOPARITY;
	BYTE serialStopBits = ONESTOPBIT;

	CString protocol("xonxoff");

	for (UINT i=0; arguments[i] != '\0'; i++) {

		// Skip blank spaces
		while (arguments[i] == ' ') {

			i++;
		}

		// Parse options
		if (arguments[i] == '-') {

			CString option("");
			CString value("");

			// Get option name
			i++;
			while ((arguments[i] != ' ') && (arguments[i] != '\0')) {

				option += arguments[i];
				i++;
			}

			// Skip blank spaces
			while (arguments[i] == ' ') {

				i++;
			}
			
			if (arguments[i] == '\0') {

				CConfigurationException::ThrowError("Unexpected command-line end");
			}

			// Get option value
			while ((arguments[i] != ' ') && (arguments[i] != '\0')) {

				value += arguments[i];
				i++;
			}

			// Parse option
			if ((option == "m") || (option == "media")) {

				media = value;
			}
			else if ((option == "b") || (option == "baudrate")) {

				serialBaudrate = atoi(value);

				if (serialBaudrate == 0) {

					CConfigurationException::ThrowError(value + " is not a valid baudrate value");
				}
			}
			else if ((option == "P") || (option == "parity")) {

				if (value == "no") {

					serialParity = NOPARITY;
				}
				else if (value == "even") {

					serialParity = EVENPARITY;
				}
				else if (value == "odd") {

					serialParity = ODDPARITY;
				}
				else if (value == "mark") {

					serialParity = MARKPARITY;
				}
				else if (value == "space") {

					serialParity = SPACEPARITY;
				}
				else {

					CConfigurationException::ThrowError(value + " is not a valid parity");
				}
			}
			else if ((option == "s") || (option == "stopBits")) {

				if (value == "1") {

					serialStopBits = ONESTOPBIT;
				}
				else if (value == "1.5") {

					serialStopBits = ONE5STOPBITS;
				}
				else if (value == "2") {

					serialStopBits = TWOSTOPBITS;
				}
				else {

					CConfigurationException::ThrowError(value + " is not a valid number of stop bits");
				}
			}
			else if ((option == "p") || (option == "protocol")) {

				protocol = value;
			}
			else {

				CConfigurationException::ThrowError("-" + option + " is not a valid option");
			}
		}
		else {

			// Parse filename
			CString filename;

			while (arguments[i] != '\0') {

				filename += arguments[i];
				i++;
			}

			try {

				this->SetFile(filename);
			}
			catch (CFileException * e) {

				char buffer[500];
				e->GetErrorMessage(buffer, 500);
				CConfigurationException::ThrowError(buffer);
			}
		}
	}

	// Set configuration
	// Media
	if (media == "serial") {

		this->SetSerialPort(serialPort, serialBaudrate, serialParity, serialStopBits);
	}
	else {

		CConfigurationException::ThrowError(media + " is not a valid media type");
	}

	// Protocol
	if (protocol == "xonxoff") {

		this->SetXonXoff();
	}
	else {

		CConfigurationException::ThrowError(protocol + " is not a valid communication protocol");
	}
}

/**
 * Name:		DisplayOptions
 * Purpose:		Displays the available command-line options
 */
void Configuration::DisplayOptions() {

	CString options;
	
	options += "Usage: FirmwareUpdater.exe [options] [firmware file]\n\n";
	options += "Global options:\n";
	options += "	-m, -media	Media type (serial)\n";
	options += "	-p, -protocol	Communication protocol (xonxoff)\n\n";
	options += "Serial options:\n";
	options += "	-n, -name		COM port name (COM1 | COM2 | ...)\n";
	options += "	-b, -baudrate	Desired baudrate\n";
	options += "	-P, -parity	Parity (no | even | odd | mark | space)\n";
	options += "	-s, -stopBits	Number of stop bits (1 | 1.5 | 2)\n";

	AfxMessageBox(options);
}
