#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 <Exception.h>
using OpenTestSystem::OtxDiagManager::Common::Exception;
#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>
#include <ProtoGen/DiagComDataModelsPb.pb.h>
using namespace OpenTestSystem::OtxDiagManager::Common;

OwnDiagRuntimeSystem::OwnDiagRuntimeSystem()
{
}

OwnDiagRuntimeSystem::~OwnDiagRuntimeSystem()
{
}

Result * OwnDiagRuntimeSystem::Execute(const Command & command)
{
	Result * result = new Result(command, ResultCodesPb::Pending);

	CommandTypesPb cmdtype = (CommandTypesPb)command.GetCommandType();

	std::shared_ptr<OpenTestSystem::OtxDiagManager::Common::Parameter> param = command.GetParameter(1);
	if (param == nullptr)
		return nullptr;

	switch (cmdtype)
	{
		case CommandTypesPb::GetComChannel:
		{
			// Get protobuf command
			GetComChannelPb getComChannel;
			getComChannel.ParseFromString(param->GetValueAsBytes());

			if (getComChannel.identifier().empty())
			{
				result->SetResultCode(OpenTestSystem::OtxDiagManager::Common::ResultCodesPb::Failed);
				result->SetExceptionData(1, OpenTestSystem::OtxDiagManager::Common::ExceptionTypesPb::DiagComException, "identifier is null");
				return result;
			}

			// ======================== HANDLE WITH RUNTIME SYSTEM =====================
			//	
			//
			// =========================================================================

			// ======================== HANDLE RESULT ========================
			// Make protobuf object
			DComChannelPb comChannel;
			comChannel.set_handle(1);
			comChannel.set_identifier(getComChannel.identifier());
			comChannel.set_ecuvariantname(getComChannel.ecuvariantname());

			// Serialize protobuf object to string
			std::string bytestr;
			comChannel.SerializeToString(&bytestr);

			// Set byte string to Result
			result->AddParameter(1, std::make_shared<Parameter>());
			result->GetParameter(1)->SetBytesValue(bytestr);
			result->SetResultCode(ResultCodesPb::Success);
			// ================================================================

			break;
		}
		case CommandTypesPb::CreateDiagServiceByName:
		{
			OpenTestSystem::OtxDiagManager::Common::CreateDiagServiceByNamePb createDiagServiceByName;
			createDiagServiceByName.ParseFromString(param->GetValueAsBytes());

			int handle(2);
			OpenTestSystem::OtxDiagManager::Common::DDiagServicePb diagService;
			diagService.set_handle(handle);
			diagService.set_shortname(createDiagServiceByName.name());

			// Make protobuf object
			OpenTestSystem::OtxDiagManager::Common::DComChannelPb* comChannelPb = new OpenTestSystem::OtxDiagManager::Common::DComChannelPb;
			comChannelPb->set_handle(createDiagServiceByName.comchannel().handle());
			diagService.set_allocated_comchannel(comChannelPb);

			// Serialize protobuf object to string
			std::string bytes;
			diagService.SerializeToString(&bytes);

			// Set byte string to Result
			std::shared_ptr<Parameter> param = std::make_shared<Parameter>();
			param->SetBytesValue(bytes);

			result = new OpenTestSystem::OtxDiagManager::Common::Result(command, 0);
			result->AddParameter(1, param);
			result->SetResultCode(ResultCodesPb::Success);
			break;
		}
		default:
		{
			// Handle an error
			result->SetResultCode(ResultCodesPb::Failed);
			result->SetExceptionData(0, ExceptionTypesPb::NotImplementedException, "Not Implemented!");
		}
	}

	return result;
}

Result * OwnDiagRuntimeSystem::ExecuteAsync(const Command & command)
{
	Result* result = Execute(command);

	if (_asyncResultHandler != nullptr)
	{
		_asyncResultHandler(*result);
	}

	return result;
}

void OwnDiagRuntimeSystem::SetAsyncResultHandler(std::function<void(const Result&)> handler)
{
	_asyncResultHandler = handler;
}

void OwnDiagRuntimeSystem::SetExceptionHandler(std::function<void(const Exception&)> handler)
{
	_exceptionHandler = handler;
}
