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

SipDissector::SipDissector() :
	m_nMessageLength(HEADER_NOT_PARSED)
{
}

SipDissector::~SipDissector() 
{
}

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

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

bool SipDissector::FinishDissection()
{
  if (m_nMessageLength == PARSING_ERROR) {
    return true;
  }
	// detect SIP header
	int i = 0;
	ssize_t nDataLen = GetPayloadSize();
	const unsigned char * pData = GetPayload();
	std::string s(reinterpret_cast<const char *>(pData), nDataLen);
	if (m_nMessageLength == HEADER_NOT_PARSED)
	{
		int nIndex = s.find("\r\n");
		if (nIndex > -1)
		{
			std::string sTmp = s.substr(0, nIndex);
			boost::regex rgx1("(\\A.* SIP/[0-9]+[\\.][0-9]+)|(\\ASIP/[0-9]+[\\.][0-9]+ .*)", boost::regex::perl|boost::regex::icase);
			if (!boost::regex_match(sTmp, rgx1))
			{
			  Logger::Instance().LogError("Invalid SIP message");
			  m_nMessageLength = PARSING_ERROR;
			  return true;
			}
			else
			  m_nMessageLength = LENGTH_NOT_PARSED;
		}
	}
	if (m_nMessageLength == LENGTH_NOT_PARSED)
	{
		int nIndex = s.find("\r\n\r\n");
		if (nIndex > -1)
		{
			std::string sTmp = s.substr(0, nIndex);
			boost::regex rgxContentLength("^(?:(?:Content-Length)|l)[ \\t]*[:]\\s*([0-9]+)$",
				boost::regex::perl|boost::regex::icase);
			boost::smatch matches;
			if (boost::regex_search(sTmp, matches, rgxContentLength))
			{
				std::string sLen(matches[1].first, matches[1].second);
				m_nMessageLength = sTmp.length() + 4 + boost::lexical_cast<int>(sLen);
			}
		}
	}
	if (m_nMessageLength >= 0 && m_nMessageLength < nDataLen) 
		// unlikely case: two or more messages came in one packet
		SeparateUnprocessedData(m_nMessageLength);

	return m_nMessageLength >= 0 && m_nMessageLength <= nDataLen;
}


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

  SavePayload(pData, nDataLength);
  return true;
}

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

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

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

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

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