/**
 * @file TrafficCaptureMessage.h
 * This header file contains basic definition for TCP/IP based communication with the
 * TrafficCapture application.
 * @author Tomas Urban
 * @version 0.1
 * @date 16/07/2009
 */
#ifndef TRAFFIC_CAPTURE_MESSAGE_H
#define TRAFFIC_CAPTURE_MESSAGE_H
#include <string>

#ifdef WIN32
#include <Winsock2.h>
#else
#include <sys/time.h>
#endif

/**
 * The enumeration contains means which can be used for traffic capture.
 */
enum ECaptureType 
{ 
	ECaptureType_PCAP /**< PCAP library (for capturing network traffic on link-layer lever) */
};
/**
 * The enumeration defines the mode in which traffic capture occurs.
 */
enum ECaptureMode 
{ 
	ECaptureMode_Live, /**< Traffic capture occurs in real time */
	ECaptureMode_Offline /**< Traffic capture is based on saved data from previous sessions */
};

/**
 * The enumeration defines results of traffic capture initialization.
 */
enum ECaptureInitResult 
{ 
	ECaptureInit_Successful, /**< Init succeeded */
	ECaptureInit_Failed, /**< Init completely failed, nothing can be captured */
	ECaptureInit_PartiallySuccessful /**< Init wasn't completely successful, but there' at least one device available for capture */
};

#pragma pack(1)
/**
 * Common message header of data message used in communication with the TrafficCapture
 * application. It is usually used for reading the header data from the socket input stream.
 */
struct TMessageHeader
{	
	unsigned short nMsgType; /**< Contains message type */
	unsigned int nMsgLen; /**< Contains length of the payload */

};
#pragma pack()

/**
 * Abstract superclass for all data messages used in communication with the TrafficCapture
 * application. It defines methods for handling the content of message header and common
 * encoding and decoding methods.\n
 * The implementation solution for message classes uses strategy and factory patterns.
 * Child classes containing definitions of real messages should implement the following:\n
 * 1. #GetId() method returning the message ID\n
 * 2. Member variables and methods for setting and getting message properties\n
 * 3. Methods for encoding and decoding message properties\n\n
 * There are two basic use cases how instances of can be used.\n
 * 1. When sending a message:\n
 * a. Create an instance of the class using its constructor\n
 * b. Initialize message values\n
 * c. Write the message to a socket stream using the #GetEncodedMessage() and 
 * #GetEncodedDataLength() methods\n\n
 * 2. When receiving a message:\n
 * a. Read the message header from a socket stream\n
 * b. Using the length information contained in the header, read the payload from the
 * socket stream\n
 * c. Instantiate the message using TrafficCaptureMessageFactory. The message instantiated
 * this way will be automatically decoded.\n
 * d. Read value data from the message
 */
class TrafficCaptureMessage
{
private:
	char * m_pData;
	unsigned int m_nDataLen;
	void Encode();
protected:
	TrafficCaptureMessage(void);
	/**
	 * This constant contains the size of encoded timestamp. It is usually used
	 * in the #CalculateDataLength() method.
	 */
	static const size_t TIME_SIZE = 12;
	/**
	 * Disposes the encoded data. This method is called by set operations of child
	 * classes.
	 */
	void DisposeEncodedData();
	/**
	 * The method calculates the size of the buffer needed for storing encoded data.
	 * If a child class introduces new data fields which increase the encoding size, 
	 * the number returned by this method has to be increased accordingly.
	 * @return Number of bytes needed for storing the encoded message
	 */
	virtual unsigned int CalculateDataLength();
	/**
	 * Returns number of bytes needed for storing the string. Encoded string is 
	 * composed of a 2-byte length field followed by a byte buffer of variable size
	 * containg string data (without terminating zero). This method is usually used
	 * inside the #CalculateDataLength() method
	 * @param sValue String whose length should be calculated
	 * @return Number of bytes needed for storing the encoded string
	 */
	unsigned int CalculateStringLength(const std::string & sValue);
	/**
	 * The method encodes message payload. This method shall be overriden if a child
	 * class introduces new data fields. These fields shall be encoded using the 
	 * encoding methods provided by this class.
	 * @param nOffset Contains the writing position in the underlying data buffer.
	 * The parameter is required for encoding methods provided by this class. It's value
	 * should never be changed manually.
	 */
	virtual void EncodePayload(unsigned int & nOffset);
	/**
	 * Writes raw binary data to a buffer containing encoded data.
	 * @param pData Binary data to write
	 * @param nSize Size of the binary data
	 * @param nOffset Writing position
	 */
	void EncodeData(const void * pData, size_t nSize, unsigned int & nOffset);
	/**
	 * Writes a single unsigned byte to a buffer containing encoded data.
	 * @param nValue Value to write
	 * @param nOffset Writing position
	 */
	void EncodeUChar(unsigned char nValue, unsigned int & nOffset);
	/**
	 * Writes an unsigned short number (2 bytes) to a buffer containing encoded data.
	 * @param nValue Value to write
	 * @param nOffset Writing position
	 */
	void EncodeUShort(unsigned short nValue, unsigned int & nOffset);
	/**
	 * Writes a signed int number (4 bytes) to a buffer containing encoded data.
	 * @param nValue Value to write
	 * @param nOffset Writing position
	 */
	void EncodeInt(int nValue, unsigned int & nOffset);
	/**
	 * Writes an unsigned int number (4 bytes) to a buffer containing encoded data.
	 * @param nValue Value to write
	 * @param nOffset Writing position
	 */
	void EncodeUInt(unsigned int nValue, unsigned int & nOffset);
	/**
	 * Writes a time_t value to a buffer containing encoded data. 
	 * @param timestamp Timestamp to write
	 * @param nOffset Writing position
	 */
	void EncodeTime(struct timeval & timestamp, unsigned int & nOffset);
	/**
	 * Writes a bool value to a buffer containing encoded data. The encoding size
	 * is 1 byte.
	 * @param bValue Value to write
	 * @param nOffset Writing position
	 */
	void EncodeBool(bool bValue, unsigned int & nOffset);
	/**
	 * Writes a string value to a buffer containing encoded data. Encoded string is
	 * composed of a 2-byte length field followed by a byte buffer of variable size
	 * containg string data (without terminating zero).
	 * @param sValue String to write
	 * @param nOffset Writing position
	 */
	void EncodeString(const std::string & sValue, unsigned int & nOffset);
	/**
	 * The method decodes message payload. This method shall be overriden if a child
	 * class introduces new data fields. These fields can be decoded using the 
	 * decoding methods provided by this class.
	 * @param pPayload Pointer to the byte buffer containing encoded payload data
	 * @param nPayloadLength Length of the payload data
	 * @param nOffset Contains the reading position in the payload data buffer.
	 * The parameter is required for decoding methods provided by this class.
	 * @return \c true if decoding was successful, \c false otherwise
	 */
	virtual bool DecodePayload(const char * pPayload, unsigned int nPayloadLength, unsigned int & nOffset);
	/**
	 * Reads raw binary data from a data buffer and copies it to a target buffer.
	 * @param pValue Target buffer
	 * @param nValueSize Size of the target buffer
	 * @param pData Buffer containing encoded payload data
	 * @param nDataLen Length of the payload data
	 * @param nOffset Reading position
	 * @return \c true if decoding was successful, \c false otherwise 
	 */
	bool DecodeData(void * pValue, size_t nValueSize, const char * pData, unsigned int nDataLen, 
		unsigned int & nOffset);
	/**
	 * Reads a single unsigned byte from a data buffer.
	 * @param nValue Target value
	 * @param pData Buffer containing encoded payload data
	 * @param nDataLen Length of the payload data
	 * @param nOffset Reading position
	 * @return \c true if decoding was successful, \c false otherwise
	 */
	bool DecodeUChar(unsigned char & nValue, const char * pData, unsigned int nDataLen, unsigned int & nOffset);
	/**
	 * Reads an unsigned short number (2 bytes) from a data buffer.
	 * @param nValue Target value
	 * @param pData Buffer containing encoded payload data
	 * @param nDataLen Length of the payload data
	 * @param nOffset Reading position
	 * @return \c true if decoding was successful, \c false otherwise
	 */
	bool DecodeUShort(unsigned short & nValue, const char * pData, unsigned int nDataLen, unsigned int & nOffset);
	/**
	 * Reads a signed int number (4 bytes) from a data buffer.
	 * @param nValue Target value
	 * @param pData Buffer containing encoded payload data
	 * @param nDataLen Length of the payload data
	 * @param nOffset Reading position
	 * @return \c true if decoding was successful, \c false otherwise
	 */
	bool DecodeInt(int & nValue, const char * pData, unsigned int nDataLen, unsigned int & nOffset);
	/**
	 * Reads an unsigned int number (4 bytes) from a data buffer.
	 * @param nValue Target value
	 * @param pData Buffer containing encoded payload data
	 * @param nDataLen Length of the payload data
	 * @param nOffset Reading position
	 * @return \c true if decoding was successful, \c false otherwise
	 */
	bool DecodeUInt(unsigned int & nValue, const char * pData, unsigned int nDataLen, unsigned int & nOffset);
	/**
	 * Reads a timestamp from a data buffer.
	 * @param timestamp Target timestamp
	 * @param pData Buffer containing encoded payload data
	 * @param nDataLen Length of the payload data
	 * @param nOffset Reading position
	 * @return \c true if decoding was successful, \c false otherwise
	 */
	bool DecodeTime(struct timeval & timestamp, const char * pData, unsigned int nDataLen, unsigned int & nOffset);
	/**
	 * Reads a bool value from a data buffer.
	 * @param bValue Target value
	 * @param pData Buffer containing encoded payload data
	 * @param nDataLen Length of the payload data
	 * @param nOffset Reading position
	 * @return \c true if decoding was successful, \c false otherwise
	 */
	bool DecodeBool(bool & bValue, const char * pData, unsigned int nDataLen, unsigned int & nOffset);
	/**
	 * Reads a string value from a data buffer. The encoded string value is
	 * composed of a 2-byte length field followed by a byte buffer of variable size
	 * containg string data (without terminating zero).
	 * @param sValue Target string
	 * @param pData Buffer containing encoded payload data
	 * @param nDataLen Length of the payload data
	 * @param nOffset Reading position
	 * @return \c true if decoding was successful, \c false otherwise
	 */
	bool DecodeString(std::string & sValue, const char * pData, unsigned int nDataLen, unsigned int & nOffset);
public:	
	virtual ~TrafficCaptureMessage(void);
	/**
	 * Returns message identification number. It is not defined by parent abstract classes level;
	 * thus it has to be overridden in child classes. The identification numbers returned by 
	 * individual child classes shall be distinct.
	 * @return Message identification number
	 */
	virtual unsigned short GetId() const = 0;
	/**
	 * Encodes the message to a byte buffer and return a pointer to it. The length of the buffer
	 * can be obtained calling the #GetEncodedDataLength() method. The pointer to the encoded
	 * data is valid as long as the instance that created it stays alive and unchanged.
	 * @return Pointer to the byte buffer containing encoded message
	 */
	const char * GetEncodedMessage();
	/**
	 * This method returns the length of the encoded message data. It is usually used with the
	 * #GetEncodedMessage() method when writing the message to a socket stream.
	 * @return Length of encoded data
	 */
	unsigned int GetEncodedDataLength();
	/**
	 * Initializes message data from a byte buffer containing encoded data for this message.
	 * This method is used by the TrafficCaptureMessageFactory when creating a message received
	 * from a remote host.
	 * @param pPayload Pointer to the byte buffer with encoded payload
	 * @param nPayloadLength Length of the encoded payload
	 * @return \c true if decoding was successful, \c false otherwise
	 */
	bool DecodePayload(const char * pPayload, unsigned int nPayloadLength);
};

/**
 * Common abstract class for reply messages. It defines a \c bool data field containing 
 * operation success.
 */
class CommonReplyMessage : public TrafficCaptureMessage
{
private:
	bool m_bResult;
protected:
	CommonReplyMessage();
	virtual unsigned int CalculateDataLength();
	virtual void EncodePayload(unsigned int & nOffset);
	virtual bool DecodePayload(const char * pPayload, unsigned int nPayloadLength, unsigned int & nOffset);
public:
	virtual ~CommonReplyMessage() {}
	/**
	 * The method returns the result of the operation.
	 * @return Operation result
	 */
	bool GetResult() const { return m_bResult; }
	/**
	 * The method sets the result of the operation. The default value is false.
	 * @param bResult Operation result
	 */
	void SetResult(bool bResult);
};

#endif
