//------------------------------------------------------------------------------------------------
// <copyright file="SBGPCTDSampleEvent.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>
// 	Declaration of SBGPCTDSampleEvent, which declares the wrapper class for the CORBA message that
//  wraps the GPCTD telemetry report
// </summary>
//
// <owner>Mike Cookson</owner>
//------------------------------------------------------------------------------------------------

#include "SBGPCTDSampleEvent.h"
#include "LqrSMACBooleanParser.h"
#include <cmath>

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

namespace LiquidRobotics {
namespace SeabirdGPCTD {

#define EVENT_PREFIX "SBGPCTDSample_"
#if 0
<columns>
<column type="id">PayloadPacketRecordId</column>
<column type="bound" width="160px" sort="0">TimeStamp</column>
<column type="related" entitytype="48" width="120px">VehicleId</column>
<column type="bound" width="120px">Latitude</column>
<column type="bound" width="120px">Longitude</column>
<column type="calculated" width="120px" method="bytefield|int|0|4|0.01|-10" name="Pressure">RecordData</column>
<column type="calculated" width="120px" method="bytefield|int|4|4|0.0001|-5" name="Temperature">RecordData</column>
<column type="calculated" width="120px" method="bytefield|int|8|4|0.00001|-0.05" name="Conductivity">RecordData</column>
<column type="calculated" width="120px" method="bytefield|int|12|4|0.1|0" name="Oxygen">RecordData</column>
<column type="bound" width="240px" name="Payload Data">RecordData</column>
</columns>
#endif

const SBGPCTDSampleEvent::PropertyNameType SBGPCTDSampleEvent::ConductivityStrTag = EVENT_PREFIX "ConductivityStr";
const SBGPCTDSampleEvent::PropertyNameType SBGPCTDSampleEvent::ConductivityRawTag = EVENT_PREFIX "RawConductivity";
const SBGPCTDSampleEvent::PropertyNameType SBGPCTDSampleEvent::ConductivityTag = EVENT_PREFIX "Conductivity";
const SBGPCTDSampleEvent::PropertyNameType SBGPCTDSampleEvent::TemperatureStrTag = EVENT_PREFIX "TemperatureStr";
const SBGPCTDSampleEvent::PropertyNameType SBGPCTDSampleEvent::TemperatureRawTag = EVENT_PREFIX "RawTemperature";
const SBGPCTDSampleEvent::PropertyNameType SBGPCTDSampleEvent::TemperatureTag = EVENT_PREFIX "Temperature";
const SBGPCTDSampleEvent::PropertyNameType SBGPCTDSampleEvent::PressureStrTag = EVENT_PREFIX "PressureStr";
const SBGPCTDSampleEvent::PropertyNameType SBGPCTDSampleEvent::PressureRawTag = EVENT_PREFIX "RawPressure";
const SBGPCTDSampleEvent::PropertyNameType SBGPCTDSampleEvent::PressureTag = EVENT_PREFIX "Pressure";
const SBGPCTDSampleEvent::PropertyNameType SBGPCTDSampleEvent::DissolvedOxygenStrTag = EVENT_PREFIX "DissolvedOxygenStr";
const SBGPCTDSampleEvent::PropertyNameType SBGPCTDSampleEvent::DissolvedOxygenRawTag = EVENT_PREFIX "RawDissolvedOxygen";
const SBGPCTDSampleEvent::PropertyNameType SBGPCTDSampleEvent::DissolvedOxygenTag = EVENT_PREFIX "DissolvedOxygen";
const SBGPCTDSampleEvent::PropertyNameType SBGPCTDSampleEvent::O2InstalledTag = EVENT_PREFIX "O2Installed";

SBGPCTDSampleEvent::SBGPCTDSampleEvent(IObjectBroker& _broker)
: Base(_broker)
{
}

SBGPCTDSampleEvent::SBGPCTDSampleEvent(const EventSettings& _eventSettings, IObjectBroker& _broker)
: Base(_eventSettings, _broker)
{
}

SBGPCTDSampleEvent::SBGPCTDSampleEvent(const EventName& _eventName, const EventType& _eventType, IObjectBroker& _broker)
: Base(_eventName, _eventType, _broker)
{
}

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

SBGPCTDSampleEvent::SBGPCTDSampleEvent(const SBGPCTDSampleEvent& other)
: Base(other)
{
}

ostream& SBGPCTDSampleEvent::Describe(ostream& stm) const
{
	Base::Describe(stm);

	if (HasReading())
	{
		string cs, ts, ps, os;
		float c, t, p, o;
		GetReading(cs, c, ts, t, ps, p, os, o);
		stm << " conductivityStr=" << cs << " conductivity=" << c
			<< " temperatureStr=" << ts << " temperature=" << t
			<< " pressureStr=" << ps << " pressure=" << p
			<< " dissolvedOxygenStr=" << os << " dissolvedOxygen=" << o;
	}

	stm << " o2Installed=" << BooleanToString(GetO2Installed());
	return stm;
}

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

	return result;
}

bool SBGPCTDSampleEvent::HasReading() const
{
    return ContainsProperty(ConductivityStrTag)
       	 && ContainsProperty(ConductivityRawTag)
    	 && ContainsProperty(ConductivityTag)
    	 && ContainsProperty(TemperatureStrTag)
    	 && ContainsProperty(TemperatureRawTag)
    	 && ContainsProperty(TemperatureTag)
    	 && ContainsProperty(PressureStrTag)
    	 && ContainsProperty(PressureRawTag)
    	 && ContainsProperty(PressureTag)
    	 && ContainsProperty(DissolvedOxygenStrTag)
    	 && ContainsProperty(DissolvedOxygenRawTag)
	     && ContainsProperty(DissolvedOxygenTag);
}

void SBGPCTDSampleEvent::GetReading(
		string& conductivityStr, float& conductivity,
		string& temperatureStr, float& temperature,
		string& pressureStr, float& pressure,
		string& dissolvedOxygenStr, float& dissolvedOxygen) const
{
	conductivityStr = GetProperty(ConductivityStrTag).GetString();
	conductivity = GetProperty(ConductivityTag).GetSingleFloat();
	temperatureStr = GetProperty(TemperatureStrTag).GetString();
	temperature = GetProperty(TemperatureTag).GetSingleFloat();
	pressureStr = GetProperty(PressureStrTag).GetString();
	pressure = GetProperty(PressureTag).GetSingleFloat();
	dissolvedOxygenStr = GetProperty(DissolvedOxygenStrTag).GetString();
	dissolvedOxygen = GetProperty(DissolvedOxygenTag).GetSingleFloat();
}

inline float ReplaceNAN(float value)
{
	if (isnan(value))
		value = -99.0;
	return value;
}

inline int32_t ConvertToRaw(float value, float factor, float offset)
{
	const int32_t result = floor(factor*(ReplaceNAN(value)+offset));
	return result;
}

void SBGPCTDSampleEvent::SetReading(
		const string& conductivityStr, float conductivity,
		const string& temperatureStr, float temperature,
		const string& pressureStr, float pressure,
		const string& dissolvedOxygenStr, float dissolvedOxygen)
{
	{ EventPropertyValue epv(broker); epv.SetString(conductivityStr); SetProperty(ConductivityStrTag, epv); }
	{ EventPropertyValue epv(broker); epv.SetString(temperatureStr); SetProperty(TemperatureStrTag, epv); }
	{ EventPropertyValue epv(broker); epv.SetString(pressureStr); SetProperty(PressureStrTag, epv); }
	{ EventPropertyValue epv(broker); epv.SetString(dissolvedOxygenStr); SetProperty(DissolvedOxygenStrTag, epv); }
	{ EventPropertyValue epv(broker); epv.SetSingleFloat(conductivity); SetProperty(ConductivityTag, epv); }
	{ EventPropertyValue epv(broker); epv.SetSingleFloat(temperature); SetProperty(TemperatureTag, epv); }
	{ EventPropertyValue epv(broker); epv.SetSingleFloat(pressure); SetProperty(PressureTag, epv); }
	{ EventPropertyValue epv(broker); epv.SetSingleFloat(dissolvedOxygen); SetProperty(DissolvedOxygenTag, epv); }

	// the event wrapper requires real engineering units, but the Seabird GPCTD returns the data in modified format,
	// and WGMS uses these raw units instead of real values.  I'm adding tags for these "raw" readings.
	{ EventPropertyValue epv(broker); epv.SetInt32(ConvertToRaw(conductivity, 100000, 0.05)); SetProperty(ConductivityRawTag, epv); }
	{ EventPropertyValue epv(broker); epv.SetInt32(ConvertToRaw(temperature, 10000, 5)); SetProperty(TemperatureRawTag, epv); }
	{ EventPropertyValue epv(broker); epv.SetInt32(ConvertToRaw(pressure, 100, 10)); SetProperty(PressureRawTag, epv); }
	{ EventPropertyValue epv(broker); epv.SetInt32(ConvertToRaw(dissolvedOxygen, 10, 0)); SetProperty(DissolvedOxygenRawTag, epv); }
}

bool SBGPCTDSampleEvent::GetO2Installed() const
{
	bool result = ContainsProperty(O2InstalledTag) && GetProperty(O2InstalledTag).GetBoolean();
	return result;
}

void SBGPCTDSampleEvent::SetO2Installed(bool isInstalled)
{
	EventPropertyValue epv(broker);
	epv.SetBoolean(isInstalled);
	SetProperty(O2InstalledTag, epv);
}

}
}




