//-------------------------------------------------------------------------------
// <copyright file="SV3RemoteController.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 SV3RemoteController, which talks to Regulus and bridges to the
//  CORBA-based IPC that the SMC uses.
// </summary>
//
// <owner>Mike Cookson</owner>
//-------------------------------------------------------------------------------

#ifndef SV3REMOTECONTROLLER_H_
#define SV3REMOTECONTROLLER_H_

#include "CommonSendCommand.h"
#include "EventTransceiver.h"
#include "LocalTransactionCounter.h"
#include "LqrSMACIdl.h"
#include "LqrSMACAsynchronousProcessExecutor.h"
#include "LqrSMACByteStream.h"
#include "LqrSMACScopedConnection.h"
#include "LqrSMACSharedLib.h"
#include "PayloadInterfaceController_Config.h"
#include "PayloadManagerClient.h"
#include "SCLookup.h"
#include "SV3NetInterface.h"
#include "SV3NetInterfaceSettings.h"
#include "TelemetrySubsystem.h"
#include "AlarmSubsystem.h"
#include "PPSByteStream.h"
#include <boost/signals2.hpp>
#include <stdint.h>
#include <time.h>

namespace LiquidRobotics {
namespace PayloadInterface {

class SHARED_LIB_PUBLIC SV3RemoteController
: public LiquidRobotics::EventLib::EventTransceiver
, public LocalTransactionCounter
, public LiquidRobotics::EventLib::PayloadManagerClient
, public CommonSendCommand
, public SCLookup
, public TelemetrySubsystem
{
public:

	LOCKABLE_CONCEPT_TYPEDEFS();
	SCOPED_CONNECTION_TYPEDEFS();
	typedef CORBA::Any CORBAAny;
	typedef CORBA::Object_ptr Object_ptr;
	typedef std::string string;
	typedef LiquidRobotics::SMACFramework::BitConvert BitConvert;
	typedef LiquidRobotics::SMACFramework::ByteArray ByteArray;
	typedef LiquidRobotics::SMACFramework::ByteStream ByteStream;
	typedef LiquidRobotics::SMACFramework::Logger Logger;
	typedef LiquidRobotics::SMACFramework::IObjectBroker IObjectBroker;
	typedef LiquidRobotics::SMACFramework::PayloadDescription PayloadDescription;
	typedef LiquidRobotics::EventLib::PayloadManagerClient PayloadManagerClient;

	SV3RemoteController(
			IObjectBroker& _broker,
			Logger& _logger,
			const string& _telemConfigPath,
			const SV3NetInterfaceSettings& _sv3NetCfg,
			const PayloadInterfaceController_Config& _config,
			const StorageController::Config& _scSettings);
	virtual ~SV3RemoteController();

	void Initialize(Object_ptr serverRef);

	// IPingable operations
    virtual ::CORBA::Double Ping();

    // Overrides of CommonSendCommon
    virtual bool HandleAdditionalCommands(const string& command, const string& requester, const string& transactionID, string& result);

    // Overrides of SCLookup
    virtual void SCCommandComplete(ProxySC& sender, const ByteArray& data, long transNumber, unsigned destID, bool complete, unsigned resultNum, bool success);
    virtual void SCNewFileAvailable(ProxySC& sender, const string& actualFileName, string& remoteFileName);

    // Override of AlarmSubsystem member
	virtual void ReportAlarm(uint16_t senderAddress, const LiquidRobotics::SMACFramework::ByteArray& level1SysInfo);

private:

	struct MessageForwarder
	{
		MessageForwarder(SV3NetInterface& _sv3NetIf, Logger& _logger);

		void Initialize();
		void Shutdown();

		void PushPendingMessage(uint16_t sourceAddress, ByteArray::Ptr contentp);
		void SetCommunicating(bool communicating);

	private:

		void Background();

		SV3NetInterface& sv3NetIf;
		Logger& logger;
		typedef LiquidRobotics::SMACFramework::Semaphore Semaphore;
		Semaphore wakeup;
		bool communicating;
		bool shutdown;
		typedef LiquidRobotics::SMACFramework::ByteArray ByteArray;
		struct Item { uint16_t sourceAddress; ByteArray::Ptr contentp; };
		typedef boost::shared_ptr<Item> ItemPtr;
		typedef LiquidRobotics::SMACFramework::WaitableThreadSafeQueue<ItemPtr> MessageList;
		MessageList pendingMessages;
		typedef boost::shared_ptr<boost::thread> ThreadPtr;
		ThreadPtr threadp;
	};

	typedef LiquidRobotics::EventLib::EventTransceiver EventTransceiver;
    typedef LiquidRobotics::EventLib::IEventBase IEventBase;

    void GPSReceiveHandler(EventTransceiver& sender, const IEventBase& receivedEvent);
    void OnCommStatus(SV3NetInterface& sender, bool commStatus);
    void OnHostGPS(SV3NetInterface& sender, uint16_t boardAddress, time_t timestamp, double latitude, double longitude);
	void OnRemoteCommand(SV3NetInterface& sender, uint16_t boardAddress, const string& transactionReference,
			uint32_t conformingReference, bool returnFile, const string& cmdLine);
	void OnShutdown(SV3NetInterface& sender, SV3NetChannel& channel);
    void OnPayloadAdded(PayloadManagerClient& sender, const PayloadDescription& payloadDesc);
    void OnPayloadChanged(PayloadManagerClient& sender, const PayloadDescription& payloadDesc);
    void OnPayloadRemoved(PayloadManagerClient& sender, const PayloadDescription& payloadDesc);
    void OnSystemGPSOffline(EventTransceiver& sender, const IEventBase& receivedEvent);
    void OnSystemGPSOnline(EventTransceiver& sender, const IEventBase& receivedEvent);
	void InformDemoServerOfShutdown();
	void ReportEncryptedPartitionStatus(bool newState);
	void SendShutdownEvent();
	void ShutdownSystem();
	void TelemetryReportComplete(TelemetryBuffer& sender, TelemetryReportKey reportKey,
			TelemetryBuffer::BoardAddress targetAddress, const LiquidRobotics::SMACFramework::ByteArray& content);

    LockableConceptMutex mutex;
    LiquidRobotics::SMACFramework::IObjectBroker& broker;
    Logger& logger;
    const PayloadInterfaceController_Config& config;
    const SV3NetInterfaceSettings& sv3NetCfg;
    SV3NetInterface sv3NetIf;
    MessageForwarder messageForwarder;
    bool pendingStartupSysInfo;
    time_t lastStartupSysInfo;
	bool haveSavedPosition;
	double savedLatitude, savedLongitude;
	bool systemGPSOnline;
	bool manualGPSRequested;
    ScopedConnectionPtr remoteCommandSubscription;
    ScopedConnectionPtr shutdownSubscription;
    ScopedConnectionPtr hostGPSSubscription;
    ScopedConnectionPtr payloadAddedSubscription;
    ScopedConnectionPtr payloadChangedSubscription;
    ScopedConnectionPtr payloadRemovedSubscription;
    ScopedConnectionPtr commstatusSubscription;
    ScopedConnectionPtr connectionToGpsSampleEvent;
    ScopedConnectionPtr connectionToGpsSystemGPSOnline;
    ScopedConnectionPtr connectionToGpsSystemGPSOffline;
};

}
}

#endif /* SV3REMOTECONTROLLER_H_ */
