//------------------------------------------------------------------------------------------------
// <copyright file="SBGPCTDControllerPersistSettings.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 SBGPCTDControllerPersistSettings, a serializable entity class that contains the
//  runtime-configurable persistent settings for an instance of SBGPCTDController
// </summary>
//
// <owner>Mike Cookson</owner>
//------------------------------------------------------------------------------------------------

#ifndef SBGPCTDCONTROLLERPERSISTSETTINGS_H_
#define SBGPCTDCONTROLLERPERSISTSETTINGS_H_

#include <boost/serialization/access.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/version.hpp>
#include "LqrSMACBooleanParser.h"
#include "LqrSMACSharedLib.h"
#include <boost/shared_ptr.hpp>
#include <string>

namespace LiquidRobotics {
namespace SeabirdGPCTD {

/*! \brief A serializable entity that holds the runtime-configurable settings for SBGPCTDController
 *  \sa SBGPCTDController, SBGPCTDControllerSettings
 */
class SHARED_LIB_PUBLIC SBGPCTDControllerPersistSettings
{
public:

	//! Smart pointer to this class
	typedef boost::shared_ptr<SBGPCTDControllerPersistSettings> Ptr;

	//! Weak reference to this class
	typedef boost::weak_ptr<SBGPCTDControllerPersistSettings> WPtr;

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

	/*! \brief Class constructor
	 *
	 * Sets default values for the various settings; no default archive path is
	 * specified
	 */
	SBGPCTDControllerPersistSettings();

	/*! \brief Class constructor with specified default path to archive file
	 *
	 * Sets default values for the various settings, but doesn't load settings from
	 * the path.
	 */
	SBGPCTDControllerPersistSettings(
			const string& _settingsPath		/**< [in] Default path/filename to use when reading settings from a file */
			);

	/*! \brief Class destructor
	 */
	virtual ~SBGPCTDControllerPersistSettings();

	/*! \brief Read "auto run" property
	 *  \sa SetAutoRun()
	 *
	 *  In "auto run" mode (true), the sensor attempts to start polling as soon as the
	 *  program starts.
	 */
	bool GetAutoRun() const;

	/*! \brief Sets the "auto run" property to a new value
	 *  \sa GetAutoRun()
	 *
	 *  In "auto run" mode (true), the sensor attempts to start polling as soon as the
	 *  program starts.
	 */
	void SetAutoRun(
			bool newValue					/** < [in] The new value for the "auto run" property */
			);

	/*! \brief Read the duty cycle time (off time), in seconds
	 *  \sa SetDutyCycleSec(), GetFlushTimeSec(), SetFlushTimeSec()
	 *
	 *  If the duty cycle time (off time) is non-zero, the sensor is powered off between
	 *  batches of readings, as long as the duty cycle time is longer than the flush time.
	 *  program starts.
	 */
	unsigned GetDutyCycleSec() const;

	/*! \brief Set the duty cycle time (off time) to a new value (seconds)
	 *  \sa GetDutyCycleSec(), GetFlushTimeSec(), SetFlushTimeSec()
	 *
	 *  If the duty cycle time (off time) is non-zero, the sensor is powered off between
	 *  batches of readings, as long as the duty cycle time is longer than the flush time.
	 *  program starts.
	 */
	void SetDutyCycleSec(
			unsigned newValue				/**< [in] The new value for duty cycle (seconds); 0=sensor does not turn off between batches */
			);

	/*! \brief Read the flush time, in seconds
	 *  \sa SetFlushTimeSec(), GetDutyCycleSec(), SetDutyCycleSec()
	 *
	 *  The flush time is the time period that the pump is turned on at high speed at the
	 *  start of each batch of readings (unless the off time is zero, in which case the
	 *  line is not flushed again.)
	 */
	unsigned GetFlushTimeSec() const;

	/*! \brief Set the flush time to a new value (seconds)
	 *  \sa GetFlushTimeSec(), GetDutyCycleSec(), SetDutyCycleSec()
	 *
	 *  The flush time is the time period that the pump is turned on at high speed at the
	 *  start of each batch of readings (unless the off time is zero, in which case the
	 *  line is not flushed again.)
	 */
	void SetFlushTimeSec(
			unsigned newValue				/**< [in] The new value to set for flush time */
			);

	/*! \brief Get the "logging enabled" property
	 *  \returns true if logging is enabled, false if logging is not enabled
	 *  \sa SetLoggingEnabled(), GetRawLoggingEnabled(), SetRawLoggingEnabled()
	 *
	 * When logging is enabled (true), samples are stored to the configured log file set;
	 * otherwise (false), samples are not stored locally on the SMC.
	 */
	bool GetLoggingEnabled() const;

	/*! \brief Set the "logging enabled" property
	 *  \sa GetLoggingEnabled(), GetRawLoggingEnabled(), SetRawLoggingEnabled()
	 *
	 * When logging is enabled (true), samples are stored to the configured log file set;
	 * otherwise (false), samples are not stored locally on the SMC.
	 */
	void SetLoggingEnabled(
			bool newValue				/**< [in] true if samples should be logged, false if samples should not be logged */
			);

	/*! \brief Get the "raw logging enabled" property
	 *  \returns true if raw logging is enabled, false if raw logging is not enabled
	 *  \sa SetRawLoggingEnabled(), GetLoggingEnabled(), SetLoggingEnabled()
	 *
	 * When raw logging is enabled (true), individual reads and writes that the
	 * interface makes to the sensor are logged locally; otherwise (false), this
	 * data is not stored locally on the SMC.
	 */
	bool GetRawLoggingEnabled() const;

	/*! \brief Set the "raw logging enabled" property
	 *  \sa GetRawLoggingEnabled(), GetLoggingEnabled(), SetLoggingEnabled()
	 *
	 * When raw logging is enabled (true), individual reads and writes that the
	 * interface makes to the sensor are logged locally; otherwise (false), this
	 * data is not stored locally on the SMC.
	 */
	void SetRawLoggingEnabled(
			bool newValue			/**< [in] true if raw reads and writes are logged, false if not */
			);

	/*! \brief Get the "report block size" property
	 *  \returns The number of samples per telemetry report
	 *  \sa SetReportBlockSize()
	 *
	 * Multiple samples can be reported per telemetry message, and this property
	 * configures that size.  It also configures the number of samples that are
	 * taken before the duty cycle time applies.
	 */
	unsigned GetReportBlockSize() const;

	/*! \brief Set the "report block size" property
	 *  \sa GetReportBlockSize()
	 *
	 * Multiple samples can be reported per telemetry message, and this property
	 * configures that size.  It also configures the number of samples that are
	 * taken before the duty cycle time applies.
	 */
	void SetReportBlockSize(
			unsigned newValue		/**< [in] The number of samples aggregated into a single telemetry message; also the number of samples taken before duty cycling */
			);

	/*! \brief Get the "sample period" property
	 *  \returns The number of of seconds between samples during the sampling period
	 *  \sa SetSamplePeriodSec()
	 *
	 * This value is sent to the sensor as the automatic sampling interval ("interval")
	 */
	unsigned GetSamplePeriodSec() const;

	/*! \brief Set the "sample period" property
	 *  \sa GetSamplePeriodSec()
	 *
	 * This value is sent to the sensor as the automatic sampling interval ("interval")
	 */
	void SetSamplePeriodSec(
			unsigned newValue		/**< [in] The number of seconds between samples during sampling (the sensor's "interval" variable) */
			);

	/*! \brief Load the settings from the XML file (constructor parameter)
	 *  \sa Load(const string& fileName), Save(), Save(const string& filenName), load()
	 *
	 *  An exception is thrown if the expected file does not exist.  If it exists, but
	 *  it is empty (zero length), the default format is written: this is helpful when
	 *  changes in the schema have occurred, or the schema is not known.  This method
	 *  also compares the file to what would be written with the Save method variants,
	 *  and if there is a difference, the new format is written to a ".upgraded" file.
	 */
	void Load();

	/*! \brief Load the settings from the XML file at the given path
	 *  \sa Load(const string& fileName), Save(), Save(const string& filenName), load()
	 *
	 *  An exception is thrown if the expected file does not exist.  If it exists, but
	 *  it is empty (zero length), the default format is written: this is helpful when
	 *  changes in the schema have occurred, or the schema is not known.  This method
	 *  also compares the file to what would be written with the Save method variants,
	 *  and if there is a difference, the new format is written to a ".upgraded" file.
	 */
	void Load(
			const string& fileName		/**< [in] The name/path of the XML file to load from */
			);

	/*! \brief Save the settings to the XML file (constructor parameter)
	 *  \sa Load(), Load(const string& fileName), Save(const string& filenName), save()
	 */
	void Save() const;

	/*! \brief Save the settings to the XML file at the given path
	 *  \sa Load(), Load(const string& fileName), Save(const string& filenName), save()
	 */
	void Save(
			const string& fileName		/**< [in] The name/path of the XML file to save to */
			) const;

	/*! \brief Sets the variables to the default settings
	 *  \sa Load(), Load(const string& fileName), Save(), Save(const string& fileName)
	 */
	void SetDefaults();

private:

	//! Allows the Boost Serialization library to access private load() and save()
	friend class boost::serialization::access;

	/*! \brief Boost serialization method for reading data from an archive file
	 *  \sa Load(), Load(const string& fileName), save(), BOOST_CLASS_VERSION()
	 *
	 *  The archive type is kept generic, but this method was created for use with
	 *  an XML archive.  The load() function can inspect the version variable and
	 *  customize its behavior to remain backward-compatible.
	 */
	template<class Archive>
	void load(
			Archive & ar,						/**< [in] Reference on the archive to load from */
			const unsigned int version		/**< [in] Version of the schema being read */
			)
	{
		using namespace LiquidRobotics::SMACFramework;
		string autoRunStr;
		ar & BOOST_SERIALIZATION_NVP(autoRunStr);
		autoRun = StringToBoolean(autoRunStr);
		ar & BOOST_SERIALIZATION_NVP(dutyCycleSec);
		ar & BOOST_SERIALIZATION_NVP(flushTimeSec);
		string loggingEnabledStr;
		ar & BOOST_SERIALIZATION_NVP(loggingEnabledStr);
		loggingEnabled = StringToBoolean(loggingEnabledStr);
		string rawLoggingEnabledStr;
		ar & BOOST_SERIALIZATION_NVP(rawLoggingEnabledStr);
		rawLoggingEnabled = StringToBoolean(rawLoggingEnabledStr);
		ar & BOOST_SERIALIZATION_NVP(reportBlockSize);
		ar & BOOST_SERIALIZATION_NVP(samplePeriodSec);
	}

	/*! \brief Boost Serialization library compatible method for storing data to an archive file
	 *  \sa Save(), Save(const string& fileName), load(), BOOST_CLASS_VERSION()
	 *
	 *  The archive type is kept generic, but this method was created for use with
	 *  an XML archive.  The save() function always writes the latest version of
	 *  of the schema.
	 */
	template<class Archive>
	void save(
			Archive & ar, 						/**< [in] Reference on the archive to save to */
			const unsigned int version		/**< [in] Version of the schema being written */
			) const
	{
		using namespace LiquidRobotics::SMACFramework;
		const string autoRunStr = BooleanToString(autoRun);
		ar & BOOST_SERIALIZATION_NVP(autoRunStr);
		ar & BOOST_SERIALIZATION_NVP(dutyCycleSec);
		ar & BOOST_SERIALIZATION_NVP(flushTimeSec);
		const string loggingEnabledStr = BooleanToString(loggingEnabled);
		ar & BOOST_SERIALIZATION_NVP(loggingEnabledStr);
		const string rawLoggingEnabledStr = BooleanToString(rawLoggingEnabled);
		ar & BOOST_SERIALIZATION_NVP(rawLoggingEnabledStr);
		ar & BOOST_SERIALIZATION_NVP(reportBlockSize);
		ar & BOOST_SERIALIZATION_NVP(samplePeriodSec);
	}

	//! Inidcates to use separate load() and save() methods instead of a single serialize() method;
	//! this is needed particularly if there are multiple schemas to detect during load
	BOOST_SERIALIZATION_SPLIT_MEMBER()

	const string settingsPath;			//!< Copy of the constructor parameter for the XML file to use, by default
	bool autoRun;						//!< true if automatically starting background sampling, false if not
	unsigned dutyCycleSec;				//!< Number of seconds to wait with power off between sampling periods
	unsigned flushTimeSec;				//!< The number of seconds to flush the line at fast speed between sample periods or when starting to sample
	bool loggingEnabled;				//!< true if local logging of samples is enabled, false if not
	bool rawLoggingEnabled;				//!< true if local logging of data transmitted or received from the sensor is enabled, false if not
	unsigned reportBlockSize;			//!< The number of samples to report in a telemetry report; also, the number of samples to read before duty cycling
	unsigned samplePeriodSec;			//!< The number of seconds between samples when sampling (sensor's "interval" variable
};

}
}

//! Indicates which version of the schema is the latest (what is written with save())
BOOST_CLASS_VERSION(LiquidRobotics::SeabirdGPCTD::SBGPCTDControllerPersistSettings, 1)

#endif /* SBGPCTDPROGRAMSETTINGS_H_ */
