/* 
*	File: nikonMessage.cpp
*	Author: Eric Martin
*	
*	Copyright: 2013 MBARI 
*	
*	The NikonMessage class handles the translation of binary messages
*	typically sent via tcp to the handling program. All messages 
*	consist of a header which contains a start byte, action byte, command
*	byte and following data.
*	
*	This class is based upon similar object to binary service written
*	in the edgetech support libraries.
*	
*/
#include "nikonMessage.h"

NikonMessage::~NikonMessage(void)
{
}

//////////////////
//Decoder services

NikonMessage::NikonMessage(NikonMessageHeaderType *pHeader):
	m_ulMessageHeaderSize(sizeof(NikonMessageHeaderType)), m_ulMaxMessageLength(ulMaxNikonDynamicDataSize_c)
{
	m_pMessageBuffer = new CBufferManager();

	SetHeader(pHeader);
}

bool NikonMessage::SetHeader(NikonMessageHeaderType *pHeader) {
	bool bSuccess = false;

	assert( pHeader != NULL);

	if (pHeader != NULL) {
		bSuccess = m_pMessageBuffer->SetBuffer((unsigned char *) pHeader, m_ulMessageHeaderSize + pHeader->byteCount, false);
	}

	if (pHeader->startOfMessage != NIKON_MESSAGE_HEADER_START) {
		return false;
	}

	return bSuccess;
}



/////////////////
// Encoder Services
/*
*	Constructor - set the header to supplied values.
*/
NikonMessage::NikonMessage(		unsigned short unMessage, unsigned char  ucCommand, unsigned char  ucCameraID):
		m_ulMessageHeaderSize(sizeof(NikonMessageHeaderType)), m_ulMaxMessageLength((unsigned long) ulMaxNikonDynamicDataSize_c)

{
	m_pMessageBuffer = (new CBufferManager());

	if (!SetHeader(unMessage, ucCommand, ucCameraID)) {
		printf("%s", "NikonMessage::NikonMessage(), Can't set header\n");
	}
}

/*
*	Set the header bytes
*/
bool NikonMessage::SetHeader(unsigned short unMessage, unsigned char ucCommand, unsigned char ucCameraID) {
	if ((m_pMessageBuffer->SetBuffer(NULL, m_ulMessageHeaderSize, true))) {
		NikonMessageHeaderType *psHeader = (NikonMessageHeaderType *) m_pMessageBuffer->GetMessage();

		memset(psHeader, 0x00, m_ulMessageHeaderSize);

		psHeader->startOfMessage = NIKON_MESSAGE_HEADER_START;
		psHeader->version = 0;

		psHeader->nikonMessage = unMessage;
		psHeader->nikonCommand = ucCommand;
		psHeader->cameraID = ucCameraID;
		psHeader->byteCount = 0;

		return true;
	}

	return false;
}

/*
*	Set the message byte in the header
*/
bool NikonMessage::SetMessage(unsigned short unMessage, unsigned char ucCommand, unsigned char *pbyMessage, unsigned long ulBytesInMessage, unsigned char ucCameraID) {

	if ((m_pMessageBuffer->SetBuffer(NULL, m_ulMessageHeaderSize + ulBytesInMessage, true))) {
		NikonMessageHeaderType *psHeader = (NikonMessageHeaderType *) m_pMessageBuffer->GetMessage();

		memset(psHeader, 0x00, m_ulMessageHeaderSize);

		psHeader->startOfMessage = NIKON_MESSAGE_HEADER_START;
		psHeader->version = 0;

		psHeader->nikonMessage = unMessage;
		psHeader->nikonCommand = ucCommand;
		psHeader->cameraID = ucCameraID;
		psHeader->byteCount = 0;

		if ((ulBytesInMessage > 0UL) && (ulBytesInMessage < m_ulMaxMessageLength)) {
			if (pbyMessage != NULL) {
				unsigned char *pbyDestination = ((unsigned char *) psHeader) + m_ulMessageHeaderSize;

				memcpy(pbyDestination, pbyMessage, ulBytesInMessage);

				psHeader->byteCount = ulBytesInMessage;
			}
		}

		return true;
	}

	return false;
}

/*
*	Constructor - from existing message.
*/
NikonMessage::NikonMessage(const NikonMessage &rRhs):
		m_ulMessageHeaderSize(sizeof(NikonMessageHeaderType)), m_ulMaxMessageLength(ulMaxNikonDynamicDataSize_c) 
{

	m_pMessageBuffer = (new CBufferManager);
	m_pMessageBuffer = rRhs.m_pMessageBuffer;
}

/*
*	Return a pointer to the message buffer's start in memory
*/
unsigned char * NikonMessage::Message(void) const {
	return m_pMessageBuffer->GetMessage();
}

/*
*	return the constant for the message buffer's data contents
*/
unsigned short NikonMessage::NikonCameraMessage(void) const {
	return ((NikonMessageHeaderType *) m_pMessageBuffer->GetMessage())->nikonMessage;
}

/*
*  return the constant of the command in the header
*/
unsigned char NikonMessage::NikonCommand(void) const {
	return ((NikonMessageHeaderType *) m_pMessageBuffer->GetMessage())->nikonCommand;
}

/*
*	return the size of the message in the buffer
*/
unsigned long NikonMessage::MessageSize(void) const {
	unsigned long ulTotalBytes = 0UL;

	ulTotalBytes = m_pMessageBuffer->MessageSize();

	return ulTotalBytes;
}

/*
* copy this class to the one supplied.
*/
NikonMessage & NikonMessage::operator =(const NikonMessage &rRhs) {
	m_pMessageBuffer = rRhs.m_pMessageBuffer;

	return *this;
}

/*
* return a pointer to the data follow the header of the message in the buffer.
*/
unsigned char * NikonMessage::OptionalData(void) const {
	return (((unsigned char *) (m_pMessageBuffer->GetMessage())) + sizeof(NikonMessageHeaderType));
}

//////////////////////////////////////////////////////////////////////
// Conversion operators.

NikonMessage::operator NikonMessageHeaderType *() const {
//	assert( m_pMessageBuffer.get() != NULL);
	return ((::NikonMessageHeaderType *) m_pMessageBuffer->GetMessage());
}

NikonMessage::operator long() const {
	return ((long) (((::NikonMessageLongType *) OptionalData())->value));
}

NikonMessage::operator unsigned long() const {
	return ((unsigned long) (((::NikonMessageLongType *) OptionalData())->value));
}

NikonMessage::operator char *() const {
	return ((char *) (((::NikonMessageStringType *) OptionalData())->name));
}

NikonMessage::operator NikonMessageStatusType *() const {
	return ((::NikonMessageStatusType *) OptionalData());
}

NikonMessage::operator NikonMessageUARTType *() const {
	return ((::NikonMessageUARTType *) OptionalData());
}

//////////////////////////////////////////////////////////////////////
// Internal helper class NikonMessage::CBufferManager implementation.

inline NikonMessage::CBufferManager::CBufferManager(void) {
	m_pbyBuffer = NULL;
	m_ulBufferSize = 0UL;
	m_bIsOwner = false;
}

inline NikonMessage::CBufferManager::CBufferManager(const NikonMessage::CBufferManager &rRhs) {
	m_pbyBuffer = NULL;
	m_ulBufferSize = 0UL;
	m_bIsOwner = false;

	SetBuffer(rRhs.m_pbyBuffer, rRhs.m_ulBufferSize, rRhs.m_bIsOwner);
}

inline NikonMessage::CBufferManager &
NikonMessage::CBufferManager::operator =(const NikonMessage::CBufferManager &rRhs) {
	m_pbyBuffer = NULL;
	m_ulBufferSize = 0UL;
	m_bIsOwner = false;

	SetBuffer(rRhs.m_pbyBuffer, rRhs.m_ulBufferSize, rRhs.m_bIsOwner);

	return *this;
}

inline NikonMessage::CBufferManager::~CBufferManager(void) {
	Release();
}



inline
bool NikonMessage::CBufferManager::SetBuffer(unsigned char *pbyBuffer, const unsigned long &rulMaxSize, const bool &rbAllocate) {
	Release();                 // Ensure any previously used buffer is released.

	assert( rulMaxSize > 0UL);

	m_ulBufferSize = rulMaxSize;
	m_bIsOwner = rbAllocate;

	if (rbAllocate) {
		m_pbyBuffer = new unsigned char[rulMaxSize];

		if (pbyBuffer != NULL) {
			::memcpy(m_pbyBuffer, pbyBuffer, rulMaxSize);
		}
	} else {
		assert( pbyBuffer != NULL);
		m_pbyBuffer = pbyBuffer;
	}

	return ((m_pbyBuffer != NULL) && (m_ulBufferSize > 0UL));
}

inline
void NikonMessage::CBufferManager::Release(void) {
	if ((m_pbyBuffer != NULL) && m_bIsOwner) {
		delete[] m_pbyBuffer;
	}

	m_pbyBuffer = NULL;
	m_ulBufferSize = 0UL;
	m_bIsOwner = false;
}

inline
unsigned char * NikonMessage::CBufferManager::GetMessage(void) {
	return m_pbyBuffer;
}

inline
unsigned long NikonMessage::CBufferManager::MessageSize(void) const {
	return m_ulBufferSize;
}