//------------------------------------------------------------------------------
// <copyright file="GPSListenerSettings.cpp" company="LiquidRobotics">
//
// Copyright (c) 2014 Liquid Robotics, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// This software is associated with a release.  Liquid Robotics makes no
// representation that the design, interfaces or component distribution will
// remain unchanged in future releases.
//
// </copyright>
//
// <summary>
//   Implementation of the GPSListenerSettings class, a serializable entity that
//   holds the configuration values for the GPSListener class
// </summary>
//
// <owner>Mike Cookson</owner>
//------------------------------------------------------------------------------

#include "GPSListenerSettings.h"
#include "LqrSMACLoadSaveBoostXml.h"

using namespace std;
using namespace boost::posix_time;
using namespace LiquidRobotics::EventLib;
using namespace LiquidRobotics::SMACFramework;

namespace LiquidRobotics {
namespace GPSListenerLib {

GPSListenerSettings::GPSListenerSettings()
: maxString(1000)
, readTimeout(milliseconds(25))
, serverName("GPSListener")
//, serverKind("")
, dateSetDirectly(true)
, dateVerb("sudo date --utc {mm}{dd}{HH}{MM}{yyyy}.{SS}")
, hwClockDefault("sudo hwclock -w")
, hwClockVerb(hwClockDefault)
, defaultOuputFileName("sensor.out")
, deltaToSetTime(millisec(100))
, deltaToSetHWClock(seconds(0))
, rmsAccuracyThreshold(50)
, setTimeOnPPS(true)
, ppsGPIO(167)
{
	GPSEventSpec spec;
	gpsEventSpecs.push_back(spec);

	GPSEventSpec spec2(1, 0, "GPSSample1Sec", "GPSSample", "LiquidR-SMC");
	gpsEventSpecs.push_back(spec2);
}

GPSListenerSettings::~GPSListenerSettings()
{
}

const GPSListenerSettings::BaudRateVectorType& GPSListenerSettings::GetBaudRates() const
{
	return tryBaudRates;
}

void GPSListenerSettings::GetBaudRates(BaudRateVectorType& rates) const
{
	rates.assign(tryBaudRates.begin(), tryBaudRates.end());
}

void GPSListenerSettings::SetBaudRates(const BaudRateVectorType& newRates)
{
	tryBaudRates.assign(newRates.begin(), newRates.end());
}

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

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

const SerialPortSettings& GPSListenerSettings::GetPortSettings() const
{
	return serialPortSettings;
}

void GPSListenerSettings::SetPortSettings(const SerialPortSettings& newValue)
{
	serialPortSettings = newValue;
}

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

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

GPSListenerSettings::size_type GPSListenerSettings::GetMaxString() const
{
	return maxString;
}

void GPSListenerSettings::SetMaxString(size_type newValue)
{
	maxString = newValue;
}

GPSListenerSettings::TimeSpan GPSListenerSettings::GetReadTimeout() const
{
	return readTimeout;
}

void GPSListenerSettings::SetReadTimeout(TimeSpan newValue)
{
	readTimeout = newValue;
}

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

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

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

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

const bool GPSListenerSettings::GetDateSetDirectly() const
{
	return dateSetDirectly;
}

void GPSListenerSettings::SetDateSetDirectly(bool newValue)
{
	dateSetDirectly = newValue;
}

const string& GPSListenerSettings::GetDateVerb() const
{
	return dateVerb;
}

void GPSListenerSettings::SetDateVerb(const string& newValue)
{
	dateVerb = newValue;
}

const string& GPSListenerSettings::GetHardwareClockVerb() const
{
	return hwClockVerb;
}

void GPSListenerSettings::SetHardwareClockVerb(const string& newValue)
{
	hwClockVerb = newValue;
}

const string& GPSListenerSettings::GetDefaultOutputFileName() const
{
	return defaultOuputFileName;
}

void GPSListenerSettings::SetDefaultOutputFileName(const string& newValue)
{
	defaultOuputFileName = newValue;
}

const GPSListenerSettings::PayloadManagerClientSettings& GPSListenerSettings::PMClientSettings() const
{
	return pmClientSettings;
}

void GPSListenerSettings::PMClientSettings(const PayloadManagerClientSettings& newValue)
{
	pmClientSettings = newValue;
}

GPSListenerSettings::TimeSpan GPSListenerSettings::GetDeltaToSetTime() const
{
	return deltaToSetTime;
}

void GPSListenerSettings::SetDeltaToSetTime(const TimeSpan& newValue)
{
	deltaToSetTime = newValue;
}

inline double ToSeconds(const timespec& t)
{
	double result = t.tv_sec + t.tv_nsec*1.0e-9;
	return result;
}

bool GPSListenerSettings::ShouldSetTime(const timespec& oldTime, const timespec& newTime) const
{
	const double elapsedSec = ToSeconds(newTime)-ToSeconds(oldTime);
	const bool result = fabs(1000.0*elapsedSec) >= deltaToSetTime.total_milliseconds();
	return result;
}

GPSListenerSettings::TimeSpan GPSListenerSettings::GetDeltaToSetHWClock() const
{
	return deltaToSetHWClock;
}

void GPSListenerSettings::SetDeltaToSetHWClock(const TimeSpan& newValue)
{
	deltaToSetHWClock = newValue;
}

bool GPSListenerSettings::ShouldSetHWClock(bool& previouslySet, double& lastSetSystemUpTime, double currentSystemUpTime) const
{
	const double elapsedSec = currentSystemUpTime-lastSetSystemUpTime;
	const bool result = !previouslySet || (deltaToSetHWClock.total_milliseconds() && (1000.0*elapsedSec >= deltaToSetHWClock.total_milliseconds()));

	if (result)
	{
		previouslySet = true;
		lastSetSystemUpTime = currentSystemUpTime;
	}

	return result;
}

double GPSListenerSettings::GetRMSAccuracyThreshold() const
{
	return rmsAccuracyThreshold;
}

void GPSListenerSettings::SetRMSAccuracyThreshold(double newValue)
{
	rmsAccuracyThreshold = newValue;
}

void GPSListenerSettings::Load(const string& fileName)
{
	LoadBoostXml(fileName, *this);
}

void GPSListenerSettings::Save(const string& fileName)
{
	SaveBoostXml(fileName, *this);
}

const GPSEventSpecArray& GPSListenerSettings::GetGPSEventSpecs() const
{
	return gpsEventSpecs;
}

void GPSListenerSettings::SetGPSEventSpecs(const GPSEventSpecArray& newValue)
{
	gpsEventSpecs.clear();
	gpsEventSpecs.assign(newValue.begin(), newValue.end());
}

bool GPSListenerSettings::GetSetTimeOnPPS() const
{
	return setTimeOnPPS;
}

void GPSListenerSettings::SetSetTimeOnPPS(bool newValue)
{
	setTimeOnPPS = newValue;
}

unsigned GPSListenerSettings::GetPPSGPIO() const
{
	return ppsGPIO;
}

void GPSListenerSettings::SetPPSGPIO(unsigned newValue)
{
	ppsGPIO = newValue;
}

const EventSettings& GPSListenerSettings::GetSystemGPSOfflineSettings() const
{
	return systemGPSOffline;

}

void GPSListenerSettings::SetSystemGPSOfflineSettings(const EventSettings& newValue)
{
	systemGPSOffline = newValue;
}

const EventSettings& GPSListenerSettings::GetSystemGPSOnlineSettings() const
{
	return systemGPSOnline;
}

void GPSListenerSettings::SetSystemGPSOnlineSettings(const EventSettings& newValue)
{
	systemGPSOnline = newValue;
}

const EventSettings& GPSListenerSettings::GetHostGPSSettings() const
{
	return hostGPSEventSettings;
}

void GPSListenerSettings::SetHostGPSSettings(const EventSettings& newValue)
{
	hostGPSEventSettings = newValue;
}

}
}
