#include "Dissector.h"
#include "Logger/Logger.h"

Dissector::Dissector() :
	m_pPayload(0),
	m_nPayloadSize(0),
	m_pLayerInfo(0),
	m_pUnprocessedData(0),
	m_nUnprocessedSize(0),
	m_pProtocolInfo(0)
{
}

Dissector::~Dissector()
{
	delete[] m_pPayload;
	delete[] m_pUnprocessedData;
	delete m_pLayerInfo;
	delete m_pProtocolInfo;
}

bool Dissector::IsPacketValid() const
{ 
	return true; 
}

bool Dissector::FinishDissection()
{ 
	return false; 
}

bool Dissector::Reassemble(Dissector * pDissector, ProtocolInfo * pProtocolInfo)
{
  Logger::Instance().LogError("Dissector does not support reassembly");
  return false;
}

void Dissector::SaveResult(DispatchInfo & info) const
{
	info.SetData(m_pPayload, m_nPayloadSize);
	if (m_pLayerInfo)
		info.AddProtocolInfo(m_pLayerInfo->Clone());
}

void Dissector::SavePayload(const unsigned char * pData, ssize_t nPayloadSize)
{
	AllocPayload(nPayloadSize);
	if (nPayloadSize > 0)
		memcpy(m_pPayload, pData, m_nPayloadSize);
}

void Dissector::AllocPayload(ssize_t nPayloadSize)
{
	delete[] m_pPayload;
	if (nPayloadSize > 0)
	{
		m_nPayloadSize = nPayloadSize;
		m_pPayload = new unsigned char[nPayloadSize];
	}
	else
	{
		m_nPayloadSize = 0;
		m_pPayload = 0;
	}
}

void Dissector::SetPayloadAt(const unsigned char * pSrcData, ssize_t nSrcSize, int nOffset)
{
	memcpy(&m_pPayload[nOffset], pSrcData, nSrcSize);
}

void Dissector::AppendPayload(Dissector * pSrc)
{
	int nTgtSize = m_nPayloadSize + pSrc->m_nPayloadSize;
	unsigned char * pTmp = 0;
	if (nTgtSize)
	{
		pTmp = new unsigned char [m_nPayloadSize + pSrc->m_nPayloadSize];
		if (m_nPayloadSize)
			memcpy(pTmp, m_pPayload, m_nPayloadSize);
		if (pSrc->m_nPayloadSize)
			memcpy(&pTmp[m_nPayloadSize], pSrc->m_pPayload, pSrc->m_nPayloadSize);
	}
	delete m_pPayload;
	m_nPayloadSize = nTgtSize;
	m_pPayload = pTmp;
}
unsigned char * Dissector::GetPayload() const
{
	return m_pPayload;
}

ssize_t Dissector::GetPayloadSize() const
{
	return m_nPayloadSize;
}

std::pair<unsigned char *, ssize_t> Dissector::DetachData()
{
	std::pair<unsigned char *, ssize_t> res(m_pPayload, m_nPayloadSize);
	m_pPayload = 0;
	m_nPayloadSize = 0;
	return res;
}

void Dissector::SaveLayerInfo()
{
	std::clog << ">>> Dissector::SaveLayerInfo" << std::endl;

	delete m_pLayerInfo;
	m_pLayerInfo = CreateLayerInfo();
}

ProtocolInfoElement * Dissector::GetLayerInfo() const
{
	std::clog << ">>> Dissector::GetLayerInfo" << std::endl;

	return m_pLayerInfo;
}

void Dissector::SeparateUnprocessedData(int nNewPayloadSize)
{
	std::clog << ">>> Dissector::SeparateUnprocessedData" << std::endl;

	if (nNewPayloadSize >= m_nPayloadSize)
		return;
	delete [] m_pUnprocessedData;
	m_nUnprocessedSize = m_nPayloadSize - nNewPayloadSize;
	m_pUnprocessedData = new unsigned char[m_nUnprocessedSize];
	memcpy(m_pUnprocessedData, &m_pPayload[nNewPayloadSize], m_nUnprocessedSize);
	unsigned char * pTmp = 0;
	if (nNewPayloadSize != 0)
	{
		pTmp = new unsigned char[nNewPayloadSize];
		memcpy(pTmp, m_pPayload, nNewPayloadSize);
	}
	delete [] m_pPayload;
	m_pPayload = pTmp;
	m_nPayloadSize = nNewPayloadSize;
}

bool Dissector::CreatesUnprocessedData() const
{
	return false;
}

bool Dissector::ContainsUnprocessedData()
{
	return m_nUnprocessedSize > 0;
}

std::pair<const unsigned char *, ssize_t> Dissector::GetUnprocessedData() const
{
	std::pair<unsigned char *, ssize_t> res(m_pUnprocessedData, m_nUnprocessedSize);
	return res;
}

ProtocolInfo * Dissector::GetProtocolInfo() const
{
	std::clog << ">>> Dissector::GetProtocolInfo" << std::endl;

	return m_pProtocolInfo;
}
void Dissector::SetProtocolInfo(ProtocolInfo * pInfo)
{
	std::clog << ">>> Dissector::SetProtocolInfo(" << std::endl;

	delete m_pProtocolInfo;
	m_pProtocolInfo = pInfo;
}

bool Dissector::MatchProtocolInfo(ProtocolInfo * pInfo) const
{
	std::clog << ">>> Dissector::MatchProtocolInfo(" << std::endl;

	if (!m_pProtocolInfo || !pInfo)
		return !m_pProtocolInfo && !pInfo;
	return m_pProtocolInfo->Match(*pInfo);
}
