#include <iostream>
#include <string>
#include <getopt.h>
#include <msclr\marshal_cppstd.h>

using namespace MxLBPLibrary;
using namespace std;

#define UNSET 	-1

enum Uart_Command
{
	RELAYMODE = 0,
	WDTRESETMODE = 1,
	WDTRELAYMODE = 2,
	APPWDTMODE = 3,
	APPWDTKICK = 4,
	APPWDTRESETMODE = 5,
	APPWDTRELAYMODE = 6,
	POWEROFFRELAYMODE = 7,
	CHECKMCUFIRMWAREVERSION = 8
};

struct action_struct {
	int command;
	int mode;
	int timeout;
};


void usage(FILE* fp)
{
	fprintf(fp, "Usage:\n");
	fprintf(fp, "	mx-lanbypass-ctl_c++ -c <Uart Command>  [-m <Mode>] [-t <Timeout>]\n");
	fprintf(fp, "OPTIONS:\n");
	fprintf(fp, "	-c <#Uart Command>\n");
	fprintf(fp, "		0 --> RelayMode \n");
	fprintf(fp, "		1 --> WDT Reset Mode \n");
	fprintf(fp, "		2 --> WDT Relay Mode \n");
	fprintf(fp, "		3 --> APP WDT Mode \n");
	fprintf(fp, "		4 --> APP WDT Kick (Send only once)\n");
	fprintf(fp, "		5 --> APP WDT Reset Mode \n");
	fprintf(fp, "		6 --> APP WDT Relay Mode \n");
	fprintf(fp, "		7 --> PowerOff Relay Mode \n");
	fprintf(fp, "		8 --> Check MCU FW Version \n");
	fprintf(fp, "	-m <#Mode>\n");
	fprintf(fp, "	    0 --> Connect / Not Reset / Disable\n");
	fprintf(fp, "	    1 --> Disconnect / Reset / Enable\n");
	fprintf(fp, "	    2 --> Bypass\n");
	fprintf(fp, "	-t <#Timeout>\n");
	fprintf(fp, "	    5-15 sec (default 5 sec)\n");
	fprintf(fp, "\n");
	fprintf(fp, "Example:\n");
	fprintf(fp, "	    Get App WDT Relay Mode\n");
	fprintf(fp, "	    # mx-lanbypass-ctl_C++.exe -c 5\n");
	fprintf(fp, "	    Set WDT Reset Mode to Disconnect\n");
	fprintf(fp, "	    # mx-lanbypass-ctl_C++.exe -c 1 -m 1\n");
	fprintf(fp, "	    Set App WDT Mode to Enable and Timeout 5s\n");
	fprintf(fp, "	    # mx-lanbypass-ctl_C++.exe -c 3 -m 1 -t 5\n");
	fprintf(fp, "	    Send App WDT Kick\n");
	fprintf(fp, "	    # mx-lanbypass-ctl_C++.exe -c 4\n");
	fprintf(fp, "	    Check MCU Firmware Version\n");
	fprintf(fp, "	    # mx-lanbypass-ctl_C++.exe -c 8\n");
	fprintf(fp, "\n");
}

int my_atoi(const char* nptr, int* number)
{
	int tmp;

	tmp = atoi(nptr);
	if (tmp != 0) {
		*number = tmp;
		return 0;
	}
	else {
		if (!strcmp(nptr, "0")) {
			*number = 0;
			return 0;
		}
	}
	return -1;
}

void ExitProcess(std::string item)
{
	cout << ("[ERROR] " + item + "\n");
	exit(0);
}

void ShowLBPMessage(int command, int status, int timeout, std::string version)
{
	switch (command)
	{
	default:
		break;
	case RELAYMODE:
		if (status == 0)
			cout << ("Current Relay Mode is Connect.\n");
		else if (status == 1)
			cout << ("Current Relay Mode is Disconnect.\n");
		else
			cout << ("Current Relay Mode is By Pass.\n");
		break;
	case WDTRESETMODE:
		if (status == 0)
			cout << ("Current WDT Reset Mode is Not Reset.\n");
		else
			cout << ("Current WDT Reset Mode is Reset.\n");
		break;
	case WDTRELAYMODE:
		if (status == 0)
			cout << ("Current WDT Relay Mode is Connect.\n");
		else if (status == 1)
			cout << ("Current WDT Relay Mode is Disconnect.\n");
		else
			cout << ("Current WDT Relay Mode is By Pass.\n");
		break;
	case APPWDTMODE:
		if (status == 0)
			cout << ("Current App WDT Mode is Disable.\n");
		else
		{
			cout << ("Current App WDT Mode is Enable.\n");
			cout << ("Current App WDT Timeout is " + std::to_string(timeout) + " sec\n");
		}
		break;
	case APPWDTKICK:
		cout << ("Send App WDT Kick.\n");
		break;
	case APPWDTRESETMODE:
		if (status == 0)
			cout << ("Current App WDT Reset Mode is Not Reset.\n");
		else
			cout << ("Current App WDT Reset Mode is Reset.\n");
		break;
	case APPWDTRELAYMODE:
		if (status == 0)
			cout << ("Current App WDT Relay Mode is Connect.\n");
		else if (status == 1)
			cout << ("Current App WDT Relay Mode is Disconnect.\n");
		else
			cout << ("Current App WDT Relay Mode is By Pass.\n");
		break;
	case POWEROFFRELAYMODE:
		if (status == 0)
			cout << ("Current Power Off Relay Mode is Disconnect.\n");
		else
			cout << ("Current Power Off Relay Mode is By Pass\n");
		break;
	case CHECKMCUFIRMWAREVERSION:
		cout << ("MCU Firmware Version is " + version + "\n");
		break;
	}
}

void do_action(struct action_struct action)
{
	MxLBP^ mxLBPLib = gcnew MxLBP(gcnew RealMCU());
	int ret;
	int status = 0;
	string version = "";

	switch (action.command) {
	default:
		ExitProcess("Wrong Command index\n");
		break;
	case RELAYMODE:
		if (action.mode == -1)
		{
			ret = mxLBPLib->GetRelayMode(status);
			if (ret == 1)
				ExitProcess("Get Relay Mode fail");
		}
		else if (action.mode == 0 || action.mode == 1 || action.mode == 2)
		{
			ret = mxLBPLib->SetRelayMode(action.mode);
			if (ret == 1)
				ExitProcess("Set Relay Mode fail");

			ret = mxLBPLib->GetRelayMode(status);
			if (ret == 1)
				ExitProcess("Get Relay Mode fail");
		}
		else
			ExitProcess("Mode must be 0:Connect/ 1:Disconnect/ 2:ByPass");
		break;

	case WDTRESETMODE:
		if (action.mode == -1)
		{
			ret = mxLBPLib->GetWDTResetMode(status);
			if (ret == 1)
				ExitProcess("Get WDT Reset Mode fail");
		}
		else if (action.mode == 0 || action.mode == 1)
		{
			ret = mxLBPLib->SetWDTResetMode(action.mode);
			if (ret == 1)
				ExitProcess("Set WDT Reset Mode fail");

			ret = mxLBPLib->GetWDTResetMode(status);
			if (ret == 1)
				ExitProcess("Get WDT Reset Mode fail");
		}
		else
			ExitProcess("Mode must be 0:Not Reset/ 1:Reset");
		break;

	case WDTRELAYMODE:
		if (action.mode == -1)
		{
			ret = mxLBPLib->GetWDTRelayMode(status);
			if (ret == 1)
				ExitProcess("Get WDT Relay Mode fail");
		}
		else if (action.mode == 0 || action.mode == 1 || action.mode == 2)
		{
			ret = mxLBPLib->SetWDTRelayMode(action.mode);
			if (ret == 1)
				ExitProcess("Set WDT Relay Mode fail");

			ret = mxLBPLib->GetWDTRelayMode(status);
			if (ret == 1)
				ExitProcess("Get WDT Relay Mode fail");
		}
		else
			ExitProcess("Mode must be 0:Connect/ 1:Disconnect/ 2:ByPass");
		break;

	case APPWDTMODE:
		if (action.mode == -1)
		{
			ret = mxLBPLib->GetAppWDTMode(status, action.timeout);
			if (ret == 1)
				ExitProcess("Get App WDT Mode fail");
		}
		else if (action.mode == 0 || action.mode == 1)
		{
			ret = mxLBPLib->SetAppWDTMode(action.mode, action.timeout);
			if (ret == 1)
				ExitProcess("Set App WDT Mode fail");
			ret = mxLBPLib->GetAppWDTMode(status, action.timeout);
			if (ret == 1)
				ExitProcess("Get App WDT Mode fail");
		}
		else
			ExitProcess("Mode must be 0:Disable/1:Enable");
		break;

	case APPWDTKICK:
		ret = mxLBPLib->SendAppWDTKick();
		if (ret == 1)
			ExitProcess("Send App WDT Kick fail");
		break;

	case APPWDTRESETMODE:
		if (action.mode == -1)
		{
			ret = mxLBPLib->GetAppWDTResetMode(status);
			if (ret == 1)
				ExitProcess("Get App WDT Reset Mode fail");
		}
		else if (action.mode == 0 || action.mode == 1)
		{
			ret = mxLBPLib->SetAppWDTResetMode(action.mode);
			if (ret == 1)
				ExitProcess("Set App WDT Reset Mode fail");

			ret = mxLBPLib->GetAppWDTResetMode(status);
			if (ret == 1)
				ExitProcess("Get App WDT Reset Mode fail");
		}
		else
			ExitProcess("Mode must be 0:Not Reset/ 1:Reset");
		break;

	case APPWDTRELAYMODE:
		if (action.mode == -1)
		{
			ret = mxLBPLib->GetAppWDTRelayMode(status);
			if (ret == 1)
				ExitProcess("Get App WDT Relay Mode fail");
		}
		else if (action.mode == 0 || action.mode == 1 || action.mode == 2)
		{
			ret = mxLBPLib->SetAppWDTRelayMode(action.mode);
			if (ret == 1)
				ExitProcess("Set App WDT Relay Mode fail");

			ret = mxLBPLib->GetAppWDTRelayMode(status);
			if (ret == 1)
				ExitProcess("Get App WDT Relay Mode fail");
		}
		else
			ExitProcess("Mode must be 0:Connect/ 1:Disconnect/ 2:ByPass");
		break;
	case POWEROFFRELAYMODE:
		if (action.mode == -1)
		{
			ret = mxLBPLib->GetPowerOffRelayMode(status);
			status -= 1;
			if (ret == 1)
				ExitProcess("Get Power Off Relay Mode fail");
		}
		else if (action.mode == 2 || action.mode == 1)
		{
			ret = mxLBPLib->SetPowerOffRelayMode(action.mode + 1);
			if (ret == 1)
				ExitProcess("Set Power Off Relay Mode fail");

			ret = mxLBPLib->GetPowerOffRelayMode(status);
			status -= 1;
			if (ret == 1)
				ExitProcess("Get Power Off Relay Mode fail");
		}
		else
			ExitProcess("Mode must be 0:Disconnect/ 1:ByPass");
		break;
	case CHECKMCUFIRMWAREVERSION:
		System::String^ MCUversion = "";
		ret = mxLBPLib->GetMCUFirmwareVersion(MCUversion);
		version = msclr::interop::marshal_as< std::string >(MCUversion);
		if (ret == 1)
			ExitProcess("Get MCU Firmware Version fail");
		break;
	}
	ShowLBPMessage(action.command, status, action.timeout, version);
}

int main(int argc, char** argv)
{
	struct action_struct action = { UNSET, UNSET, 5 };
	int c;

	while (1) {
		c = getopt(argc, argv, "hc:m:t:");
		if (c == -1)
			break;

		switch (c) {
		case 'h':
			usage(stdout);
			exit(0);
		case 'c':
			if (my_atoi(optarg, &action.command) != 0) {
				fprintf(stderr, "%s is not a number\n", optarg);
				exit(1);
			}
			break;
		case 'm':
			if (my_atoi(optarg, &action.mode) != 0) {
				fprintf(stderr, "%s is not a number\n", optarg);
				exit(1);
			}
			break;
		case 't':
			if (my_atoi(optarg, &action.timeout) != 0) {
				fprintf(stderr, "%s is not a number\n", optarg);
				exit(1);
			}
			break;
		default:
			usage(stderr);
			exit(99);
		}
	}
	if (action.command == UNSET) {
		fprintf(stderr, "port number is unset\n");
		usage(stderr);
		exit(99);
	}
	do_action(action);
	exit(0);
}