extern "C"
{
	#include "TciTM/TriTciChannel.h"
}
#ifdef WIN32
#include <Windows.h>
#endif
#include <boost/thread/thread.hpp>
#include <boost/thread/condition.hpp>
#include "Logger/Logger.h"

#include "tri-sa.h"
#include "tri-pa.h"
#include <iostream>
#include <string.h>

static boost::mutex exitMutex;
static boost::condition exitCondition;

void onConnectionClosed()
{
	boost::mutex::scoped_lock localLock(exitMutex);
	exitCondition.notify_one();
}

void onError(char * pErrorString)
{
	std::cout << "TRI channel error:" << std::endl;
	std::cout << pErrorString << std::endl;
}

int main(int argc, char **argv)
{
	std::cout << "Application started" << std::endl;
	if (argc == 2 && strcmp(argv[1], "-help") == 0)
	{
		std::cout << "Usage: Adapter [-a address][-p port_number]" << std::endl;
		std::cout << "-a address       Specifies TestCast IP address. 127.0.0.1 is used by" << std::endl;
		std::cout << "                 default." << std::endl;
		std::cout << "-p port_number   Specifies TestCast port. 7777 is used by default." << std::endl;
		std::cout << "-L*              Sets the log level. Log levels can be combined together." << std::endl;
		std::cout << "                 The following log levels are available:" << std::endl;
		std::cout << "   -Linfo        Displays information messages" << std::endl;
		std::cout << "   -Lerr         Displays errors" << std::endl;
		std::cout << "   -Lwarn        Displays warnings" << std::endl;
		std::cout << "   -Ldebug       Displays debugging information" << std::endl;
		std::cout << "   -Lall         Displays all information" << std::endl;
		std::cout << "   -Lnone        No messages are displayed" << std::endl;
		return 0;
	}

	int nLogMode = 0;
	bool bLogModeSet = false;
	bool bError = false;
	Logger::Instance().SetLoggingMode(Logger::LOG_ERRORS);
	char * pszAddr = "127.0.0.1";
	int nPort = 7777;
	WSADATA w;
	for (int i = 1; i < argc; ++i)
	{
		bool bLog = false;
		char * pszArg = argv[i];
		if (strcmp(pszArg, "-p") == 0)
		{
			if (bError = i + 1 == argc)
				std::cout << "Port value missing" << std::endl;
			else
			{
				pszArg = argv[++i];
				nPort = atoi(pszArg);
			}
		}
		else if (strcmp(pszArg, "-a") == 0)
		{
			if (bError = i + 1 == argc)
				std::cout << "Address value missing" << std::endl;
			else
			{
				pszArg = argv[++i];
				pszAddr = pszArg;
			}
		}
		else if (bLog = strcmp(pszArg, "-Linfo") == 0)
			nLogMode |= Logger::LOG_INFO;
		else if (bLog = strcmp(pszArg, "-Lerr") == 0)
			nLogMode |= Logger::LOG_ERRORS;
		else if (bLog = strcmp(pszArg, "-Lwarn") == 0)
			nLogMode |= Logger::LOG_WARNINGS;
		else if (bLog = strcmp(pszArg, "-Ldebug") == 0)
			nLogMode |= Logger::LOG_DEBUG | Logger::LOG_INFO;
		else if (bLog = strcmp(pszArg, "-Lall") == 0)
			nLogMode = Logger::LOG_ALL;
		else if (bLog = strcmp(pszArg, "-Lnone") == 0)
			nLogMode = Logger::LOG_NOTHING;
		else
		{
			bError = true;
			std::string s = "Unknown command line parameter \"";
			s += pszArg;
			s += "\"";
			std::cout << s << std::endl;
		}
		if (bLog)
			bLogModeSet = true;
	}
	if (bError)
		return 1;
	if (!bLogModeSet)
	Logger::Instance().SetLoggingMode(nLogMode);
	Logger::Instance().LogDebug("Command line parameters processed successfully");

#ifdef WIN32
	// Winsock init
	if (WSAStartup(0x0002, &w))
	{
		std::cout << "Error initiating Winsock library" << std::endl;
		return 1;
	}
#endif
	// Map callbacks
	setTriSAResetCallback (triSAReset);
	setTriExecuteTestCaseCallback (triExecuteTestCase);
	setTriMapCallback (triMap);
	setTriUnmapCallback (triUnmap);
	setTriEndTestCaseCallback (triEndTestcase);
	setTriSendCallback (triSend);
	//setTriSendBCCallback (triSendBC);
	//setTriSendMCCallback (triSendMC);
	setTriCallCallback (triCall);
	//setTriCallBCCallback (triCallBC);
	//setTriCallMCCallback (triCallMC);
	setTriReplyCallback (triReply);
	//setTriReplyBCCallback (triReplyBC);
	//setTriReplyMCCallback (triReplyMC);
	setTriRaiseCallback (triRaise);
	//setTriRaiseBCCallback (triRaiseBC);
	//setTriRaiseMCCallback (triRaiseMC);
	//setTriSUTActionInformalCallback (triSUTActionInformal);
	//setTriPAResetCallback (triPAReset);
	//setTriStartTimerCallback (triStartTimer);
	//setTriStopTimerCallback (triStopTimer);
	//setTriReadTimerCallback (triReadTimer);
	//setTriTimerRunningCallback (triTimerRunning);
	//setTriExternalFunctionCallback (triExternalFunction);

	// Callback for monitoring connection termination
	setOnConnectionClosedCallback(onConnectionClosed);
	setTciTMErrorCallback(onError);

	int nRes = 0;
	// Create TCP/IP connection
	std::cout << "Atempting to establish TCP/IP connection to TestCast" << std::endl;
	if (openTriTciChannel(pszAddr, nPort, SA_ENABLED | PA_ENABLED, L"Generic T3devkit Adapter"))
	{
		std::cout << "TCP/IP connection with TestCast established" << std::endl;
		// Local lock for monitoring exit condition
		boost::mutex::scoped_lock exitLock(exitMutex);
		// Waiting for exit condition
		exitCondition.wait(exitLock);
		closeTriChannel();
		std::cout << "TCP/IP connection with TestCast closed" << std::endl;
	}
	else
	{
		std::cout << "Failed to open TRI channel" << std::endl;
		nRes = 2;
	}
#ifdef WIN32
	// Winsock cleanup
	WSACleanup();
#endif

	return 2;
}


