//----------------------------------------------------------------------------------
// <copyright file="FCCMessage_CommHeaderMessage.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>
//   Declarations for:
//
//		- CommHeaderMessage, a template class that derives from CommHeaderMessageGeneric
//		  and encapsulates a parameterized simple class
//
//		- CmdLayout, a templated structure that defines CMD_FMT_COMMON followed by
//		  a class instance
//
//		- CommandClass, a templated class for a command with command parameters from
//		  the template
// </summary>
//
// <owner>Mike Cookson</owner>
//----------------------------------------------------------------------------------

#ifndef FCCMESSAGE_COMMHEADERMESSAGE_H_
#define FCCMESSAGE_COMMHEADERMESSAGE_H_

#include "FCCMessage_CommHeaderMessageGeneric.h"

namespace LiquidRobotics {
namespace PayloadInterface {
namespace FCCMessage {

template<typename SimpleType, bool WithCRC = false>
class CommHeaderMessage : public CommHeaderMessageGeneric
{
public:

	typedef CommHeaderMessageGeneric Base;

	CommHeaderMessage(unsigned extraBytes = 0)
	: Base(sizeof(SimpleType), WithCRC, extraBytes)
	{
	}

	CommHeaderMessage(const ByteArray& byteData, unsigned offset)
	: Base(sizeof(SimpleType), WithCRC, byteData, offset)
	{
	}

	CommHeaderMessage(const byte* pData, unsigned dataLength)
	: Base(sizeof(SimpleType), WithCRC, pData, dataLength)
	{
	}

	CommHeaderMessage(uint8_t _type, uint32_t _packetID, const CommHeaderConversionBase& _data)
	: Base(sizeof(SimpleType), WithCRC, _type, _packetID, _data)
	{
	}

	CommHeaderMessage(uint8_t _type, uint32_t _packetID, const SimpleType& _data = SimpleType(), unsigned extraBytes = 0)
	: Base(sizeof(SimpleType), WithCRC, _type, _packetID, &_data, extraBytes)
	{
	}

	virtual ~CommHeaderMessage()
	{
	}

	inline const SimpleType* operator->() const
	{
		if (pConversionBaseData)
			return dynamic_cast<const SimpleType*>(pConversionBaseData.get());
		else
			return (const SimpleType*) &data.at(0);
	}

	inline SimpleType* operator->()
	{
		if (pConversionBaseData)
			return dynamic_cast<SimpleType*>(pConversionBaseData.get());
		else
			return (SimpleType*) &data.at(0);
	}

	inline const SimpleType& operator*() const
	{
		if (pConversionBaseData)
			return dynamic_cast<const SimpleType&>(*pConversionBaseData);
		else
			return (const SimpleType&) data.at(0);
	}

	inline SimpleType& operator*()
	{
		if (pConversionBaseData)
			return dynamic_cast<SimpleType&>(*pConversionBaseData);
		else
			return (SimpleType&) data.at(0);
	}
};

#pragma pack(push,1)
template<class CmdParams>
struct CmdLayout
{
	FCCMessage::CMD_FMT_COMMON cmdFormat;
	CmdParams params;
};
#pragma pack(pop)

template<class CmdParams, bool WithCRC = true>
class CommandClass : public CommHeaderMessage< CmdLayout<CmdParams>, WithCRC >
{
public:

	typedef CommHeaderMessage< CmdLayout<CmdParams>, WithCRC > Base;

	CommandClass()
	{
		Base::SetType(RCV_CMD);
	}

	CommandClass(const ByteArray& byteData, unsigned offset)
	: Base(byteData, offset)
	{
	}

	CommandClass(const byte* pData, unsigned dataLength)
	: Base(pData, dataLength)
	{
	}
};

}
}
}

#endif /* FCCMESSAGE_COMMHEADERMESSAGE_H_ */
