#include <OwnCommandProcessor.h>
#include <OwnDiagRuntimeSystem.h>
#include <Command.h>
using OpenTestSystem::OtxDiagManager::Common::Command;
#include <Parameter.h>
using OpenTestSystem::OtxDiagManager::Common::Parameter;
#include <Result.h>
using OpenTestSystem::OtxDiagManager::Common::Result;
#include <ProtoGen/CommandTypesPb.pb.h>
using OpenTestSystem::OtxDiagManager::Common::CommandTypesPb;
#include <ProtoGen/ResultCodesPb.pb.h>
using OpenTestSystem::OtxDiagManager::Common::ResultCodesPb;
#include <ProtoGen/ExceptionTypesPb.pb.h>
using OpenTestSystem::OtxDiagManager::Common::ExceptionTypesPb;
#include <ProtoGen/DiagComCommandsPb.pb.h>
using OpenTestSystem::OtxDiagManager::Common::GetComChannelPb;
using OpenTestSystem::OtxDiagManager::Common::CreateDiagServiceByNamePb;
#include <functional>
#include <iostream>

Command CreateCommandGetComChannel(const std::string& identifier, const std::string& ecuvariantname);
Command CreateCommandCreateDiagServiceByName();
void ProcessResult(const Result& result);

int main(char* args)
{
	std::cout << "Initialize CommandProcessor and DiagRuntimeSystem" << std::endl;
	OwnCommandProcessor* cp = new OwnCommandProcessor(new OwnDiagRuntimeSystem());
	Result* rs = nullptr;

	// ===== CREATE GetComChannel Command ======
	Command getcomchannelCommand = CreateCommandGetComChannel("LL_GatewUDS", "");
	// =========================================

	// ===== Execute GetComChannel Command ======
	std::cout << "Execute a GetComChannel Command" << std::endl;

	rs = cp->Execute(getcomchannelCommand);
	ProcessResult(*rs);
	delete rs;
	rs = nullptr;

	// ===== Execute GetComChannel Command with ExecuteAsync ======
	std::cout << "Execute Async a GetComChannel Command" << std::endl;

	std::function<void(const Result&)> asyncResultHandler = ProcessResult;
	cp->SetAsyncResultHandler(asyncResultHandler);

	rs = cp->ExecuteAsync(getcomchannelCommand);
	delete rs;
	rs = nullptr;

	// ===== CREATE CreateDiagServiceByName Command ======
	Command createDiagServiceByNameCommand = CreateCommandCreateDiagServiceByName();
	// ===================================================

	std::cout << "Execute a CreateDiagServiceByName Command" << std::endl;
	rs = cp->Execute(createDiagServiceByNameCommand);
	ProcessResult(*rs);
	delete rs;
	rs = nullptr;
	return 1;
}

Command CreateCommandGetComChannel(const std::string& identifier, const std::string& ecuvariantName)
{
	GetComChannelPb getComChannel;
	getComChannel.set_identifier(identifier);
	getComChannel.set_ecuvariantname(ecuvariantName);

	std::string bytestr;
	getComChannel.SerializeToString(&bytestr);

	Command getComChannelCommand;
	getComChannelCommand.SetCommandType(CommandTypesPb::GetComChannel);
	getComChannelCommand.AddParameter(1, std::make_shared<Parameter>());
	getComChannelCommand.GetParameter(1)->SetBytesValue(bytestr);

	return getComChannelCommand;
}

Command CreateCommandCreateDiagServiceByName()
{
	CreateDiagServiceByNamePb createDiagServiceByName;
	createDiagServiceByName.set_name("diagservicename");

	std::string bytestr;
	createDiagServiceByName.SerializeToString(&bytestr);

	Command createDiagServiceByNameCommand;
	createDiagServiceByNameCommand.SetCommandType(CommandTypesPb::CreateDiagServiceByName);
	createDiagServiceByNameCommand.AddParameter(1, std::make_shared<Parameter>());
	createDiagServiceByNameCommand.GetParameter(1)->SetBytesValue(bytestr);

	return createDiagServiceByNameCommand;
}

void ProcessResult(const Result& result)
{
	try
	{
		int resultCode = result.GetResultCode();
		if (resultCode == ResultCodesPb::Success)
		{
			std::cout << "Execute successfully. " << std::endl;
		}
		else if (resultCode == ResultCodesPb::Failed)
		{
			int errorCode;
			ExceptionTypesPb exceptionType;
			std::string errorMessage;
			result.GetExceptionData(errorCode, exceptionType, errorMessage);
			std::cout << "Execute failed. ErrorCode(" << errorCode << "), " << "ExceptionType(" << exceptionType << "), " << "ErrorMessage: " << errorMessage << std::endl;
		}

		// ===== Return Result to Diag Manager Server ======

		//==================================================

	}
	catch (std::exception& e)
	{
		std::cout << "Execute failed. ErrorMessage: " << e.what();
	}
}