//-------------------------------------------------------------------------------------------------
// <copyright file="LWController.h" company="LiquidRobotics">
//  Copyright (c) Liquid Robotics Corporation, confidential and proprietary.  All rights reserved. 
// </copyright>
//
// <summary>
//	Declaration of the controller class for LuaWrapper (the methods that theoretically
//	are not reliant on CORBA, though in fact they provide some translations between
//	CORBA and lua.)
// </summary>
//
// <owner>Mike Cookson</owner>
//-------------------------------------------------------------------------------------------------

#ifndef __LWCONTROLLER_H__
#define __LWCONTROLLER_H__

#include "LWConcreteCmd.h"
#include "LWControllerSettings.h"
#include "SensorController.h"
#include "LqrSMACLuaInstance.h"
#include "LqrSMACSemaphore.h"
#include "LqrSMACSerialPort.h"
#include "LqrSMACSerialListener.h"
#include <boost/thread.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <map>
#include <set>

namespace LiquidRobotics {

namespace EventLib {
	class EventSettings;
	class GPSSampleEvent;
	class IEventBase;
	class PayloadManagerClientSettings;
};

namespace SMACFramework {
	class CmdOutputFormatter;
	class IObjectBroker;
}

namespace LuaWrapper {

typedef EventLib::SensorController<LWControllerBase0,LWControllerCommand,LWCmdID,EventLib::SensorControllerExceptions> LWControllerBase;

class LWControllerLua;

class SHARED_LIB_PUBLIC LWController
: public LWControllerBase
{
public:

	typedef boost::shared_ptr<CommandQueue> CommandQueuePtr;
	typedef LWControllerBase Base;
	typedef LiquidRobotics::EventLib::EventSettings EventSettings;
	typedef LiquidRobotics::EventLib::IEventBase IEventBase;
	typedef boost::shared_ptr<IEventBase> IEventBasePtr;
	typedef CommandPtr LuaCommandPtr;
	typedef LiquidRobotics::SMACFramework::QueueWorker<LuaCommandPtr> LuaQueueWorker;
	typedef boost::shared_ptr<LuaQueueWorker> LuaQueueWorkerPtr;
	typedef LiquidRobotics::EventLib::PayloadManagerClientSettings PayloadManagerClientSettings;
	typedef std::string string;
	typedef boost::signals2::signal<void (LWController& sender, const string& instanceName, const string& eventName,
			const string& eventType, const string& eventDomain, const string& dataSetName, const string& content)> PublishDataSetSignalType;
	typedef boost::signals2::signal<void (LWController& sender, IEventBase& evt)> PublishEventSignalType;

	LWController(const LWControllerSettings& _settings, IObjectBroker& _broker, Logger& _logger, GPSSignalSubscriber::Ptr _gpsSubscriber, ShutdownSignalSubscriber::Ptr _shutdownSubscriber, const PayloadManagerClientSettings& _pmc, const EventSettings& _commandCompleteEventSettings);
	virtual ~LWController();

	void Initialize();
	void Shutdown();

	void ForwardAnyEventReceived(const IEventBase& receivedEvent);
	ScopedConnectionPtr SubscribePublishDataSet(PublishDataSetSignalType::slot_type slot);
	ScopedConnectionPtr SubscribePublishEvent(PublishEventSignalType::slot_type slot);

	virtual void CloseLua(const string& instanceName);
	virtual void CloseLuaInternal(const string& instanceName);
	virtual void CloseSerialPortConfig(const string& configName);
	virtual IEventBase::Ptr CreateTelemetryEvent(const string& eventName, const string& eventTypeName, const string& eventDomainName);
	virtual void ForwardSerialData(const string& instanceName, const string& portInstanceName, const ByteArray& data);
	//virtual void ForwardSerialDataImmediate(const string& instanceName, const string& portInstanceName, const ByteArray& data);
	virtual void ForwardTimeout(const string& instanceName, const string& timerName);
	virtual bool GetLocation(double& latVar, double& lonVar) const;
	virtual LuaInstancePtr GetLuaInstance(const string& instanceName);
	virtual void GetLuaInstanceReport(StringArray& result);
	virtual void GetServerDetails(unsigned boardAddress, string& serverName, string& serverTypeName);
	virtual bool InvokeSendCommand(const string& serverName, const string& serverType, EventPropertyValue& epvCommand,
			EventPropertyValue& epvResponse, string& asynchronousResponseTag, bool asynch);
	virtual void OpenLua(const string& instanceName, const string& luaFileName, int traceOpt = 0);
	virtual void OpenLuaInternal(const string& instanceName, const string& luaFileName, int traceOpt);
	virtual void OpenSerialPortConfig(const string& configName, ISerialPort::Ptr& resultingPort, SerialListener::Ptr& resultingListener);
	virtual void PublishDataSet(const string& instanceName, const string& eventName, const string& eventType, const string& eventDomain,
			const string& dataSetName, const string& content);
	virtual void SetTraceOptions(const string& instanceName, int traceOpt);
	virtual void SetTraceOptionsInternal(const string& instanceName, int traceOpt);
	virtual void TransmitEvent(IEventBase& evt);
	virtual string RunLuaCommand(CommandPtr cmdp, bool awaitResult = true);

protected:

	typedef LiquidRobotics::EventLib::GPSSampleEvent GPSSampleEvent;

	virtual string GetDefaultOutputFormatter() const;
	virtual void OnGPSSampleEvent(const GPSSampleEvent& sample);
	virtual void OnProcessLuaQueue(LuaQueueWorker& sender, const LuaCommandPtr& item);
	virtual void OnShutdownEvent();
	virtual CommandPtr ParseCommand(TCon::ParsingContext& context, bool internalCmd = false);

private:

	static void HookFunc(lua_State *L, lua_Debug *ar);

	typedef LiquidRobotics::SMACFramework::LuaInstance LuaInstance;
	typedef boost::shared_ptr<LuaInstance> LuaInstancePtr;
	typedef boost::recursive_mutex Mutex;
	typedef boost::unique_lock<Mutex> MutexLock;
	typedef std::set<string> StringSet;

	struct NamedInstance
	{
		NamedInstance(const string& _name, LWController* pcon, Logger& logger, IObjectBroker& broker);

		string fileName;
		string instanceName;
		LuaInstancePtr inst;
		LWControllerLua* luac;
		bool forwardGPS;
		bool forwardAnyEvents;
	};

	struct WaitingCommand
	{
		typedef LiquidRobotics::SMACFramework::Semaphore Semaphore;

		WaitingCommand(IObjectBroker& _broker) : sem(0) { }

		string tag;
		Semaphore sem;
		::CORBA::Any_var result;
	};

	typedef boost::shared_ptr<WaitingCommand> WaitingCommandPtr;

	typedef boost::shared_ptr<NamedInstance> NamedInstancePtr;
	typedef std::map<string, NamedInstancePtr> NamedInstanceMap;
	typedef std::map<string, WaitingCommandPtr> TagToWaitingCommandMap;

	Mutex mutex;
	const LWControllerSettings& settings;
	IObjectBroker& broker;
	LuaQueueWorkerPtr luaQW;
	ScopedConnectionPtr lqHandleWorkItemConnection;
	NamedInstanceMap instances;
	StringSet usedSerialConfigs;
	double lat, lon;
	double hasGPS;
	const PayloadManagerClientSettings& pmc;
	string procTag;
	int cmdNum;
	EventSettings commandCompleteEventSettings;
	TagToWaitingCommandMap tagToWaitingCommandMap;
	PublishDataSetSignalType publishDataSetSignal;
	PublishEventSignalType publishEventSignal;
};

typedef boost::shared_ptr<LWController> LWControllerPtr;

}
}

#endif
