/**
 * @file TrafficCaptureMessage.cpp
 * @author Tomas Urban
 * @version 0.2
 * @date 23/07/2009
 */
#include "TrafficCaptureMessage.h"
#include <string.h>

TrafficCaptureMessage::TrafficCaptureMessage(void)
{
	m_pData = 0;
	m_nDataLen = 0;
}

TrafficCaptureMessage::~TrafficCaptureMessage(void)
{
	DisposeEncodedData();
}

void TrafficCaptureMessage::DisposeEncodedData()
{
	delete m_pData;
	m_pData = 0;
	m_nDataLen = 0;
}

void TrafficCaptureMessage::EncodeData(const void * pData, size_t nSize, unsigned int & nOffset)
{
	if (!pData || !nSize)
		return;
	memcpy(&m_pData[nOffset], pData, nSize);
	nOffset += nSize;
}

void TrafficCaptureMessage::EncodeUChar(unsigned char nValue, unsigned int & nOffset)
{
	EncodeData(&nValue, sizeof(unsigned char), nOffset);
}

void TrafficCaptureMessage::EncodeUShort(unsigned short nValue, unsigned int & nOffset)
{
	EncodeData(&nValue, sizeof(unsigned short), nOffset);
}

void TrafficCaptureMessage::EncodeInt(int nValue, unsigned int & nOffset)
{
	EncodeData(&nValue, sizeof(int), nOffset);
}
void TrafficCaptureMessage::EncodeUInt(unsigned int nValue, unsigned int & nOffset)
{
	EncodeData(&nValue, sizeof(unsigned int), nOffset);
}

void TrafficCaptureMessage::EncodeTime(struct timeval & timestamp, unsigned int & nOffset)
{
	unsigned long long nSec = timestamp.tv_sec;
	EncodeData(&nSec, sizeof(unsigned long long), nOffset);
	EncodeUInt(timestamp.tv_usec, nOffset);
}

void TrafficCaptureMessage::EncodeBool(bool bValue, unsigned int & nOffset)
{
	m_pData[nOffset++] = (char)bValue;
}

void TrafficCaptureMessage::EncodeString(const std::string & sValue, unsigned int & nOffset)
{
	unsigned int nLen = sValue.length();
	EncodeUInt(nLen, nOffset);
	EncodeData(sValue.c_str(), nLen, nOffset);
}

unsigned int TrafficCaptureMessage::CalculateDataLength()
{
	return 
		sizeof(unsigned short) // 2 byte id
		+ sizeof(m_nDataLen); // 4 byte length
}

unsigned int TrafficCaptureMessage::CalculateStringLength(const std::string & sValue)
{
	return sizeof(unsigned int) + sValue.length();
}

void TrafficCaptureMessage::EncodePayload(unsigned int & nOffset)
{
}

void TrafficCaptureMessage::Encode()
{
	m_nDataLen = CalculateDataLength();
	m_pData = new char[m_nDataLen];
	unsigned int nOffset = 0;
	EncodeUShort(GetId(), nOffset);
	unsigned int nPayloadLen = m_nDataLen - sizeof(unsigned short) - sizeof (m_nDataLen);
	EncodeUInt(nPayloadLen, nOffset);
	EncodePayload(nOffset);
}

const char * TrafficCaptureMessage::GetEncodedMessage()
{
	if (!m_pData)
		Encode();
	return m_pData;
}

unsigned int TrafficCaptureMessage::GetEncodedDataLength()
{
	if (!m_pData)
		Encode();
	return m_nDataLen;
}

bool TrafficCaptureMessage::DecodeData(void * pValue, size_t nValueSize, const char * pData, 
									   unsigned int nDataLen, unsigned int & nOffset)
{
	if (nOffset + nValueSize > nDataLen)
		return false;
	memcpy(pValue, &pData[nOffset], nValueSize);
	nOffset += nValueSize;
	return true;
}

bool TrafficCaptureMessage::DecodeUChar(unsigned char & nValue, const char * pData, unsigned int nDataLen, 
										 unsigned int & nOffset)
{
	return DecodeData(&nValue, sizeof(unsigned char), pData, nDataLen, nOffset);
}

bool TrafficCaptureMessage::DecodeUShort(unsigned short & nValue, const char * pData, unsigned int nDataLen, 
										 unsigned int & nOffset)
{
	return DecodeData(&nValue, sizeof(unsigned short), pData, nDataLen, nOffset);
}
bool TrafficCaptureMessage::DecodeInt(int & nValue, const char * pData, unsigned int nDataLen, 
									  unsigned int & nOffset)
{
	return DecodeData(&nValue, sizeof(int), pData, nDataLen, nOffset);
}
bool TrafficCaptureMessage::DecodeUInt(unsigned int & nValue, const char * pData, unsigned int nDataLen, 
									   unsigned int & nOffset)
{
	return DecodeData(&nValue, sizeof(unsigned int), pData, nDataLen, nOffset);
}

bool TrafficCaptureMessage::DecodeTime(struct timeval & timestamp, const char * pData, unsigned int nDataLen, 
									   unsigned int & nOffset)
{
	unsigned long long nSec;
	if (!DecodeData(&nSec, sizeof(unsigned long long), pData, nDataLen, nOffset))
		return false;
#ifdef WIN32
	timestamp.tv_sec = static_cast<int>(nSec);
#else
	timestamp.tv_sec = nSec;
#endif	
	int nMicrosec;
	if (!DecodeInt(nMicrosec, pData, nDataLen, nOffset))
		return false;
	timestamp.tv_usec = nMicrosec;
	return true;
}

bool TrafficCaptureMessage::DecodeBool(bool & bValue, const char * pData, unsigned int nDataLen, 
									   unsigned int & nOffset)
{
	if (nOffset + 1 > nDataLen)
		return false;
	bValue = pData[nOffset++] != 0;
	return true;
}

bool TrafficCaptureMessage::DecodeString(std::string & sValue, const char * pData, 
										 unsigned int nDataLen, unsigned int & nOffset)
{
	unsigned int nLen;
	if (!DecodeUInt(nLen, pData, nDataLen, nOffset))
		return false;
	char * pszTmp = new char [nLen + 1];
	bool bRes = DecodeData(pszTmp, nLen, pData, nDataLen, nOffset);
	if (bRes)
	{
		pszTmp[nLen] = '\0';
		sValue = pszTmp;
	}
	delete pszTmp;
	return bRes;
}

bool TrafficCaptureMessage::DecodePayload(const char * pPayload, unsigned int nPayloadLength, 
										  unsigned int & nOffset)
{
	return true;
}

bool TrafficCaptureMessage::DecodePayload(const char * pPayload, unsigned int nPayloadLength)
{
	unsigned int nOffset = 0;
	bool bRes = DecodePayload(pPayload, nPayloadLength, nOffset);
	bRes &= nPayloadLength == nOffset; // verify that there's no unprocessed data left
	return bRes;
}

CommonReplyMessage::CommonReplyMessage() :
	m_bResult(false)
{
}

unsigned int CommonReplyMessage::CalculateDataLength()
{
	return TrafficCaptureMessage::CalculateDataLength() + 1; // bool is encoded into 1 byte
}

void CommonReplyMessage::EncodePayload(unsigned int & nOffset)
{
	TrafficCaptureMessage::EncodePayload(nOffset);
	EncodeBool(m_bResult, nOffset);
}

bool CommonReplyMessage::DecodePayload(const char * pPayload, unsigned int nPayloadLength, 
									   unsigned int & nOffset)
{
	if (!TrafficCaptureMessage::DecodePayload(pPayload, nPayloadLength, nOffset))
		return false;
	if (!DecodeBool(m_bResult, pPayload, nPayloadLength, nOffset))
		return false;
	return true;
}

void CommonReplyMessage::SetResult(bool bResult)
{
	DisposeEncodedData();
	m_bResult = bResult;
}

