//------------------------------------------------------------------------------
// <copyright file="VirtualRelayController.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 VirtualRelayController class. This class is responsible for
//  managing a single channel (ie, Cell or WiFi) and the connection to WGMS.
//  It can receive outgoing FCC messages from VirtualRelayProgram, and will
//  send them over the channel. It will also fire off signals when it receives
//  a WGMS command, when the connection times out (based off telemetry) and
//  when it wants a channel request to be sent.
// </summary>
//
// <owner>Arash Ushani</owner>
//------------------------------------------------------------------------------

#ifndef __VirtualRelayController_H__
#define __VirtualRelayController_H__

#include "VirtualRelayMessageManager.h"
#include "LqrSMACSharedLib.h"
#include "LqrSMACTimerCollection.h"
#include <boost/shared_ptr.hpp>
#include <boost/signals2.hpp>
#include <boost/asio.hpp>
#include <stdint.h>

namespace LiquidRobotics {

namespace EventLib {
	class IEventBase;
}

namespace SMACFramework {
	class IObjectBroker;
	class Logger;
	class PayloadDescription;
}

namespace VirtualRelay {

class VirtualRelayControllerSettings;
class VirtualRelayMessageManager;

class SHARED_LIB_PUBLIC VirtualRelayController
{

public:

	typedef LiquidRobotics::SMACFramework::Logger Logger;
	typedef boost::signals2::scoped_connection ScopedConnection;
	typedef boost::shared_ptr<ScopedConnection> ScopedConnectionPtr;
	typedef EventLib::EventPropertyValue::UInt8Vector UInt8Vector;

	typedef boost::signals2::signal<void (const VirtualRelayController& sender, const UInt8Vector& incomingMessage)> IncomingMessageSignalType;
	typedef boost::shared_ptr<IncomingMessageSignalType> IncomingMessageSignalTypePtr;

	typedef boost::signals2::signal<void (const VirtualRelayController& sender, bool state)> ChannelRequestSignalType;
	typedef boost::shared_ptr<ChannelRequestSignalType> ChannelRequestSignalTypePtr;

	typedef boost::signals2::signal<void (VirtualRelayController& sender)> TelemetryTimeoutSignalType;
	typedef boost::shared_ptr<TelemetryTimeoutSignalType> TelemetryTimeoutSignalTypePtr;

	typedef boost::signals2::mutex Mutex;
	typedef unsigned char byte;

	VirtualRelayController(VirtualRelayControllerSettings& _settings, Logger& _logger);
	virtual ~VirtualRelayController();

	ScopedConnectionPtr SubscribeToIncomingMessages(IncomingMessageSignalType::slot_type slot);
	ScopedConnectionPtr SubscribeToChannelRequests(ChannelRequestSignalType::slot_type slot);
	ScopedConnectionPtr SubscribeToTelemetryTimeout(TelemetryTimeoutSignalType::slot_type slot);

	void Start();
	void Shutdown();

	void SetBoardID(int val);
	int GetAddress() const;
	int GetProtocolRevision() const;

	void UpdateChannelState(bool state);
	void UpdateSignalStrength(int signalStrength);
	void SetVehicleUniqueID(unsigned int uniqueID);

	VirtualRelayPacketComparision::Priority HighestPriorityMessage();
	UInt8Vector PopMessage();

	void OutgoingMessage(std::vector<byte>& message);

	// Settings Configuration
	void SetSleepTime(int val);
	void SetRetryRate(int val);
	void SetRetries(int val);
	void SetTimeout(int val);
	void SetTelemetryInterrupt(bool val);
	void SetAckInterrupt(bool val);

private:

	std::string Describe();

	void Run();

	bool StartSocketTransaction();
	void CloseSocket();

	void RunService();
	void DoRelayStatus();
	float TimeToNextRelayStatus();
	bool SocketSession();

	void HandleIncomingMessageFromShore(const VirtualRelayMessageManager& sender, const UInt8Vector& incomingMessage);

	// Socket Handling
	void HandleRelayConnection(const boost::system::error_code& error);
	void HandleIncomingRelayMessages(const boost::system::error_code& error, std::size_t bytes);

	// Fire Signals
	void SendIncomingFCCMessage(const UInt8Vector& message);
	void ChannelRequest(bool state);
	void SignalTelemetryTimeout();

	VirtualRelayControllerSettings& settings;
	Logger& logger;

	boost::shared_ptr<VirtualRelayMessageManager> messageManagerPtr;

	ScopedConnectionPtr connectionToFCCIncomingMessageEvent;

	IncomingMessageSignalTypePtr incomingMessageSignalPtr;
	ChannelRequestSignalTypePtr channelRequestSignalPtr;
	TelemetryTimeoutSignalTypePtr telemetryTimeoutSignalPtr;

	boost::shared_ptr<boost::asio::io_service> io_service;
	boost::shared_ptr<boost::asio::ip::tcp::socket> socket;

	float lastSocketSessionTime;
	Mutex socketSessionMutex;

	//const static uint16_t SOCKETBUFFERSIZE = 65535;
	const static uint16_t SOCKETBUFFERSIZE = 4000;
	char socketBuffer[SOCKETBUFFERSIZE];

	bool runIOService;
	bool IOServiceIsRunning;
	bool successfulTransaction;

	bool channelOn;

	int  signalStrength;

	int boardID;
};

}
}

#endif
