//-------------------------------------------------------------------------------------------------
// <copyright file="PayloadManagerSettings.cpp" company="LiquidRobotics">
//  Copyright (c) Liquid Robotics Corporation, confidential and proprietary.  All rights reserved. 
// </copyright>
//
// <summary>
// 	Implementation of PayloadManagerSettings, a serializable entity that contains
//  customization variables for PayloadManager
// </summary>
//
// <owner>Mike Cookson</owner>
//-------------------------------------------------------------------------------------------------

#include "PayloadManagerSettings.h"
#include <stdexcept>
#include <iostream>
#include <fstream>
#include <sstream>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

using namespace std;
using namespace LiquidRobotics::EventLib;
using namespace boost;
using namespace boost::archive;
using namespace boost::serialization;

static const char rootLevel[] = "rootlevel";
static const char className[] = "PayloadManagerSettings";

PayloadManagerSettings::PayloadManagerSettings()
: serverName("PayloadManager")
, serverKind("")
, defaultBoardID(0xFF)
, deviceAddedEventName("PayloadDeviceAdded")
, deviceChangedEventName("PayloadDeviceChanged")
, deviceRemovedEventName("PayloadDeviceRemoved")
, commonEventType("PayloadRegistrationEvent")
, commonEventDomain("LiquidR-SMC")
{
}

PayloadManagerSettings::PayloadManagerSettings(const PayloadManagerSettings& other)
: serverName(other.serverName)
, serverKind(other.serverKind)
, defaultBoardID(other.defaultBoardID)
, deviceAddedEventName(other.deviceAddedEventName)
, deviceChangedEventName(other.deviceChangedEventName)
, deviceRemovedEventName(other.deviceRemovedEventName)
, commonEventType(other.commonEventType)
, commonEventDomain(other.commonEventDomain)
, eventTransceiverSettings(other.eventTransceiverSettings)
{
}

PayloadManagerSettings& PayloadManagerSettings::operator=(const PayloadManagerSettings& other)
{
	if (this != &other)
	{
		serverName = other.serverName;
		serverKind = other.serverKind;
		defaultBoardID = other.defaultBoardID;
		deviceAddedEventName = other.deviceAddedEventName;
		deviceChangedEventName = other.deviceChangedEventName;
		deviceRemovedEventName = other.deviceRemovedEventName;
		commonEventType = other.commonEventType;
		commonEventDomain = other.commonEventDomain;
		eventTransceiverSettings = other.eventTransceiverSettings;
	}

	return *this;
}

bool PayloadManagerSettings::operator==(const PayloadManagerSettings& other) const
{
	return !serverName.compare(other.serverName)
	    && !serverKind.compare(other.serverKind)
	    && (defaultBoardID == other.defaultBoardID)
	    && !deviceAddedEventName.compare(other.deviceAddedEventName)
	    && !deviceChangedEventName.compare(other.deviceChangedEventName)
	    && !deviceRemovedEventName.compare(other.deviceRemovedEventName)
	    && !commonEventType.compare(other.commonEventType)
	    && !commonEventDomain.compare(other.commonEventDomain)
	    && (eventTransceiverSettings == other.eventTransceiverSettings);
}

const string& PayloadManagerSettings::GetServerName() const
{
	return serverName;
}

void PayloadManagerSettings::SetServerName(const string& newValue)
{
	serverName = newValue;
}

const string& PayloadManagerSettings::GetServerKind() const
{
	return serverKind;
}

void PayloadManagerSettings::SetServerKind(const string& newValue)
{
	serverKind = newValue;
}

const PayloadManagerSettings::StdOutLoggerSettings& PayloadManagerSettings::GetLoggerSettings() const
{
	return loggerSettings;
}

void PayloadManagerSettings::SetLoggerSettings(const StdOutLoggerSettings& newValue)
{
	loggerSettings = newValue;
}

PayloadManagerSettings::byte PayloadManagerSettings::GetDefaultBoardID() const
{
	return defaultBoardID;
}

void PayloadManagerSettings::SetDefaultBoardID(byte newValue)
{
	defaultBoardID = newValue;
}

const PayloadManagerSettings::EventTransceiverSettings& PayloadManagerSettings::GetEventTransceiverSettings() const
{
	return eventTransceiverSettings;
}

const string& PayloadManagerSettings::GetDeviceAddedEventName() const
{
	return deviceAddedEventName;
}

void PayloadManagerSettings::SetDeviceAddedEventName(const string& newValue)
{
	deviceAddedEventName = newValue;
}

const string& PayloadManagerSettings::GetDeviceChangedEventName() const
{
	return deviceChangedEventName;
}

void PayloadManagerSettings::SetDeviceChangedEventName(const string& newValue)
{
	deviceChangedEventName = newValue;
}

const string& PayloadManagerSettings::GetDeviceRemovedEventName() const
{
	return deviceRemovedEventName;
}

void PayloadManagerSettings::SetDeviceRemovedEventName(const string& newValue)
{
	deviceRemovedEventName = newValue;
}

const string& PayloadManagerSettings::GetCommonEventType() const
{
	return commonEventType;
}

void PayloadManagerSettings::SetCommonEventType(const string& newValue)
{
	commonEventType = newValue;
}

const string& PayloadManagerSettings::GetCommonEventDomain() const
{
	return commonEventDomain;
}

void PayloadManagerSettings::SetCommonEventDomain(const string& newValue)
{
	commonEventDomain = newValue;
}

void PayloadManagerSettings::SetEventTransceiverSettings(const EventTransceiverSettings& newValue)
{
	eventTransceiverSettings = newValue;
}

void PayloadManagerSettings::Load(const string& fileName)
{
	struct stat statBuf;
	int status = stat(fileName.c_str(), &statBuf);
	int errSave = errno;

	if (!status)
	{
		if (!statBuf.st_size)
		{
			PayloadManagerSettings temp;
			temp.Save(fileName);
		}

		ifstream ifs(fileName.c_str());

		if (!ifs.good())
		{
			stringstream msg;
			msg << className << "::Load: could not open '" << fileName << "' for read";
			throw invalid_argument(msg.str());
		}

		xml_iarchive ia(ifs);
		ia >> make_nvp(rootLevel, *this);
	}
	else
	{
		char tempBuffer[256];
		strerror_r(errSave, tempBuffer, sizeof(tempBuffer));

		stringstream msg;

		msg << className << "::Load: could not stat '" << fileName << "'"
		    << " (errno=" << errSave << " '" << tempBuffer << "')";
		throw invalid_argument(msg.str());
	}
}

void PayloadManagerSettings::Save(const string& fileName) const
{
	ofstream ofs(fileName.c_str());

	if (!ofs.good())
	{
		stringstream msg;
		msg << className << "::Save: could not open '" << fileName << "' for write";
		throw invalid_argument(msg.str());
	}

	xml_oarchive oa(ofs);
	oa << make_nvp(rootLevel, *this);
}
