#include "DiameterDissector.h"
#include "Logger/Logger.h"
#include <boost/regex.hpp>

#include <iomanip>
#include <ios>
#include <iostream>
 
#include <stdlib.h>

DiameterDissector::DiameterDissector() :
	m_nMessageLength(HEADER_NOT_PARSED)
{
}

DiameterDissector::~DiameterDissector() 
{
}

DiameterDissector * DiameterDissector::Clone() const 
{
  return new DiameterDissector();
}

bool DiameterDissector::IsPacketValid() const
{
  return m_nMessageLength != PARSING_ERROR;
}

bool DiameterDissector::FinishDissection()
{
  if (m_nMessageLength == PARSING_ERROR) {
    return true;
  }
	// detect DIAMETER header
	const unsigned char * pData = GetPayload();
	unsigned int nLen = 0;
	std::cout << std::hex << std::setfill('0') << std::setw(2) << *pData << std::endl;
	if (m_nMessageLength == HEADER_NOT_PARSED)
	{
		if (*pData != 0x01) // Diameter version
		{
		  Logger::Instance().LogError("Invalid DIAMETER message, bad version number");
		  m_nMessageLength = PARSING_ERROR;
		  return true;
		}
		else
		{
		  m_nMessageLength = LENGTH_NOT_PARSED;
		  //pData += 1;
		  nLen = (*(unsigned int *)pData) & 0xFFFFFF00;
		  nLen = ((nLen &0x0000FF00)<<8) | ((nLen & 0x00FF0000) >> 8)|((nLen & 0xFF000000) >> 24);
		  std::cout << std::hex << std::setfill('0') << std::setw(2) << nLen << std::endl;
		}
	}
	if (m_nMessageLength == LENGTH_NOT_PARSED)
	{
	  m_nMessageLength = nLen;
	  std::cout << "DiameterDissector::FinishDissection: len= " << m_nMessageLength << std::endl;
	  pData += 4;
	  std::cout << std::hex << std::setfill('0') << std::setw(2) << *pData << std::endl;
	}

	return m_nMessageLength >= 0;
}


bool DiameterDissector::Dissect(const unsigned char * pData, const ssize_t nDataLength) 
{
	std::clog << ">>> DiameterDissector::Dissect: " << pData << std::endl;

  SavePayload(pData, nDataLength);
  return true;
}

bool DiameterDissector::NeedReassembly() const 
{
  return m_nMessageLength < 0 || m_nMessageLength > GetPayloadSize();
}

bool DiameterDissector::Reassemble(Dissector * pDissector, ProtocolInfo * pProtocolInfo) 
{
  if (!MatchProtocolInfo(pProtocolInfo)) {
    return false; // Different addresses or ports than expected
  }
  AppendPayload(pDissector);
  FinishDissection();
  return true;
}

const EProtocolType DiameterDissector::GetUpperLayerType() const 
{
  return EProtocolType_None;
}

ProtocolInfoElement * DiameterDissector::CreateLayerInfo()
{
	return 0;
}

bool DiameterDissector::CreatesUnprocessedData() const
{
  return true;
}
