//-------------------------------------------------------------------------------------------------
// <copyright file="OneTimeCommandController.h" company="LiquidRobotics">
//  Copyright (c) Liquid Robotics Corporation, confidential and proprietary.  All rights reserved. 
// </copyright>
//
// <summary>
// </summary>
//
// <owner></owner>
//-------------------------------------------------------------------------------------------------

#ifndef __ONETIMECOMMANDCONTROLLER_H__
#define __ONETIMECOMMANDCONTROLLER_H__

#include "OneTimeCommandSettings.h"
#include "FCCMessage.h"
#include "LatLon.h"
#include "LqrSMACSemaphore.h"
#include "PayloadPortSlave.h"

namespace LiquidRobotics {

namespace SMACFramework {
	class CmdLineParser;
}
namespace OneTimeCommand {

class OneTimeCommandController
: public LiquidRobotics::PayloadInterface::PayloadPortSlave

{
public:

	typedef LiquidRobotics::PayloadInterface::HDLCPort HDLCPort;
	typedef LiquidRobotics::SMACFramework::Semaphore Semaphore;
	typedef std::string string;

	OneTimeCommandController(const OneTimeCommandSettings& _settings, Logger& _logger, Semaphore& _runSem);
	virtual ~OneTimeCommandController();

    // === Overrides of PayloadPortSlave virtual methods ===

	// Overriding this handler to catch the exit from the program
	virtual void Run(HDLCPort::Ptr pHDLC);

protected:

	typedef LiquidRobotics::PayloadInterface::FCCMessage::CMD_FMT_1E CMD_FMT_1E;
	typedef LiquidRobotics::PayloadInterface::FCCMessage::CommandClass<CMD_FMT_1E,false> CommandClass_CMD_FMT_1E;
	typedef LiquidRobotics::PayloadInterface::PayloadMessage PayloadMessage;
	typedef LiquidRobotics::PayloadInterface::PayloadProtocol PayloadProtocol;

	// Overriding this handler to halt the system when requested
	virtual PayloadMessage::Ptr WaitForMessage(HDLCPort::Ptr pHDLC);

	// This method is called whenever a message is received.  The return value contains the message to be sent
	// in response (or send back a null pointer if no response should be made)
	//
	// Normally, duplicateHeader will be false; if duplicateHeader is true, the receiver should typically return
	// a null pointer and the handler will retransmit the message that was previously sent.
	virtual PayloadMessage::Ptr OnMessageReceived(PayloadMessage::Ptr messageReceived, bool duplicateHeader);

	// This method is called whenever an forwarded or copied ICD message is received; the receiver should fill out
	// either the ack or the nak response
	virtual void OnICDMessageReceived(PayloadMessage::Ptr messageReceived,
			boost::shared_ptr<AckContainerBase>& ack,
			boost::shared_ptr<NakContainer>& nak);

	// This methnod is called whenever a power notification message is received; the user should fill out either
	// the ack responses or the nak container
	virtual void OnPowerNotification(const PayloadProtocol::PYLD_POWER_NOTIFICATION& notification,
			boost::shared_ptr< CountedAckContainer<PayloadProtocol::ACK_PYLD_POWER_NOTIFICATION_RECORD> >& ack,
			boost::shared_ptr<NakContainer>& nak);

	// This method is called by the default OnMessageReceived implementation when an ID/enumeration request is
	// received; the user should fill out the responses array for processing on return.
	virtual void OnRequestIDReceived(const PayloadProtocol::LRI_REQUEST_ID& idRequest,
			std::vector<PayloadProtocol::LRI_ID_PACKET>& responses);

	// This method is called by the default OnMessageReceived implementation when a status request message is
	// received; the user should fill out either the Nak structure or the Ack strcture
	virtual void OnStatusRequest(const PayloadProtocol::LRI_REQUEST_PIB_STATUS& statusRequest,
			boost::shared_ptr< CountedAckContainer<PayloadProtocol::LRI_PIB_STATUS> >& ack,
			boost::shared_ptr<NakContainer>& nak);

	// Returns true if there are messages queued to be read out by the Host, false if there are none; this method
	// is used to set the "have messages" flag in all responses
	virtual bool HaveMessagesQueued(BoardAddress destinationAddress) const;

	// This method should return true unless intending to exit
	virtual bool Running() const;

	// Returns true if the address is one that should be Nak'd, false if the address is unknown
	virtual bool SendNaksForAddress(BoardAddress destinationAddress) const;

	// Returns the board address of the main task
	virtual PayloadMessage::BoardAddress MainTaskAddress() const;

	// Attemps to pull the next message from the queue that matches the given board address (i.e. the board ID
	// matches); returns an empty smart pointer upon failure
	virtual PayloadMessage::Ptr DequeueMessage(BoardAddress boardAddress);

private:

	typedef LiquidRobotics::PayloadInterface::LatLon LatLon;

	Logger& GetLogger() const;
	void HandleShutdown();
	void ShutdownSystem();

	const OneTimeCommandSettings& config;
	Semaphore& runSem;
	bool halt;
	bool shutdownCompleted;
	LatLon lastFix;
	bool running;
};

}
}

#endif
