//------------------------------------------------------------------------------------------------
// <copyright file="SBGPCTDSampleEvent.h" 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>
//------------------------------------------------------------------------------------------------

#ifndef SBGPCTDSAMPLEEVENT_H_
#define SBGPCTDSAMPLEEVENT_H_

#include "TelemetryEventBase.h"

namespace LiquidRobotics {
namespace SeabirdGPCTD {

/*! \brief CORBA event encapsulation for reporting Seabird GPCTD samples
 *
 *  Instantiate this class to report telemetry or to inform other processes
 *  of a completed reading.  For example (assuming SBGPCTDSensor::Sample in sample):
 *
 *  \code
 *  EventSettings messageName("SBGPCTDSample", "SBGPCTDSampleEvent", "LiquidR-SMC");
 *  SBGPCTDSampleEvent evt(messageName, broker);
 *  const uint16_t myBoardAddress = pmClient->GetMyBoardAddress();   // get my board address from PayloadManagerClient instance
 *  evt.SetGeneratorAddress(myBoardAddress);
 *  evt.SetGenerationLocation(lat, lon);		// use latitude and longitude from GPS
 *  evt.SetReading(sample.condSmStr, sample.condSm, sample.tempCStr, sample.tempC, sample.pressureStr, sample.pressure, sample.disOxyHzStr, sample.disOxyHz);
 *  evt.SetO2Installed(false);
 *  EventTransceiver::TransmitEvent(evt);
 *  \endcode
 *
 *  Note that different message names are used depending on whether there is an O2
 *  sensor installed.
 *
 *  If receiving an event, you can use this code in the Program role class (with
 *  EventTransceiver as a base class) to subscribe to an event, have the base class
 *  create it using the wrapper and then up-cast the event in the callback:
 *
 *  \code
 *  void MyProgram::Initialize(Object_ptr serverRef)
 *  {
 *  	EventTransceiver::Initialize(serverRef);
 *
 *  	// ... other initializations ...
 *
 *  	// shortcut to GPCTD sample event settings
 *  	const EventSettings& gpctdSampleEvent = config.GetGPCTDSampleSettings();
 *
 *		// creates a class factory that creates a SBGPCTDSampleEvent whenever
 *		// an event is received with a type matching the settings (rather than
 *		// just basing it on as a basic event)
 *  	RegisterEventClassFactory(gpctdSampleEvent.GetType(),
 *  		new EventTransceiver::TEventClassFactory<SBGPCTDSampleEvent>);
 *
 *  	// creates a signal to subscribe to for call-backs based on the event name
 *  	InformSignalType& gpctdSignal = SignalForEventName(gpctdSampleEvent.GetName());
 *
 *  	// defines a callback (OnGPCTD) and subscribes
 *  	connectionTOGPCTDSample.reset(
 *  		new ScopedConnection(gpctdSignal, boost::bind(&MyProgram::OnGPCTD, this, _1, _2)) );
 *
 *		// ... complete initialization ...
 *  }
 *
 *  void MyProgram::OnGPCTD(EventTransceiver& sender, const IEventBase& receivedEvent)
 *  {
 *		const EventSettings& gpctdSampleEvent = config.GetGPCTDSampleSettings();
 *		const SBGPCTDSampleEvent& evt =
 *			UpcastEventRef<SBGPCTDSampleEvent>(receivedEvent, gpctdSampleEvent, "MyProgram::OnGPCTD");
 *		// ... use evt's methods to access the data ...
 *  }
 *  \endcode
 */
class SHARED_LIB_PUBLIC SBGPCTDSampleEvent : public LiquidRobotics::EventLib::TelemetryEventBase
{
public:

	//! Shortcut to the base class
	typedef LiquidRobotics::EventLib::TelemetryEventBase Base;

	//! Define a short-cut for EventLib's EventSettings class (don't want "using namespace" in header files)
	typedef LiquidRobotics::EventLib::EventSettings EventSettings;

	//! Define a short-cut for string (don't want "using namespace" in header files)
	typedef std::string string;

	/*! \brief Constructor only specifying object broker
	 */
	SBGPCTDSampleEvent(
			IObjectBroker& _broker					/**< [in] Reference to the CORBA object broker wrapper to be used */
			);
	/*! \brief Constructor specifying EventSettings and object broker (most typical)
	 */
	SBGPCTDSampleEvent(
			const EventSettings& _eventSettings,	/**< [in] Name and type to assign to event */
			IObjectBroker& _broker					/**< [in] Reference to the CORBA object broker wrapper to be used */
			);
	/*! \brief Constructor specifying event name and type separately along with object broker
	 */
	SBGPCTDSampleEvent(
			const EventName& _eventName,			/**< [in] Event name to assign */
			const EventType& _eventType,			/**< [in] Event type to assign */
			IObjectBroker& _broker					/**< [in] Reference to the CORBA object broker wrapper to be used */
			);
	/*! \brief Constructor specifying event name and type separately along with the sender's IOR (string ID of proxy) and object broker
	 */
	SBGPCTDSampleEvent(
			const EventName& _eventName,			/**< [in] Event name to assign */
			const EventType& _eventType,			/**< [in] Event type to assign */
			const IOR& _senderIOR,					/**< [in] CORBA IOR (string ID of proxy) to sender */
			IObjectBroker& _broker					/**< [in] Reference to the CORBA object broker wrapper to be used */
			);
	/*! \brief Copy constructor
	 */
	SBGPCTDSampleEvent(
			const SBGPCTDSampleEvent& other			/**< [in] Reference to another instance of the event to be copied */
			);

	/*! \brief Derived class specialization that describes the instance
	 *  \returns The stream reference that was passed in
	 *
	 *  Overrides the base class method.
	 */
	virtual ostream& Describe(
			ostream& stm							/**< [in] The stream to describe the object to */
			) const;

	/*! \brief Duplicates the instance, creating a new copy of the derived class
	 *  \returns A new SBGPCTDSampleEvent that duplicates the content of this instance (as a smart pointer)
	 *
	 *  Overrides the base class method.  This allows another copy of the most derived
	 *  class to the duplicate the event while holding only a pointer to the base
	 *  class.
	 */
	virtual IEventBase::Ptr Duplicate() const;

	/*! \brief Tests if the event has a reading attached
	 *  \returns true if the event has a reading (GetReading() will not throw), false if the event does not have a reading (GetReading() will throw)
	 */
	bool HasReading() const;

	/*! \brief Reads the components of the GPCTD reading into variables
	 *
	 *  Note that the values are returned in decimal engineering units
	 */
	void GetReading(
			string& conductivityStr,				/**< [out] The conductivity component from the sensor (literal text) */
			float& conductivity,					/**< [out] The conductivity component from the sensor (converted from literal text; NaN if unable to convert */
			string& temperatureStr,					/**< [out] The temperature component from the sensor (literal text) */
			float& temperature,						/**< [out] The temperature component from the sensor (converted from literal text; NaN if unable to convert */
			string& pressureStr,					/**< [out] The pressure component from the sensor (literal text) */
			float& pressure,						/**< [out] The pressure component from the sensor (converted from literal text; NaN if unable to convert */
			string& dissolvedOxygenStr,				/**< [out] The dissolved oxygen component from the sensor (literal text) */
			float& dissolvedOxygen					/**< [out] The dissolved oxygen component from the sensor (converted from literal text; NaN if unable to convert or sensor not installed */
			) const;

	/*! \brief Sets the components of the GPCTD reading
	 *
	 *  Note that the values are expected to be in decimal engineering units
	 */
	void SetReading(
			const string& conductivityStr,			/**< [in] The conductivity component from the sensor (literal text) */
			float conductivity,						/**< [in] The conductivity component from the sensor (converted from literal text; NaN if unable to convert */
			const string& temperatureStr,			/**< [in] The temperature component from the sensor (literal text) */
			float temperature,						/**< [in] The temperature component from the sensor (converted from literal text; NaN if unable to convert */
			const string& pressureStr,				/**< [in] The pressure component from the sensor (literal text) */
			float pressure,							/**< [in] The pressure component from the sensor (converted from literal text; NaN if unable to convert */
			const string& dissolvedOxygenStr,		/**< [in] The dissolved oxygen component from the sensor (literal text) */
			float dissolvedOxygen					/**< [in] The dissolved oxygen component from the sensor (converted from literal text; NaN if unable to convert or not installed */
			);

	/*! \brief Reads the "dissolved oxygen sensor installed" flag
	 *  \returns true if the dissolved oxygen sensor is installed, false if the dissolved oxygen sensor is not installed (or the flag was never set)
	 */
	bool GetO2Installed() const;

	/*! \brief Sets the "dissolved oxygen sensor installed" flag
	 */
	void SetO2Installed(
			bool isInstalled = true				/**< [in] true (default) if the dissolved oxygen sensor is installed, false if it is not installed */
			);

private:

	static const PropertyNameType ConductivityStrTag;		//!< CORBA event field name of the conductivity component (literal text string)
	static const PropertyNameType ConductivityRawTag;		//!< CORBA event field name of conductivity in hexadecimal engineering units calculated during the SetReading() operation (NaN decimal engineering value is NaN, float)
	static const PropertyNameType ConductivityTag;			//!< CORBA event field name of the conductivity component (decimal engineering units, NaN if could not convert from text, float)
	static const PropertyNameType TemperatureStrTag;		//!< CORBA event field name of the temperature component (literal text string)
	static const PropertyNameType TemperatureRawTag;		//!< CORBA event field name of temperature in  hexadecimal engineering units calculated during the SetReading() operation (NaN decimal engineering value is NaN, float)
	static const PropertyNameType TemperatureTag;			//!< CORBA event field name of the temperature component (decimal engineering units, NaN if could not convert from text, float)
	static const PropertyNameType PressureStrTag;			//!< CORBA event field name of the pressure component (literal text string)
	static const PropertyNameType PressureRawTag;			//!< CORBA event field name of pressure in  hexadecimal engineering units calculated during the SetReading() operation (NaN decimal engineering value is NaN, float)
	static const PropertyNameType PressureTag;				//!< CORBA event field name of the pressure component (decimal engineering units, NaN if could not convert from text, float)
	static const PropertyNameType DissolvedOxygenStrTag;	//!< CORBA event field name of the dissolved oxygen component (literal text string)
	static const PropertyNameType DissolvedOxygenRawTag;	//!< CORBA event field name of dissolved oxygen in  hexadecimal engineering units calculated during the SetReading() operation (NaN decimal engineering value is NaN, float)
	static const PropertyNameType DissolvedOxygenTag;		//!< CORBA event field name of the dissolved oxygen component (decimal engineering units, NaN if could not convert from text, float)
	static const PropertyNameType O2InstalledTag;			//!< CORBA event field name of the "dissolved oxygen sensor installed" flag (boolean)
};

}
}

#endif /* SBGPCTDSAMPLEEVENT_H_ */
