#ifndef _CCO_ALL_H_
#define _CCO_ALL_H_

#include <config.h>
#include "fireflier.h"
#include <string>
#include <netinet/in.h>

#if FF_DEBUG
#include <iostream>
using namespace std;
#endif

class CCO_Base
{
public:
	typedef guint16 streamsize;
	

	virtual streamsize getHeaderLen() const = 0;
	virtual streamsize getMsgLen() const = 0;
};


class CCO_SendBase: public CCO_Base
{
public:
	virtual const char* getHeaderBuf() const = 0;
	virtual const char* getMsgBuf() const = 0;
};


class CCO_RetrieveBase: public CCO_Base
{
public:
	virtual char* getHeaderBuf() = 0;
	virtual char* getMsgBuf() = 0;
	virtual void parse() = 0;
};


class CCO_SendCommon: public CCO_SendBase
{
protected:
	char m_pHeaderBuf[2];


public:	
	const char* getHeaderBuf() const
	{
		return m_pHeaderBuf;
	}
	
	streamsize getHeaderLen() const
	{
		return sizeof(m_pHeaderBuf);
	}
	
};


class CCO_IPTablesRuleDelete: public CCO_SendCommon
{
protected:
	char m_pMsgBuf[3];
	

public:
	CCO_IPTablesRuleDelete(const ff::Chains& enChain, const guint16& nRuleNum)
	{
		m_pHeaderBuf[0] = (char) ff::CMD_DELETE_RULE;
		m_pHeaderBuf[1] = 0;
		m_pMsgBuf[0] = (char) enChain;
		*(guint16*) &m_pMsgBuf[1] = htons(nRuleNum);
	}
	

public:
	const char* getMsgBuf() const
	{
		return m_pMsgBuf;
	}
	
	streamsize getMsgLen() const
	{
		return sizeof(m_pMsgBuf);
	}
};


class CCO_Login: public CCO_SendCommon
{
protected:
	char* m_pMsgBuf;
	streamsize m_nMsgLen;


public:
	CCO_Login(const std::string& strUserName, const std::string& strPwd)
		: m_pMsgBuf(NULL)
		, m_nMsgLen(std::streamsize())
	{
		guint16 lenUserName = strUserName.length();
		guint16 lenPwd = strPwd.length();
		m_pMsgBuf = new char[sizeof(guint16)*2+lenUserName+lenPwd];
		if (!m_pMsgBuf)
			throw CffIO::CffIOError(CffIO::COMMERR_NO_MEMORY);
		
		m_pHeaderBuf[0] = ff::CMD_AUTH;
		m_pHeaderBuf[1] = 0;
	
		*(guint16*) (m_pMsgBuf) = htons(lenUserName);
		memcpy(m_pMsgBuf+sizeof(guint16), strUserName.data(), lenUserName);
	
		*(guint16*) (m_pMsgBuf+sizeof(guint16)+lenUserName) = htons(lenPwd);
		if (lenPwd>0)
			memcpy(m_pMsgBuf+sizeof(guint16)*2+lenUserName, strPwd.data(), lenPwd);
		
		m_nMsgLen = sizeof(guint16)*2+lenUserName+lenPwd;
	}
	
	virtual ~CCO_Login()
	{
		delete[] m_pMsgBuf;
		m_pMsgBuf = NULL;
	}
	
	
public:
	const char* getMsgBuf() const
	{
		return m_pMsgBuf;
	}
	
	streamsize getMsgLen() const
	{
		return m_nMsgLen;
	}
};


class CCO_PacketRule: public CCO_SendCommon
{
protected:
	char m_pMsgBuf[15];

	
public:
	CCO_PacketRule(	const ff::Commands& enCmd, 
					const ff::Rulecommands& enRuleCommand, 
					const bool& bSrcIP, 
					const bool& bDstIP, 
					const bool& bSrcPort, 
					const bool& bDstPort, 
					const bool& bInterfaceIn, 
					const bool& bInterfaceOut, 
					const bool& bProtocol, 
					const bool& bTracking, 
					const bool& bProgramName, 
					const guint32& nTimeout)
	{
#if FF_DEBUG
		cerr << "CCO_PacketRule::bProtocol=" << bProtocol << endl;
#endif
		m_pHeaderBuf[0]						= (char) enCmd;
		m_pHeaderBuf[1]						= 0;
		m_pMsgBuf[0]						= (char) enRuleCommand;
		m_pMsgBuf[ff::SB_IP_SRC]			= bSrcIP;
		m_pMsgBuf[ff::SB_IP_DST]			= bDstIP;
		m_pMsgBuf[ff::SB_PORT_SRC]			= bSrcPort;
		m_pMsgBuf[ff::SB_PORT_DST]			= bDstPort;
		m_pMsgBuf[ff::SB_INTERFACE_IN]		= bInterfaceIn;
		m_pMsgBuf[ff::SB_INTERFACE_OUT]		= bInterfaceOut;
		m_pMsgBuf[ff::SB_RESERVED_FOR_MAC]	= 0; // reserved for mac address filtering
		m_pMsgBuf[ff::SB_PROTOCOL]			= bProtocol;
		m_pMsgBuf[ff::SB_CONNTRACK]			= bTracking;
		m_pMsgBuf[ff::SB_PROGRAMNAME]		= bProgramName;
		// bytes 11-14
		// ntohl added.
		*(guint32*) &m_pMsgBuf[11] 			= htonl(nTimeout);
	}
	

public:
	const char* getMsgBuf() const
	{
		return m_pMsgBuf;
	}
	
	streamsize getMsgLen() const
	{
		return sizeof(m_pMsgBuf);
	}
};


class CCO_SimpleRequest: public CCO_SendCommon
{
public:
	CCO_SimpleRequest(const ff::Commands& enCmd)
	{
		m_pHeaderBuf[0]	= (char) enCmd;
		m_pHeaderBuf[1]	= 0;
	}
	

public:
	const char* getMsgBuf() const
	{
		return NULL;
	}
	
	streamsize getMsgLen() const
	{
		return 0;
	}
};


class CCO_USpaceRuleDelete: public CCO_SendCommon
{
protected:
	char m_pMsgBuf[3];
	

public:
	CCO_USpaceRuleDelete(const int& nRuleNum)
	{
		m_pHeaderBuf[0] = (char) ff::CMD_DELETE_URULE;
		m_pHeaderBuf[1] = 0;
		m_pMsgBuf[0] = 0;
		*(streamsize*) &m_pMsgBuf[1] = htons((short)nRuleNum);
	}
	
	
public:
	const char* getMsgBuf() const
	{
		return m_pMsgBuf;
	}
	
	streamsize getMsgLen() const
	{
		return sizeof(m_pMsgBuf);
	}
};


// read CCO_x
class CCO_RetrieveHeader: public CCO_RetrieveBase
{
protected:
	ff::Commands m_enCmd;
	char m_pHeaderBuf[1];


public:
	CCO_RetrieveHeader()
		: m_enCmd(ff::CMD_INVALID)
	{
	}
	
	
public:
	char* getHeaderBuf()
	{
		return m_pHeaderBuf;
	}
	
	streamsize getHeaderLen() const
	{
		return sizeof(m_pHeaderBuf);
	}
	
	char* getMsgBuf()
	{
		return NULL;
	}
	
	streamsize getMsgLen() const
	{
		return 0;
	}
	
	void parse()
	{
		m_enCmd = (ff::Commands) m_pHeaderBuf[0];
	}
	
	ff::Commands getCmd() const
	{
		return m_enCmd;
	}
};


class CCO_RetrieveSimple: public CCO_RetrieveBase
{
protected:
	streamsize m_nMsgLen;
	char m_pHeaderBuf[sizeof(streamsize)];
	char* m_pMsgBuf;
	

public:
	CCO_RetrieveSimple()
		: m_nMsgLen(streamsize())
		, m_pMsgBuf(NULL)
	{
	}
	
	virtual ~CCO_RetrieveSimple()
	{
		if (m_pMsgBuf)
			delete[] m_pMsgBuf;
	}
	
	char* getHeaderBuf()
	{
		return m_pHeaderBuf;
	}
	
	streamsize getHeaderLen() const
	{
		return sizeof(m_pHeaderBuf);
	}

	char* getMsgBuf()
	{
		return m_pMsgBuf;
	}

	streamsize getMsgLen() const
	{
		return m_nMsgLen;
	}

	void parse()
	{
	  unsigned short *addr_len;

		if (m_pMsgBuf)
			delete[] m_pMsgBuf;
		m_pMsgBuf = NULL;

		addr_len = (unsigned short *)  m_pHeaderBuf;
		m_nMsgLen = (streamsize) ntohs(*addr_len);
		m_pMsgBuf = new char[m_nMsgLen];
	}
};


class CCO_RetrieveSrc: public CCO_RetrieveSimple
{
public:
	CCO_RetrieveSrc(streamsize nMsgLen)
	{
		m_nMsgLen = nMsgLen;
		m_pMsgBuf = new char[nMsgLen];
	}
	
	~CCO_RetrieveSrc()
	{
	}

	char* getHeaderBuf()
	{
		return NULL;
	}
	
	streamsize getHeaderLen() const
	{
		return 0;
	}
	
	void parse()
	{
	}
};


class CCO_RetrieveLogin: public CCO_RetrieveBase
{
protected:
	char m_pMsgBuf[1];


public:
	CCO_RetrieveLogin()
	{
	}
	
	
public:
	char* getHeaderBuf()
	{
		return NULL;
	}
	
	streamsize getHeaderLen() const
	{
		return 0;
	}
	
	char* getMsgBuf()
	{
		return m_pMsgBuf;
	}
	
	streamsize getMsgLen() const
	{
		return sizeof(m_pMsgBuf);
	}
	
	void parse()
	{
	}
	
	int getAuth() const
	{
		return (int) m_pMsgBuf[0];
	}
};


#endif // #ifdef _CCO_ALL_H_
