//------------------------------------------------------------------------------
// <copyright file="PayloadProtocol.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>
// </summary>
//
// <owner></owner>
//------------------------------------------------------------------------------


#ifndef PAYLOADPROTOCOL_H_
#define PAYLOADPROTOCOL_H_

#include <stdint.h>
#include "LqrSMACByteArray.h"
#include "LqrSMACSharedLib.h"

namespace LiquidRobotics {

namespace SMACFramework {
	class ByteStream;
}

namespace PayloadInterface {

class SHARED_LIB_PUBLIC PayloadProtocol
{
public:

#pragma pack(push,1)

	typedef struct _TM_
	{
		int tm_sec;
		int tm_min;
		int tm_hour;
		int tm_mday;
		int tm_mon;
		int tm_year;
		int tm_wday;
		int tm_yday;
		int tm_isdst;
	} tm_pyld;

	//Time stamp structure
	typedef struct
	{
		int8_t	second;
		int8_t	minute;
		int8_t	hour;
		int8_t	day;
		int8_t	month;
		uint8_t	year;
	} TIMESTAMP, *PTIMESTAMP;

	enum ENakSummary
	{
		NAKSUMMARY_UNKNOWN_RECIPIENT,
		NAKSUMMARY_UNKNOWN_COMMAND,
		NAKSUMMARY_INVALID_DATA,
		NAKSUMMARY_DEVICE_NOT_FOUND,
		NAKSUMMARY_PROGRAM_DOWNLOAD_REQUESTED,
		NAKSUMMARY_REQUEST_POWER_CYCLE,
		NAKSUMMARY_REQUEST_POWER_OFF
	};

	typedef struct _LRI_GENERIC_NAK_
	{
		uint16_t	originalCmd;
		uint8_t		nakSummary;
	} LRI_GENERIC_NAK, *PLRI_GENERIC_NAK;

	typedef struct _LRI_GENERIC_ACK_
	{
		uint16_t	originalCmd;
	} LRI_GENERIC_ACK, *PLRI_GENERIC_ACK;

	typedef struct _LRI_REQUEST_ID_
	{
		uint16_t	communicationProtocols;
		uint16_t	commandFormats;
	} LRI_REQUEST_ID, *PLRI_REQUEST_ID;

	enum ELRIIdExtraInfo
	{
		EXTRA_INFO_TELEMETRY = 1,
		EXTRA_INFO_POWER = 2,
		EXTRA_INFO_EVENTS = 4,
		EXTRA_INFO_ECHOED_ACKS = 8
	};

	typedef struct _LRI_ID_PACKET_
	{
		uint16_t	version;
		uint16_t	deviceType;
		uint16_t	address;
		char		serialNum[6];
		uint8_t		port;
		uint32_t	pollingRate;
		uint8_t		extraInfo;	//Bit 0 = telemetry, Bit 1 = power, Bit 2 = evets, Bit 3 = Echoed ACKS
		uint8_t		firmwareMajor;
		uint8_t		firmwareMinor;
		uint16_t	firmwareRev;
		char		description[20];
	}LRI_ID_PACKET, *PLRI_ID_PACKET;

	typedef struct _LRI_ID_ACK_WRAPPER_
	{
		uint16_t		totalNumber;
		uint16_t		numberOfReplies;
		LRI_ID_PACKET	firstID;
	} LRI_ID_ACK_WRAPPER, *PLRI_ID_ACK_WRAPPER;

	typedef struct _LRI_ACK_COUNT_WRAPPER_
	{
		uint16_t		totalNumber;
		uint16_t		numberOfReplies;
	} LRI_ACK_COUNT_WRAPPER, *PLRI_ACK_COUNT_WRAPPER;

	typedef struct _LRI_TELEM_ACK_WRAPPER_
	{
		uint16_t	numACKS;
		uint16_t	numDataWaiting;
		uint16_t	firstAddress;
	} LRI_TELEM_ACK_WRAPPER, *PLRI_TELEM_ACK_WRAPPER;

	typedef struct _LRI_REQUEST_PIB_STATUS_
	{
		TIMESTAMP	timestamp;
		int32_t	latitude;
		int32_t	longitude;
		char		fixValid;
	} LRI_REQUEST_PIB_STATUS, *PLRI_REQUEST_PIB_STATUS;

	typedef struct _LRI_PIB_STATUS_
	{
		uint16_t	version;	//Hi bit = Comand/Data Waiting
		uint16_t	address;	//PIB address
		uint16_t	alarms;
	    uint8_t 	leak1;		//Leak Sensor 1 status
		uint8_t		leak2;		//Leak Sensor 2 status
		int8_t 		humidTemp;	//Temperature Form the Humidity Sensor (deg C)
		uint8_t 	humidity;	//Relative Humidity (%)
		int8_t 		presTemp;	//Temperature From the Pressure Sensor (deg C)
		uint8_t 	pressure;	//Pressure (kPa)
	}LRI_PIB_STATUS, *PLRI_PIB_STATUS;

	typedef struct _LRI_STATUS_ACK_WRAPPER_
	{
		uint16_t		totalNumber;
		uint16_t		numberOfReplies;
		LRI_PIB_STATUS	firstStatus[0];
	}LRI_STATUS_ACK_WRAPPER, *PLRI_STATUS_ACK_WRAPPER;

	typedef struct _PYLD_POWER_NOTIFICATION_
	{
		uint8_t 	notificationType;
		uint8_t		boardID;
		uint8_t		newState;
	}PYLD_POWER_NOTIFICATION, *PPYLD_POWER_NOTIFICATION;

	typedef struct _ACK_PYLD_POWER_NOTIFICATION_RECORD_
	{
		uint16_t	address;
		uint8_t		boardID;
		uint8_t		state;
		uint8_t		delayOff;
		uint8_t		delayOn;
	}ACK_PYLD_POWER_NOTIFICATION_RECORD, *PACK_PYLD_POWER_NOTIFICATION_RECORD;

	// allowable values for flagSendFwd
	enum ESendFwd
	{
		SF_INFORMATION,
		SF_EXECUTE
	};

	// allowable values for cmdFormat
	enum ECmdFormat
	{
		CF_SHIP_SHORE_ICD = 1
	};

	typedef struct _SEND_FWD_ICD_MESSAGE_HEADER_
	{
		uint8_t		flagSendFwd;
		uint16_t	cmdFormat;
	} SEND_FWD_ICD_MESSAGE_HEADER, *PSEND_FWD_ICD_MESSAGE_HEADER;

	// inserted before the actual message when replying with a command for the
	// Float C&C command interpreter
	struct RESPONSE_HEADER_WITH_FORMAT
	{
		RESPONSE_HEADER_WITH_FORMAT() : cmdFormat(CF_SHIP_SHORE_ICD) { }
		RESPONSE_HEADER_WITH_FORMAT(ECmdFormat _cmdFormat) : cmdFormat(_cmdFormat) { }

		uint16_t	cmdFormat;
	};

	// this structure appears in the payload section of a ACK_REQUESTED_PACKET
	// payload message before the actual ack data
	typedef struct _LRI_FLOAT_COMMAND_ACK_WRAPPER_
	{
		uint16_t	commandFormat;					// 1
		uint16_t	acknowledgementCode;			// 0=command success, others=NAK
	}LRI_FLOAT_COMMAND_ACK_WRAPPER, *PLRI_FLOAT_COMMAND_ACK_WRAPPER;

#pragma pack(pop)

	struct LRIGenericAck : public LRI_GENERIC_ACK
	{
		LRIGenericAck(uint16_t _originalCmd = 0, bool _haveMessages = false)
		{
			originalCmd = (_originalCmd & 0x7FFF) | (_haveMessages ? 0x8000 : 0);
		}

		bool GetHaveMessages() const
		{
			return !!(originalCmd & 0x8000);
		}

		void SetHaveMessages(bool newValue)
		{
			if (newValue)
				originalCmd |= 0x8000;
			else
				originalCmd &= ~0x8000;
		}
	};

	struct LRIGenericAckWithFormat : public LRIGenericAck, public RESPONSE_HEADER_WITH_FORMAT
	{
		LRIGenericAckWithFormat(uint16_t _originalCmd = 0, bool _haveMessages = false, ECmdFormat _cmdFormat = CF_SHIP_SHORE_ICD)
		: LRIGenericAck(_originalCmd, _haveMessages)
		, RESPONSE_HEADER_WITH_FORMAT(_cmdFormat)
		{
		}
	};

	struct LRIAckCountWrapper : public LRIGenericAck, public LRI_ACK_COUNT_WRAPPER
	{
		LRIAckCountWrapper(uint16_t _originalCmd = 0, uint16_t _totalNumber = 0, uint16_t _numberOfReplies = 0, bool haveMessages = false)
		: LRIGenericAck(_originalCmd, haveMessages)
		{
			totalNumber = _totalNumber;
			numberOfReplies = _numberOfReplies;
		}
	};

	struct LRIGenericNak : public LRIGenericAck
	{
		typedef LiquidRobotics::SMACFramework::ByteArray ByteArray;

		LRIGenericNak(uint16_t _originalCmd = 0, uint8_t _nakSummary = 0, bool haveMessages = false)
		: LRIGenericAck(_originalCmd, haveMessages)
		, nakSummary(_nakSummary)
		{
		}

		LRIGenericNak(const ByteArray& _additionalData, uint16_t _originalCmd = 0, uint8_t _nakSummary = 0, bool haveMessages = false)
		: LRIGenericAck(_originalCmd, haveMessages)
		, nakSummary(_nakSummary)
		{
		}

		uint8_t nakSummary;
		ByteArray additionalData;
	};
};

SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator>>(LiquidRobotics::SMACFramework::ByteStream& bs, PayloadProtocol::PYLD_POWER_NOTIFICATION& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator<<(LiquidRobotics::SMACFramework::ByteStream& bs, const PayloadProtocol::PYLD_POWER_NOTIFICATION& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator>>(LiquidRobotics::SMACFramework::ByteStream& bs, PayloadProtocol::LRI_REQUEST_ID& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator<<(LiquidRobotics::SMACFramework::ByteStream& bs, const PayloadProtocol::LRI_REQUEST_ID& data);

SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator>>(LiquidRobotics::SMACFramework::ByteStream& bs, PayloadProtocol::ACK_PYLD_POWER_NOTIFICATION_RECORD& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator<<(LiquidRobotics::SMACFramework::ByteStream& bs, const PayloadProtocol::ACK_PYLD_POWER_NOTIFICATION_RECORD& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator>>(LiquidRobotics::SMACFramework::ByteStream& bs, PayloadProtocol::LRI_GENERIC_ACK& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator<<(LiquidRobotics::SMACFramework::ByteStream& bs, const PayloadProtocol::LRI_GENERIC_ACK& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator>>(LiquidRobotics::SMACFramework::ByteStream& bs, PayloadProtocol::LRI_ACK_COUNT_WRAPPER& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator<<(LiquidRobotics::SMACFramework::ByteStream& bs, const PayloadProtocol::LRI_ACK_COUNT_WRAPPER& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator>>(LiquidRobotics::SMACFramework::ByteStream& bs, PayloadProtocol::RESPONSE_HEADER_WITH_FORMAT& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator<<(LiquidRobotics::SMACFramework::ByteStream& bs, const PayloadProtocol::RESPONSE_HEADER_WITH_FORMAT& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator>>(LiquidRobotics::SMACFramework::ByteStream& bs, PayloadProtocol::LRIGenericAck& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator<<(LiquidRobotics::SMACFramework::ByteStream& bs, const PayloadProtocol::LRIGenericAck& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator>>(LiquidRobotics::SMACFramework::ByteStream& bs, PayloadProtocol::LRIGenericAckWithFormat& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator<<(LiquidRobotics::SMACFramework::ByteStream& bs, const PayloadProtocol::LRIGenericAckWithFormat& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator>>(LiquidRobotics::SMACFramework::ByteStream& bs, PayloadProtocol::LRIAckCountWrapper& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator<<(LiquidRobotics::SMACFramework::ByteStream& bs, const PayloadProtocol::LRIAckCountWrapper& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator>>(LiquidRobotics::SMACFramework::ByteStream& bs, PayloadProtocol::LRI_REQUEST_PIB_STATUS& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator<<(LiquidRobotics::SMACFramework::ByteStream& bs, const PayloadProtocol::LRI_REQUEST_PIB_STATUS& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator>>(LiquidRobotics::SMACFramework::ByteStream& bs, PayloadProtocol::TIMESTAMP& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator<<(LiquidRobotics::SMACFramework::ByteStream& bs, const PayloadProtocol::TIMESTAMP& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator>>(LiquidRobotics::SMACFramework::ByteStream& bs, PayloadProtocol::SEND_FWD_ICD_MESSAGE_HEADER& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator<<(LiquidRobotics::SMACFramework::ByteStream& bs, const PayloadProtocol::SEND_FWD_ICD_MESSAGE_HEADER& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator>>(LiquidRobotics::SMACFramework::ByteStream& bs, PayloadProtocol::LRI_PIB_STATUS& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator<<(LiquidRobotics::SMACFramework::ByteStream& bs, const PayloadProtocol::LRI_PIB_STATUS& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator>>(LiquidRobotics::SMACFramework::ByteStream& bs, PayloadProtocol::LRI_ID_PACKET& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator<<(LiquidRobotics::SMACFramework::ByteStream& bs, const PayloadProtocol::LRI_ID_PACKET& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator>>(LiquidRobotics::SMACFramework::ByteStream& bs, PayloadProtocol::LRI_FLOAT_COMMAND_ACK_WRAPPER& data);
SHARED_LIB_PUBLIC LiquidRobotics::SMACFramework::ByteStream& operator<<(LiquidRobotics::SMACFramework::ByteStream& bs, const PayloadProtocol::LRI_FLOAT_COMMAND_ACK_WRAPPER& data);

}
}

#endif /* PAYLOADPROTOCOL_H_ */
