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

#ifndef __ENCRYPTEDPAYLOADCONTROLLER_H__
#define __ENCRYPTEDPAYLOADCONTROLLER_H__

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

namespace LiquidRobotics {

namespace SMACFramework {
	class CmdLineParser;
}
namespace EncryptedStartup {

class EncryptedPayloadController
: public LiquidRobotics::PayloadInterface::PayloadPortSlave

{
public:

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

	EncryptedPayloadController(const EncryptedStartupSettings& _settings, Logger& _logger, Semaphore& _runSem);
	virtual ~EncryptedPayloadController();

    // === 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 an ASCII- or binary-formatted console command is received
	virtual void OnConsoleMessage(
			BoardAddress source,
			BoardAddress target,
			const Level2Wrapper& receivedLevel2,
			const LiquidRobotics::PayloadInterface::FCCMessage::CMD_FMT_1E& receivedParams,
			const ByteArray& dataBytes,
			bool asciiFormat,
			bool& acked,
			uint8_t& nakDisp,
			uint8_t& nakSummary,
			bool wantsAck);

	// 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,
			PayloadProtocol::ACK_PYLD_POWER_NOTIFICATION_RECORD& ack,
			bool& acked,
			PayloadProtocol::ENakSummary& nakSummary);

	// 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,
			LRI_ID_PACKET_ARRAY& 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,
			PayloadProtocol::LRI_PIB_STATUS& ack,
			bool& acked,
			PayloadProtocol::ENakSummary& nakSummary);

	// 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;

private:

	struct CryptoAction
	{
		CryptoAction(const string& _cmd, uint16_t _src, uint16_t _dst, uint32_t _packetID)
		: havePassPhrase(false)
		, cmd(_cmd)
		, src(_src)
		, dst(_dst)
		, packetID(_packetID)
		{
		}

		CryptoAction(const string& _cmd, const string& _pass, uint16_t _src, uint16_t _dst, uint32_t _packetID)
		: havePassPhrase(true)
		, passphrase(_pass)
		, cmd(_cmd)
		, src(_src)
		, dst(_dst)
		, packetID(_packetID)
		{
		}

		const bool havePassPhrase;
		const string passphrase;
		const string cmd;
		const uint16_t src;
		const uint16_t dst;
		const uint32_t packetID;
	};

	typedef LiquidRobotics::SMACFramework::CmdLineParser CmdLineParser;
	typedef LiquidRobotics::PayloadInterface::LatLon LatLon;
	typedef boost::shared_ptr<CryptoAction> CryptoActionPtr;

	bool AlreadyMounted(const string& mountPoint) const;
	int CloseCrypto(const string& cryptoDevice);
	string CryptoDevicePath(const string& cryptoDevice);
	void CryptoMount(const CmdLineParser& parser, uint32_t packetID, uint16_t responseTarget);
	bool CryptoUsed(const string& cryptoDevice, string& info);
	bool DeferredStartupTelem() const;
	void EnqueueStartupTelemetryMessage(bool defer = false);
	void EnqueueConsoleResponse(const string& data, uint32_t packetID, uint16_t source, uint16_t dest);
	void EnqueueConsoleResponse(const ByteArray& data, uint32_t packetID, uint16_t source, uint16_t dest);
	void ExecutePostCryptoAction();
	void GenericCrypto(const CmdLineParser& parser, uint32_t packetID, uint16_t responseTarget);
	Logger& GetLogger() const;
	void HandleShutdown();
	int PipeRun(const string& cmd, const string& input, string& output);
	void RunShell(const CmdLineParser& parser, uint32_t packetID, uint16_t responseTarget);
	void ShutdownSystem();

	const EncryptedStartupSettings& config;
	Semaphore& runSem;
	bool halt;
	bool shutdownCompleted;
	bool enqueueStartupTelem;
	LatLon lastFix;
	CryptoActionPtr action;
};

}
}

#endif
