//-------------------------------------------------------------------------------------------
// <copyright file="SBGPCTDLoggingCmd.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 SBGPCTDLoggingCmd, which enables or disables sample logging or raw logging
// </summary>
//
// <owner>Mike Cookson</owner>
//-------------------------------------------------------------------------------------------

#ifndef SBGPCTDLOGGINGCMD_H_
#define SBGPCTDLOGGINGCMD_H_

#include "SBGPCTDClassConfig.h"
#include "LqrSMACBooleanParser.h"
#include "LqrSMACCmdLineParser.h"

namespace LiquidRobotics {
namespace SeabirdGPCTD {

/*! \class SBGPCTDLoggingCmd
 *  \brief Implementation of the Seabird GPCTD interface Logging command
 *  \sa SBGPCTDController, SBGPCTDController::ParseCommand()
 *
 *  The Logging command sets or reads the state of the logging switches for
 *  sample logging or raw logging.
 *
 *  Command classes always implement a Parse member function that determines if
 *  parameters supplied indicate the command implemented by the class and parses
 *  out the the parameters.  If successful, the parameters are used to
 *  instantiate the class.  The class derives from the "concrete command" class,
 *  which provides members and data related used by all commands.
 */
class SHARED_LIB_PUBLIC SBGPCTDLoggingCmd : public SBGPCTDConcreteCmd
{
public:

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

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

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

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

	/*! \brief Class constructor
	 */
	SBGPCTDLoggingCmd(
			TCon& _ctrl,					/**< [in] References the Controller class, used during execution */
			const string& _cmd,				/**< [in] A copy of the original command line */
			bool _reading,					/**< [in] true if reading the setting, false if writing the setting */
			bool _newValue,					/**< [in] true if the new value enables logging, false if it disables it */
			bool _affectRawLogging,			/**< [in] true if affecting the raw log setting, false if affecting the sample log setting */
			Logger& _logger					/**< [in] References a logger that can be used during the command */
			)
	: SBGPCTDConcreteCmd(_ctrl)
	, ctrl(_ctrl)
	, cmd(_cmd)
	, reading(_reading)
	, newValue(_newValue)
	, affectRawLogging(_affectRawLogging)
	, logger(_logger)
	{
	}

	/*! \brief Class destructor
	 */
	virtual ~SBGPCTDLoggingCmd()
	{
	}

	/*! \brief Implementation of command execution.
	 *
	 * (Overrides the base class member)
	 */
	virtual void Execute()
	{
		using namespace std;
		using namespace LiquidRobotics::SMACFramework;

		try
		{
			SignalStarted();

			bool result;

			if (reading)
			{
				if (affectRawLogging)
					result = ctrl.GetPersistSettings().GetRawLoggingEnabled();
				else
					result = ctrl.GetPersistSettings().GetLoggingEnabled();
			}
			else
			{
				if (affectRawLogging)
					ctrl.GetPersistSettings().SetRawLoggingEnabled(newValue);
				else
					ctrl.GetPersistSettings().SetLoggingEnabled(newValue);

				ctrl.SavePersistentSettings();
				result = newValue;
			}

			CmdOutputFormatter::Ptr fmt = GetOutputFormatter();
			if (fmt)
					fmt->AppendOutput(BooleanToString(result));
		}
		catch(exception& ex)
		{
			stringstream msg;
			msg << "ERROR: " << ex.what();

			CmdOutputFormatter::Ptr fmt = GetOutputFormatter();
			if (fmt)
					fmt->AppendOutput(msg.str());
		}
	}

	/*! \brief Parses command parameters and creates command instance
	 *  \returns A smart pointer to an instance of the command class or a nil smart pointer
	 *
	 * If the first parameter to the command matches arg1 and the second parameter matches arg2,
	 * the Parse member uses the remaining parameters configure a new instance of this command
	 * class and returns it as a smart pointer; exceptions may be thrown if parameters are not
	 * valid.
	 *
	 * If the command doesn't match the arguments, then a nil smart pointer is returned.
	 */
	static CmdPtr Parse(
			const string& arg1,					/**< [in] Required value for parameter #1 to the command */
			const string& arg2,					/**< [in] Required value for parameter #2 to the command */
			TCon& ctrl,							/**< [in] Reference to the controller (retained for command execution */
			const CmdLineParser& parser,		/**< [in] Reference to a parsed input command line used to get access to command parameters */
			ParsingContext& context,			/**< [in] Information about the remote caller (not used by the parser) */
			Logger& logger,						/**< [in] Logger to be used while parsing or executing the command */
			const bool affectRawLogging		/**< [in] true if the command affects logging of transmit and receive, false if command affects sample logging */
			)
	{
		using namespace std;
		using namespace LiquidRobotics::SMACFramework;

		CmdPtr result;
		const CmdLineParser::StringArray& tokens = parser.GetTokens();

		if ((tokens.size() >= 2)
		 && boost::iequals(tokens[0], arg1)
		 && boost::iequals(tokens[1], arg2))
		{
			bool reading = (tokens.size() == 2);

			if (tokens.size() > 3)
				throw invalid_argument("Too many arguments");

			const bool newValue = !reading && StringToBoolean(tokens[2]);

			result.reset(new SBGPCTDLoggingCmd(ctrl, parser.GetOriginalCmdLine(), reading, newValue, affectRawLogging, logger));
		}

		return result;
	}

private:

	SBGPCTDControllerBase0& ctrl;		//!< Reference to the controller
	const string cmd;					//!< Copy of the command that was issued by the user
	const bool reading;				//!< true if reading the value, false if setting the value
	const bool newValue;				//!< the new value to set (true if logging, false if not logging)
	const bool affectRawLogging;		//!< true if affecting transmit/receive logging, false if affecting sample reading
	Logger& logger;						//!< Reference to the logger to be used while running
};

}
}

#endif /* SBGPCTDLOGGINGCMD_H_ */
