//-------------------------------------------------------------------------------------
// <copyright file="TelemetrySettingsChangedEvent.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 TelemetrySettingsChangedEvent, an IEventBase-derived class that
//   defines the data fields for an event that announces changes in telemetry settings.
// </summary>
//
// <owner>Mike Cookson</owner>
//-------------------------------------------------------------------------------------

#include "TelemetrySettingsChangedEvent.h"
#include <sstream>

using namespace std;

namespace LiquidRobotics {
namespace EventLib {

const TelemetrySettingsChangedEvent::PropertyNameType TelemetrySettingsChangedEvent::formatCodeTag = "TelemChanged-FormatCode";
const TelemetrySettingsChangedEvent::PropertyNameType TelemetrySettingsChangedEvent::pendingMessageTreatmentTag = "TelemChanged-PendingMessageTreatment";
const TelemetrySettingsChangedEvent::PropertyNameType TelemetrySettingsChangedEvent::maxSamplesTag = "TelemChanged-MaxSamples";
const TelemetrySettingsChangedEvent::PropertyNameType TelemetrySettingsChangedEvent::maxRetainTimeTag = "TelemChanged-MaxRetainTime";

TelemetrySettingsChangedEvent::TelemetrySettingsChangedEvent(IObjectBroker& _broker)
: TelemetryEventBase(_broker)
{
}

TelemetrySettingsChangedEvent::TelemetrySettingsChangedEvent(const EventSettings& _eventSettings, IObjectBroker& _broker)
: TelemetryEventBase(_eventSettings, _broker)
{
}

TelemetrySettingsChangedEvent::TelemetrySettingsChangedEvent(const EventName& _eventName, const EventType& _eventType, IObjectBroker& _broker)
: TelemetryEventBase(_eventName, _eventType, _broker)
{
}

TelemetrySettingsChangedEvent::TelemetrySettingsChangedEvent(const EventName& _eventName, const EventType& _eventType, const IOR& _senderIOR, IObjectBroker& _broker)
: TelemetryEventBase(_eventName, _eventType, _senderIOR, _broker)
{
}

TelemetrySettingsChangedEvent::TelemetrySettingsChangedEvent(const TelemetrySettingsChangedEvent& other)
: TelemetryEventBase(other)
{
}

ostream& TelemetrySettingsChangedEvent::Describe(ostream& stm) const
{
	TelemetryEventBase::Describe(stm);

	stm << " format-code=" << ((unsigned) GetFormatCode())
	    << " " << ToString(GetPendingMessageTreatment());

	if (HaveMaxSamples())
		stm << " max-samples=" << GetMaxSamples();

	if (HaveMaxRetainTime())
		stm << " max-retain-time=" << GetMaxRetainTime();

	return stm;
}

IEventBase::Ptr TelemetrySettingsChangedEvent::Duplicate() const
{
	IEventBase::Ptr result;
	result.reset(new TelemetrySettingsChangedEvent(*this));

	return result;
}

uint8_t TelemetrySettingsChangedEvent::GetFormatCode() const
{
	uint8_t result = 0;

	if (ContainsProperty(formatCodeTag))
		result = GetProperty(formatCodeTag).GetUInt8();

	return result;
}

void TelemetrySettingsChangedEvent::SetFormatCode(uint8_t newValue)
{
	PropertyValueType fc(broker);
	fc.SetUInt8(newValue);

	SetProperty(formatCodeTag, fc);
}

TelemetrySettingsChangedEvent::PendingMessageTreatment TelemetrySettingsChangedEvent::GetPendingMessageTreatment() const
{
	PendingMessageTreatment result = PMT_PUBLISH;

	if (ContainsProperty(pendingMessageTreatmentTag))
	{
		const PropertyValueType& prop = GetProperty(pendingMessageTreatmentTag);

		switch(sizeof(PendingMessageTreatment))
		{
		case 1:		result = (PendingMessageTreatment) prop.GetUInt8();			break;
		case 2:		result = (PendingMessageTreatment) prop.GetUInt16();		break;
		case 4:		result = (PendingMessageTreatment) prop.GetUInt32();		break;
		default:	throw runtime_error("Unhandled case for size of PendingMessageTreatment in GetPendingMessageTreatment");
		}
	}

	return result;
}

void TelemetrySettingsChangedEvent::SetPendingMessageTreatment(PendingMessageTreatment newValue)
{
	PropertyValueType pmt(broker);

	switch(sizeof(PendingMessageTreatment))
	{
	case 1:		pmt.SetUInt8(newValue);			break;
	case 2:		pmt.SetUInt16(newValue);		break;
	case 4:		pmt.SetUInt32(newValue);		break;
	default:	throw runtime_error("Unhandled case for size of PendingMessageTreatment in SetPendingMessageTreatment");
	}

	SetProperty(pendingMessageTreatmentTag, pmt);
}

void TelemetrySettingsChangedEvent::ClearMaxSamples()
{
	if (ContainsProperty(maxSamplesTag))	ClearProperty(maxSamplesTag);
}

uint16_t TelemetrySettingsChangedEvent::GetMaxSamples() const
{
	return GetProperty(maxSamplesTag).GetUInt16();
}

bool TelemetrySettingsChangedEvent::HaveMaxSamples() const
{
	return ContainsProperty(maxSamplesTag);
}

void TelemetrySettingsChangedEvent::SetMaxSamples(uint16_t newValue)
{
	PropertyValueType maxSamples(broker);

	maxSamples.SetUInt16(newValue);
	SetProperty(maxSamplesTag, maxSamples);
}

void TelemetrySettingsChangedEvent::ClearMaxRetainTime()
{
	if (ContainsProperty(maxRetainTimeTag))		ClearProperty(maxRetainTimeTag);
}

time_t TelemetrySettingsChangedEvent::GetMaxRetainTime() const
{
	return (time_t) GetProperty(maxRetainTimeTag).GetUInt32();
}

bool TelemetrySettingsChangedEvent::HaveMaxRetainTime() const
{
	return ContainsProperty(maxRetainTimeTag);
}

void TelemetrySettingsChangedEvent::SetMaxRetainTime(time_t newValue)
{
	PropertyValueType maxRetainTime(broker);

	maxRetainTime.SetUInt32(newValue);
	SetProperty(maxRetainTimeTag, maxRetainTime);
}

void TelemetrySettingsChangedEvent::FromString(const string& str, PendingMessageTreatment& pmt)
{
	if (boost::iequals(str, "PMT_RETAIN"))
		pmt = PMT_RETAIN;
	else if (boost::iequals(str, "PMT_PUBLISH"))
		pmt = PMT_PUBLISH;
	else if (boost::iequals(str, "PMT_CLEAR"))
		pmt = PMT_CLEAR;
	else
	{
		stringstream msg;
		msg << "Could not decode '" << str << "' as a PendingMessageTreatment";
		throw invalid_argument(msg.str());
	}
}

string TelemetrySettingsChangedEvent::ToString(const PendingMessageTreatment& pmt)
{
	string result;

	switch(pmt)
	{
	case PMT_RETAIN:		result = "PMT_RETAIN";			break;
	case PMT_PUBLISH:		result = "PMT_PUBLISH";			break;
	case PMT_CLEAR:			result = "PMT_CLEAR";			break;

	default:
		{
			stringstream msg;
			msg << ((int) pmt) << "?";
			result = msg.str();
			break;
		}
	}

	return result;
}

}
}
