#include "common_sip_msrp.h"
#include "msrp_codets.h"
//#include "gen_classes.h"
//#include "Regex.h"
#include <iostream>
#include <fstream>

namespace t3devlib { namespace gen {

// YGA: For debug purpose
/*{
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "CaptureSource::PreEncodeField: " << field_id << std::endl;
	logfile.close();
}*/

//
// Implementation of the decoder for MSRP
//

// MSRP quoted strings messages allow multiple ways of representing
// some characters (raw unicode or escaped). This function is used
// to normalise the content so that two equivalent representation
// will result in the same TTCN-3 charstring.
//
bool detect_assign(Buffer & buffer) throw (DecodeError)
{
	Regex reg_assign ("^" SIPREG_EQUAL);
	return detect_separator(reg_assign, buffer);
}

bool detect_colon(Buffer & buffer) throw (DecodeError)
{
	Regex reg_assign ("^" SIPREG_COLON);
	return detect_separator(reg_assign, buffer);
}

#define KW_MSRP_UTF8	"\x4D\x53\x52\x50" //;MSRP in caps
#define KW_SEND_UTF8	"\x53\x45\x4e\x44" //; SEND in caps
#define KW_REPORT_UTF8	"\x52\x45\x50\x4f\x52\x54" //; REPORT in caps
#define KW_AUTH_UTF8	"\x41\x55\x54\x48"//; AUTH in caps

//Header field name constants
#define MSRPREG_HEADER_COLON				"[" SIPCHARS_WSP "]*:"
#define KW_FROM_PATH_HEADER_NAME			"From-Path"
#define REG_HDR_From_Path_TOKEN				KW_FROM_PATH_HEADER_NAME MSRPREG_HEADER_COLON
#define KW_TO_PATH_HEADER_NAME				"To-Path"
#define REG_HDR_To_Path_TOKEN				KW_TO_PATH_HEADER_NAME MSRPREG_HEADER_COLON
#define KW_MESSAGE_ID_HEADER_NAME			"Message-ID"
#define REG_HDR_MESSAGE_ID_TOKEN			KW_MESSAGE_ID_HEADER_NAME MSRPREG_HEADER_COLON
#define KW_SUCCESS_REPORT_HEADER_NAME		"Success-Report"
#define REG_HDR_SUCCESS_REPORT_TOKEN		KW_SUCCESS_REPORT_HEADER_NAME MSRPREG_HEADER_COLON
#define KW_FAILURE_REPORT_HEADER_NAME		"Failure-Report"
#define REG_HDR_FAILURE_REPORT_TOKEN		KW_FAILURE_REPORT_HEADER_NAME MSRPREG_HEADER_COLON
#define KW_BYTE_RANGE_HEADER_NAME			"Byte-Range"
#define REG_HDR_BYTE_RANGE_TOKEN			KW_BYTE_RANGE_HEADER_NAME MSRPREG_HEADER_COLON
#define KW_STATUS_HEADER_NAME				"Status"
#define REG_HDR_STATUS_TOKEN				KW_STATUS_HEADER_NAME MSRPREG_HEADER_COLON
#define KW_Content_ID_HEADER_NAME			"Content-ID"
#define REG_HDR_Content_ID_TOKEN			KW_Content_ID_HEADER_NAME MSRPREG_HEADER_COLON
#define KW_Content_Description_HEADER_NAME	"Content-Description"
#define REG_HDR_Content_Description_TOKEN	KW_Content_Description_HEADER_NAME MSRPREG_HEADER_COLON
#define KW_Content_Disposition_HEADER_NAME	"Content-Disposition"
#define REG_HDR_Content_Disposition_TOKEN	KW_Content_Disposition_HEADER_NAME MSRPREG_HEADER_COLON
//"MIME_EXT_FIELD_E", // RFC2045 Section 9. "Content-*"
//any CHAR, excluding CTLs, SPACE, and ":"        33-57, 59-126
//													decimal
//CHAR        =  <any ASCII character>        ; (	0.-127.)
//SPACE       =  <ASCII SP, space>            ; (		32.)
//CTL         =  <any ASCII control           ; (	0.- 31.)
// character and DEL>						  ; (		127.)
#define RFC822_ANY_HEADER_NAME_CHAR			"\x21-\x39\x3B-\x7E"
//#define REG_HDR_MIME_ANY_TOKEN				"Content-[" RFC822_ANY_HEADER_NAME_CHAR "]*" MSRPREG_HEADER_COLON
#define REG_HDR_MIME_ANY_TOKEN_GR			"(Content-[" RFC822_ANY_HEADER_NAME_CHAR "]*)" MSRPREG_HEADER_COLON
#define KW_CONTENT_TYPE_HEADER_NAME			"Content-Type"
#define REG_HDR_CONTENT_TYPE_TOKEN			KW_CONTENT_TYPE_HEADER_NAME MSRPREG_HEADER_COLON
#define KW_WWW_Authenticate_HEADER_NAME		"WWW-Authenticate"
#define REG_HDR_WWW_Authenticate_TOKEN		KW_WWW_Authenticate_HEADER_NAME MSRPREG_HEADER_COLON
#define KW_Authorization_HEADER_NAME		"Authorization"
#define REG_HDR_Authorization_TOKEN			KW_Authorization_HEADER_NAME MSRPREG_HEADER_COLON
#define KW_Authentication_Info_HEADER_NAME	"Authentication-Info"
#define REG_HDR_Authentication_Info_TOKEN	KW_Authentication_Info_HEADER_NAME MSRPREG_HEADER_COLON
#define KW_Expires_HEADER_NAME				"Expires"
#define REG_HDR_Expires_TOKEN				KW_Expires_HEADER_NAME MSRPREG_HEADER_COLON
#define KW_Min_Expires_HEADER_NAME			"Min-Expires"
#define REG_HDR_Min_Expires_TOKEN			KW_Min_Expires_HEADER_NAME MSRPREG_HEADER_COLON
#define KW_Max_Expires_HEADER_NAME			"Max-Expires"
#define REG_HDR_Max_Expires_TOKEN			KW_Max_Expires_HEADER_NAME MSRPREG_HEADER_COLON
#define KW_Use_Path_HEADER_NAME				"Use-Path"
#define REG_HDR_Use_Path_TOKEN				KW_Use_Path_HEADER_NAME MSRPREG_HEADER_COLON


#define ALPHA_IN_SET "A-Za-z"
#define UPALPHA_IN_SET "\x41-\x5A"
#define DIGIT_IN_SET "0-9"

//ALPHANUM = ALPHA / DIGIT
#define ALPHANUM_IN_SET DIGIT_IN_SET ALPHA_IN_SET

//ident-char = ALPHANUM / "." / "-" / "+" / "%" / "="
#define IDENT_CHAR_IN_SET ALPHANUM_IN_SET  "." "\\-" "+" "%" "=" 

//ident = ALPHANUM 3*31ident-char
#define IDENT "[" ALPHANUM_IN_SET "][" IDENT_CHAR_IN_SET "]{3,31}"

//other-method = 1*UPALPHA
#define OTHER_METHOD "[" UPALPHA_IN_SET "]+"

//UTF8-CONT = %x80-BF
#define UTF8_CONT "[\x80-\xBF]"

/*UTF8-NONASCII = %xC0-DF 1UTF8-CONT
/ %xE0-EF 2UTF8-CONT
/ %xF0-F7 3UTF8-CONT
/ %xF8-Fb 4UTF8-CONT
/ %xFC-FD 5UTF8-CONT*/
#define UTF8_NONASCII_IN_GROUP "[\xC0-\xDF]" UTF8_CONT \
	"|" "[\xE0-\xEF]" UTF8_CONT "{2}" \
	"|" "[\xF0-\xF7]" UTF8_CONT "{3}" \
	"|" "[\xF8-\xFB]" UTF8_CONT "{4}" \
	"|" "[\xFC-\xFD]" UTF8_CONT "{5}" 

#define UTF8_NONASCII "(" UTF8_NONASCII_IN_GROUP ")"

//utf8text = *(HTAB / %x20-7E / UTF8-NONASCII)
#define UTF8TEXT "([" HTAB "\x20-\x7E" "]|" UTF8_NONASCII_IN_GROUP ")*"

//status-code = 3DIGIT ; any code defined in this document
#define STATUS_CODE	"[" DIGIT_IN_SET "]{3}"

//method = mSEND / mREPORT / other-method
#define METHOD "(" KW_SEND_UTF8 "|" KW_REPORT_UTF8 "|" OTHER_METHOD ")"

//continuation-flag = "+" / "$" / "#"
#define CONTINUATION_FLAG_IN_SET "+$#"
#define CONTINUATION_FLAG "[" CONTINUATION_FLAG_IN_SET "]"

//("yes" / "no" )
#define YES_NO_IN_GROUP "yes|no"
#define YES_NO "(" YES_NO_IN_GROUP ")"

//("yes" / "no" / "partial" )
#define YES_NO_PARTIAL_IN_GROUP YES_NO_IN_GROUP "|partial"
#define YES_NO_PARTIAL "(" YES_NO_PARTIAL_IN_GROUP ")"

//range-start = 1*DIGIT
#define RANGE_START "[" DIGIT_IN_SET "]+"
//range-end = 1*DIGIT / "*"
#define RANGE_END "(" RANGE_START "|\\*)"
//total = 1*DIGIT / "*"
#define TOTAL RANGE_END

//namespace = 3(DIGIT); "000" for all codes defined in this document.
#define NAMESPACE "[" DIGIT_IN_SET "]{3}"


#define YES_NO_TOKEN			"^" YES_NO
#define YES_NO_PARTIAL_TOKEN	"^" YES_NO_PARTIAL
#define IDENT_TOKEN				"^" IDENT
//#define TRANSACT_ID_TOKEN		IDENT_TOKEN 
#define OTHER_METHOD_TOKEN		"^" OTHER_METHOD
//#define COMMENT_TOKEN			"^" UTF8TEXT
#define METHOD_TOKEN			"^" METHOD
//#define CONTINUATION_FLAG_TOKEN CONTINUATION_FLAG
#define RANGE_START_TOKEN		"^" RANGE_START
#define RANGE_END_TOKEN			"^" RANGE_END
#define RANGE_TOTAL_TOKEN		"^" TOTAL
#define NAMESPACE_TOKEN			"^" NAMESPACE 

//token = 1*(%x21 / %x23-27 / %x2A-2B / %x2D-2E / %x30-39 / %x41-5A / %x5E-7E)
//; token is compared case-insensitive
#define RFC4975_TOKEN_IN_SET "\x21\x23-\x27\x2A-\x2B\\\x2D-\x2E\x30-\x39\x41-\x5A\x5E-\x7E"
#define RFC4975_TOKEN "^[" RFC4975_TOKEN_IN_SET "]+"


//LHEX = DIGIT / %x61-66 ;lowercase a-f
#define LHEX_IN_SET DIGIT_IN_SET "\x61-\x66"
#define LHEX "[" LHEX_IN_SET "]"

//response-digest = DQUOTE *LHEX DQUOTE
#define RESPONSE_DIGEST_TOKEN "^" DQUOTE LHEX "*" DQUOTE

//hname = ALPHA *token
#define HNAME "[" ALPHA_IN_SET "][" RFC4975_TOKEN_IN_SET "]*"
#define HNAME_TOKEN "^" HNAME

//hval = utf8text
#define HVAL_TOKEN "^" UTF8TEXT

//qdtext = SP / HTAB / %x21 / %x23-5B / %x5D-7E / UTF8-NONASCII
#define QD_TEXT_IN_GROUP SP "|" HTAB "|\x21|\x23-\x5B|\x5D-\x7E|" UTF8_NONASCII_IN_GROUP
#define QD_TEXT "(" QD_TEXT_IN_GROUP ")"

//BACKSLASH = "\"
#define BACKSLASH "\\"

//qd-esc = (BACKSLASH BACKSLASH) / (BACKSLASH DQUOTE)
#define QD_ESC_IN_GROUP BACKSLASH BACKSLASH "|" BACKSLASH DQUOTE 
#define QD_ESC "(" QD_ESC_IN_GROUP ")"

//quoted-string = DQUOTE *(qdtext / qd-esc) DQUOTE

#define QUOTED_STRING DQUOTE "(" QD_TEXT_IN_GROUP "|" QD_ESC_IN_GROUP ")*" DQUOTE

//pname = token
#define PNAME_TOKEN RFC4975_TOKEN

//pval = token / quoted-string
#define PVAL_TOKEN "^([" RFC4975_TOKEN_IN_SET "]+|" QUOTED_STRING ")"

//msrp-scheme = "msrp" / "msrps"
#define MSRP_SCHEME "(msrps|msrp)"
#define MSRP_SCHEME_TOKEN "^" MSRP_SCHEME

//RFC3986

//unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
#define UNRESERVED_IN_SET ALPHA_IN_SET DIGIT_IN_SET "\\-" "\\." "_" "~"

//gen-delims    = ":" / "/" / "?" / "#" / "[" / "]" / "@"
#define GEN_DELIMS_IN_SET ":" "\\\\" "\\?" "#" "\\[" "\\]" "@"

//sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
//                 / "*" / "+" / "," / ";" / "="
#define SUB_DELIMS_IN_SET "!" "$" "&" "'" "(" ")" "*" "+" "," ";" "="

//reserved      = gen-delims / sub-delims
#define RESERVED_IN_SET GEN_DELIMS_IN_SET SUB_DELIMS_IN_SET

//pct-encoded   = "%" HEXDIG HEXDIG
#define PCT_ENCODED "%[" HEXDIG_IN_SET "]{2}"

//userinfo      = *( unreserved / pct-encoded / sub-delims / ":" )
#define USERINFO "([" UNRESERVED_IN_SET "]|" PCT_ENCODED "|[" SUB_DELIMS_IN_SET "]|:)*"

#define IPv6ADDRESS SIPREG_IP6_INTERNAL

//IPvFuture     = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
#define IPvFUTURE "v[" HEXDIG_IN_SET "]+\\.[" UNRESERVED_IN_SET SUB_DELIMS_IN_SET ":]+" 

//IP-literal    = "[" ( IPv6address / IPvFuture  ) "]"
#define IP_LITERAL "\\[(" IPv6ADDRESS "|" IPvFUTURE ")\\]"


//IPv4address   = dec-octet "." dec-octet "." dec-octet "." dec-octet
#define IPv4ADDRESS SIPREG_IP4

//reg-name      = *( unreserved / pct-encoded / sub-delims )
//obsolete, as replaced by SIP one because of ';' clash...
//#define REG_NAME "([" UNRESERVED_IN_SET "]|" PCT_ENCODED "|[" SUB_DELIMS_IN_SET "])*"

//host          = IP-literal / IPv4address / reg-name
//obsolete, as replaced by SIP one because of ';' clash...
//#define HOST "(" IP_LITERAL "|" IPv4ADDRESS "|" REG_NAME ")"


//port          = *DIGIT
#define PORT "[" DIGIT_IN_SET "]*"
//#define AUTHORITY "(" USERINFO "@)?" HOST "(:" PORT ")?"

//session-id = 1*( unreserved / "+" / "=" / "/" )
//; unreserved as defined in RFC3986
#define SESSION_ID_TOKEN "^[" UNRESERVED_IN_SET "+=/]+"

//transport = "tcp" / 1*ALPHANUM
#define TRANSPORT_TOKEN "^(tcp|[" ALPHANUM_IN_SET "]+)"


//URI_PARAMS_TOKEN

//URI-parameter = token ["=" token] //TODO:will i need this at all?
//#define URI_PARAMETER_TOKEN RFC4975_TOKEN "(=[" RFC4975_TOKEN_IN_SET "]+)?"
void process_token_value(Charstring& cs)
{
	std::string result;

	const unsigned char* p   = cs.GetValueBin();
	const unsigned char* end = p + (cs.GetLength() / 8);
	//TODO: UTF-8 chars?
	for ( ; p!=end ; p++)
	{
		if(*p >= 'A' && *p <='Z')
			result += (*p + 0x20);
		else
			result += *p;
	}
	// replace the string with the quoted string
	Bytestring& bs = cs;
	bs.SetValue (result);
	return;
}

void skip_mandatory (Regex * rgx, Buffer & buffer, Variable* v) {
	rgx->AssertMatch (buffer, v);
	buffer.SetPosition (buffer.GetPosition() + rgx->GetMatchedLength());
}

#define MSRPREG_CRLF		"[" SIPCHARS_WSP "]*\r\n[" SIPCHARS_WSP "]*"

void skip_mandatory_CRLF(Buffer & buffer, Variable* v, const char* src)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "Skip SIPREG_SWS from: " << buffer.GetPosition() << std::endl;
	logfile << "Skip for: " << src << std::endl;
#endif
	static Regex reg_crlf ("^" MSRPREG_CRLF);
	skip_mandatory(&reg_crlf, buffer, v);
#ifdef DEBUG_LOG
	logfile << "Skip SIPREG_SWS to: " << buffer.GetPosition() << std::endl;
	logfile.close();
#endif
}

void msrp_skip_sp(Buffer & buffer)
{
	static Regex reg_wsp ("^[" SIPCHARS_WSP "]*");
	if (reg_wsp.Match(buffer))
		reg_wsp.MovePast(buffer);
}

void msrp_read_sp (Buffer & buffer, Variable* v) 
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "Skip msrp_read_sp from: " << buffer.GetPosition() << std::endl;
#endif

	static Regex reg_ws ("^["SIPCHARS_WSP"]+");
	reg_ws.AssertMatch (buffer, v);
	buffer.SetPosition (buffer.GetPosition() + reg_ws.GetMatchedLength());

#ifdef DEBUG_LOG
	logfile << "Skip msrp_read_sp to: " << buffer.GetPosition() << std::endl;
	logfile.close();
#endif
}

//MsrpRequestLine
//req-start = pMSRP SP transact-id SP method CRLF
//------------------------------------------------------------
/*
type record MsrpRequestLine {
	MsrpKeywords tagMsrp (e_MSRP), // MSRP keyword
    TransactionID transactionID, // The transaction identifier created by sender
    MsrpMethod method // The method name
}
*/
//============================================================
void MsrpRequestLine::PostEncode (Buffer& buffer) throw (EncodeError)
{
	Charstring cs;
	cs.SetValue(CRLF);
	cs.Encode(buffer);
}

void MsrpRequestLine::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	Charstring cs;

	cs.SetValue(SP);

	switch(field_id) {
	case id_tagMsrp:
	case id_transactionID:
		cs.Encode(buffer);
		break;
	default:
		break;
	}
}

void MsrpRequestLine::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "MsrpRequestLine::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_tagMsrp ("^" KW_MSRP_UTF8);
	static Regex reg_transactionID (IDENT_TOKEN);//TRANSACT_ID_TOKEN);trans-id = ident
	static Regex reg_method (METHOD_TOKEN);

	switch (id) {
		case id_tagMsrp:
			reg_tagMsrp.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_tagMsrp.GetMatchedLength());
			break;
		case id_transactionID:
			msrp_read_sp (buffer, this);
			reg_transactionID.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_transactionID.GetMatchedLength());
			break;
		case id_method:
			msrp_read_sp (buffer, this);
			reg_method.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_method.GetMatchedLength());
			break;
		default:
			break;
	}
}

void MsrpRequestLine::PostDecode (Buffer& buffer) throw (DecodeError)
{
	skip_mandatory_CRLF(buffer, this, "MsrpRequestLine");
}

//MSRP_ResponseLine
//resp-start = pMSRP SP transact-id SP status-code [SP comment] CRLF
//------------------------------------------------------------
//============================================================
void MsrpResponseLine::PostEncode (Buffer& buffer) throw (EncodeError)
{
	Charstring cs;

	cs.SetValue(CRLF);
	cs.Encode(buffer);
}
void MsrpResponseLine::PreEncode(Buffer& buffer) throw (EncodeError)
{
	Get_statusCode().SetFormat(Integer::AsciiDecimal);
}
void MsrpResponseLine::PreDecode(Buffer& buffer) throw (DecodeError)
{
	Get_statusCode().SetFormat(Integer::AsciiDecimal);
}

void MsrpResponseLine::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	Charstring cs;

	cs.SetValue(SP);

	switch(field_id) {
	case id_tagMsrp:
	case id_transactionID:
	case id_statusCode:
		cs.Encode(buffer);
		break;
	default:
		break;
	}
}

void MsrpResponseLine::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "ResponseLine::PreDecodeField: " << id;
	logfile.close();
#endif

	static Regex reg_tagMsrp ("^" KW_MSRP_UTF8);
	static Regex reg_transactionID (IDENT_TOKEN);//TRANSACT_ID_TOKEN);
	static Regex reg_statusCode ("^" STATUS_CODE);
	static Regex reg_comment ("^" UTF8TEXT);//COMMENT_TOKEN);

	//resp-start = pMSRP SP transact-id SP status-code [SP comment] CRLF
	switch (id) {
		case id_tagMsrp:
			reg_tagMsrp.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_tagMsrp.GetMatchedLength());
			//logfile << "-Field-OK " << std::endl;
			break;
		case id_transactionID:
			msrp_read_sp (buffer, this);
			reg_transactionID.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_transactionID.GetMatchedLength());
			//logfile << "-Field-OK " << std::endl;
			break;
		case id_statusCode:
			msrp_read_sp (buffer, this);
			reg_statusCode.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_statusCode.GetMatchedLength());
			//logfile << "-Field-OK, len: " << reg_statusCode.GetMatchedLength() << std::endl;
			break;
		case id_comment:
			msrp_read_sp (buffer, this);
			if(reg_comment.Match(buffer) && reg_comment.GetMatchedLength())
			{
				SetHypFieldIsPresent(id, 1);
				SetHypFieldLength (id, reg_comment.GetMatchedLength());
				//logfile << "-Field-OK, len: "<< reg_comment.GetMatchedLength() << std::endl;
			}
			else
			{
				SetHypFieldIsPresent(id, 0);
				//logfile << "-Field-NotPresent " << std::endl;
			}
			break;
		default:
			break;
	}
}

void MsrpResponseLine::PostDecode (Buffer& buffer) throw (DecodeError)
{
	skip_mandatory_CRLF(buffer, this, "MsrpResponseLine");
}

//EndLine
//"-------" transact-id continuation-flag CRLF
//------------------------------------------------------------
/*
type record EndLine
{
	TransactionID transactionID,
    ContinuationFlag continuationFlag
}
*/
//============================================================
void EndLine::PostEncode (Buffer& buffer) throw (EncodeError)
{
	Charstring cs;

	cs.SetValue(CRLF);
	cs.Encode(buffer);
}

void EndLine::PreEncodeField(int field_id, Buffer& buffer) throw (EncodeError)
{
	if(field_id != id_transactionID)
		return;
	Charstring cs;
	cs.SetValue("-------");
	cs.Encode(buffer);
}

void EndLine::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "EndLine::PreDecodeField: " << id << std::endl;
	logfile << "EndLine::PreDecodeField:ContFlagRegex: " << CONTINUATION_FLAG << std::endl;
	logfile.close();
#endif

	static Regex reg_intro ("^-------");
	static Regex reg_transactionID ("^(" IDENT ")" CONTINUATION_FLAG CRLF);
	static Regex reg_tagcontinuationFlag ("^" CONTINUATION_FLAG);
	
	switch (id) {
		case id_transactionID:
			reg_intro.AssertMatch(buffer, this);
			reg_intro.MovePast(buffer);
			
			reg_transactionID.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_transactionID.GetMatchedLength(1));
			//logfile << "EndLine::PreDecodeField:TransactionID: " << reg_transactionID.GetMatchedString(1) << std::endl;
			break;
		case id_continuationFlag:
			reg_tagcontinuationFlag.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_tagcontinuationFlag.GetMatchedLength());
			//logfile << "EndLine::PreDecodeField:ContFlag: " << reg_tagcontinuationFlag.GetMatchedString() << std::endl;
			break;
		default:
			break;
	}
}

void EndLine::PostDecode (Buffer& buffer) throw (DecodeError)
{
	skip_mandatory_CRLF(buffer, this, "EndLine");
}

//MessageID
//Message-ID = "Message-ID:" SP ident
//------------------------------------------------------------
//============================================================
void MessageID::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	Charstring cs;

	cs.SetValue(SP);

	switch(field_id) {
	case id_headerName:
		cs.Encode(buffer);
		break;
	default:
		break;
	}
}

void MessageID::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "MessageID::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_headerName ("^" REG_HDR_MESSAGE_ID_TOKEN);
	static Regex reg_messageID (IDENT_TOKEN);
	
	switch (id) {
	case id_headerName:
			reg_headerName.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_headerName.GetMatchedLength());
			break;
		case id_messageId:
			msrp_read_sp(buffer, this);
			reg_messageID.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_messageID.GetMatchedLength());
			break;
		default:
			break;
	}
}

//SuccessReport
//Success-Report = "Success-Report:" SP ("yes" / "no" )
//------------------------------------------------------------
//============================================================
void SuccessReport::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	Charstring cs;

	cs.SetValue(SP);

	switch(field_id) {
	case id_headerName:
		cs.Encode(buffer);
		break;
	default:
		break;
	}
}

void SuccessReport::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "SuccessReport::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_headerName ("^" REG_HDR_SUCCESS_REPORT_TOKEN);
	static Regex reg_reportStatus (YES_NO_TOKEN);
	//id_headerName = 0
    //id_reportStatus = 1
	switch (id) {
	case id_headerName:
			reg_headerName.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_headerName.GetMatchedLength());
			break;
		case id_reportStatus:
			msrp_read_sp(buffer, this);
			reg_reportStatus.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_reportStatus.GetMatchedLength());
			break;
		default:
			break;
	}
}

//FailureReport
//Failure-Report = "Failure-Report:" SP ("yes" / "no" / "partial" )
//------------------------------------------------------------
//============================================================
void FailureReport::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	Charstring cs;

	cs.SetValue(SP);

	switch(field_id) {
	case id_headerName:
		cs.Encode(buffer);
		break;
	default:
		break;
	}
}

void FailureReport::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "FailureReport::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_headerName ("^" REG_HDR_FAILURE_REPORT_TOKEN);
	static Regex reg_reportStatus (YES_NO_PARTIAL_TOKEN);
	//id_headerName = 0
    //id_reportStatus = 1
	switch (id) {
	case id_headerName:
			reg_headerName.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_headerName.GetMatchedLength());
			break;
		case id_reportStatus:
			msrp_read_sp(buffer, this);
			reg_reportStatus.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_reportStatus.GetMatchedLength());
			break;
		default:
			break;
	}
}

//ByteRange
//Byte-Range = "Byte-Range:" SP range-start "-" range-end "/" total
//------------------------------------------------------------
/*
type record ByteRange {
	HeaderName headerName (BYTE_RANGE_E),
    integer startValue,				// [1..infinity)
    ByteRangeValue endValue,		// [0..infinity) TODO can take also wilcard value: "*"
    ByteRangeValue totalValue		// [0..infinity) TODO can take also wilcard value: "*"
}
*/
//============================================================
void ByteRange::PreEncode (Buffer& buffer) throw (EncodeError)
{
	Get_startValue().SetFormat(Integer::AsciiDecimal);
}

void ByteRange::PreDecode (Buffer& buffer) throw (DecodeError)
{
	Get_startValue().SetFormat(Integer::AsciiDecimal);
}

void ByteRange::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	Charstring cs;
	switch(field_id) {
		case id_headerName:
			cs.SetValue(SP);
			cs.Encode(buffer);
			break;
		case id_startValue:
			cs.SetValue("-");
			cs.Encode(buffer);
			break;
		case id_endValue:
			cs.SetValue("/");
			cs.Encode(buffer);
			break;
		default:
			break;
	}
}

void ByteRange::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "ByteRange::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif
	static Regex reg_headerName ("^" REG_HDR_BYTE_RANGE_TOKEN);
	static Regex reg_startValue (RANGE_START_TOKEN);
	static Regex reg_endSep ("^" SIPREG_SWS "-" SIPREG_SWS);
	static Regex reg_endValue (RANGE_END_TOKEN);
	static Regex reg_totalSep ("^" SIPREG_SLASH);
	static Regex reg_totalValue (RANGE_TOTAL_TOKEN);
	//Byte-Range = "Byte-Range:" SP range-start "-" range-end "/" total
	switch (id) {
	case id_headerName:
			reg_headerName.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_headerName.GetMatchedLength());
			break;
		case id_startValue:
			msrp_read_sp(buffer, this);
			reg_startValue.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_startValue.GetMatchedLength());
			break;
		case id_endValue:
			skip_mandatory(&reg_endSep, buffer, this);
			reg_endValue.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_endValue.GetMatchedLength());
			break;
		case id_totalValue:
			skip_mandatory(&reg_totalSep, buffer, this);
			reg_totalValue.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_totalValue.GetMatchedLength());
			break;
			default:
			break;
	}
}


//ByteRangeValue
//Byte-Range = "Byte-Range:" SP range-start "-" range-end "/" total
//------------------------------------------------------------
/*
type union ByteRangeValue {
	integer intValue,		// [0..infinity)	
    MsrpKeywords wildcard	// "*"
}     
*/
//============================================================
void ByteRangeValue::PreEncode (Buffer& buffer) throw (EncodeError)
{
	if(GetChosenId() == id_intValue)
		Get_intValue().SetFormat(Integer::AsciiDecimal);
}

void ByteRangeValue::PreDecode (Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "ByteRangeValue::PreDecode" << std::endl;
	logfile.close();
#endif

	static Regex reg_wildcard ("\\*");
	
	//mPosition = buffer.GetPosition();
	if(reg_wildcard.Match(buffer))
		SetHypChosenId (id_wildcard);
	else
	{
		SetHypChosenId (id_intValue);
		Get_intValue().SetFormat(Integer::AsciiDecimal);
	}
}

//MsrpStatus
//Status = "Status:" SP namespace SP status-code [SP comment]
//------------------------------------------------------------
//============================================================
void MsrpStatus::PreEncode (Buffer& buffer) throw (EncodeError)
{
	Get_namespace().SetFormat(Integer::AsciiDecimal);
	Get_statusCode().SetFormat(Integer::AsciiDecimal);
}

void MsrpStatus::PreDecode (Buffer& buffer) throw (DecodeError)
{
	Get_namespace().SetFormat(Integer::AsciiDecimal);
	Get_statusCode().SetFormat(Integer::AsciiDecimal);
}

void MsrpStatus::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	Charstring cs;

	cs.SetValue(SP);

	switch(field_id) {
	case id_headerName:
	case id_namespace:
		cs.Encode(buffer);
		break;
	case id_statusCode:
		if(IsPresent(id_comment))
		cs.Encode(buffer);
		break;
	default:
		break;
	}
}

void MsrpStatus::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "Status::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_headerName ("^" REG_HDR_STATUS_TOKEN);
	static Regex reg_namespace (NAMESPACE_TOKEN);
	static Regex reg_statusCode ("^" STATUS_CODE);
	static Regex reg_comment ("^" UTF8TEXT);//COMMENT_TOKEN);

	switch (id) {
	case id_headerName:
			reg_headerName.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_headerName.GetMatchedLength());
			break;
		case id_namespace:
			msrp_read_sp(buffer, this);
			reg_namespace.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_namespace.GetMatchedLength());
			break;
		case id_statusCode:
			msrp_read_sp(buffer, this);
			reg_statusCode.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_statusCode.GetMatchedLength());
			break;
		case id_comment:
			msrp_read_sp(buffer, this);
			if(reg_comment.Match(buffer) && reg_comment.GetMatchedLength())
			{
				SetHypFieldIsPresent(id, 1);
				SetHypFieldLength (id, reg_comment.GetMatchedLength());
			}
			else
				SetHypFieldIsPresent(id, 0);
			break;
		default:
			break;
	}
}

//MsrpExpires
//Expires = "Expires:" SP 1*DIGIT
//------------------------------------------------------------
//============================================================
void MsrpExpires::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	if(field_id != id_headerName)
		return;
	Charstring cs;
	cs.SetValue(SP);
	cs.Encode(buffer);
}

void MsrpExpires::PreEncode (Buffer& buffer) throw (EncodeError)
{
	Get_intValue().SetFormat(Integer::AsciiDecimal);
}

void MsrpExpires::PreDecode (Buffer& buffer) throw (DecodeError)
{
	Get_intValue().SetFormat(Integer::AsciiDecimal);
}

void MsrpExpires::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "Expires::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_headerName ("^" REG_HDR_Expires_TOKEN);
	static Regex reg_expiresValue ("^[" DIGIT_IN_SET "]+");
	switch (id) {
	case id_headerName:
			reg_headerName.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_headerName.GetMatchedLength());
			break;
		case id_intValue:
			msrp_read_sp(buffer, this);
			reg_expiresValue.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_expiresValue.GetMatchedLength());
			break;
	default:
			break;
	}
}

//MsrpMinExpires
//Min-Expires = "Min-Expires:" SP 1*DIGIT
//------------------------------------------------------------
//============================================================
void MsrpMinExpires::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	if(field_id != id_headerName)
		return;
	Charstring cs;
	cs.SetValue(SP);
	cs.Encode(buffer);
}
void MsrpMinExpires::PreEncode (Buffer& buffer) throw (EncodeError)
{
	Get_intValue().SetFormat(Integer::AsciiDecimal);
}

void MsrpMinExpires::PreDecode (Buffer& buffer) throw (DecodeError)
{
	Get_intValue().SetFormat(Integer::AsciiDecimal);
}

void MsrpMinExpires::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "MinExpires::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_headerName ("^" REG_HDR_Min_Expires_TOKEN);
	static Regex reg_expiresValue ("^[" DIGIT_IN_SET "]+");
	switch (id) {
		case id_headerName:
			reg_headerName.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_headerName.GetMatchedLength());
			break;
		case id_intValue:
			msrp_read_sp(buffer, this);
			reg_expiresValue.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_expiresValue.GetMatchedLength());
			break;
	default:
			break;
	}
}

//MaxExpires
//Max-Expires = "Max-Expires:" SP 1*DIGIT
//------------------------------------------------------------
//============================================================
void MaxExpires::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	if(field_id != id_headerName)
		return;
	Charstring cs;
	cs.SetValue(SP);
	cs.Encode(buffer);
}

void MaxExpires::PreEncode (Buffer& buffer) throw (EncodeError)
{
	Get_intValue().SetFormat(Integer::AsciiDecimal);
}

void MaxExpires::PreDecode (Buffer& buffer) throw (DecodeError)
{
	Get_intValue().SetFormat(Integer::AsciiDecimal);
}
void MaxExpires::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "MaxExpires::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_headerName ("^" REG_HDR_Max_Expires_TOKEN);
	static Regex reg_expiresValue ("^[" DIGIT_IN_SET "]+");
	switch (id) {
		case id_headerName:
			reg_headerName.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_headerName.GetMatchedLength());
			break;
		case id_intValue:
			msrp_read_sp(buffer, this);
			reg_expiresValue.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_expiresValue.GetMatchedLength());
			break;
		default:
			break;
	}
}

//UsePath
//Use-Path = "Use-Path:" SP MSRP-URI *(SP MSRP-URI)
//------------------------------------------------------------
//============================================================
void UsePath::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	if(field_id != id_headerName)
		return;
	Charstring cs;
	cs.SetValue(SP);
	cs.Encode(buffer);
}

void UsePath::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "UsePath::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_headerName ("^" REG_HDR_Use_Path_TOKEN);
	
	switch (id) {
	case id_headerName:
			reg_headerName.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_headerName.GetMatchedLength());
			break;
		/*case id_msrpURIs:
			break;*/
		default:
			break;
	}
}


//AuthParam
/*
type record AuthParam {
   charstring pvalue,	// token 
   charstring pname	// token / quoted-string
}
*/
//------------------------------------------------------------
//this is called by the "Digest" type, if it detects the presence of the matching field...
//============================================================
void AuthParam::PreEncodeField(int field_id, Buffer& buffer) throw (EncodeError)
{
	if(field_id != id_pvalue)
		return;
	Charstring cs;
	cs.SetValue("=");
	cs.Encode(buffer);
}

void AuthParam::PreDecodeField(int field_id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "AuthParam::PreDecodeField: " << field_id << std::endl;
	logfile.close();
#endif

	static Regex reg_authParam (RFC4975_TOKEN);
	static Regex reg_authSep ("^" SIPREG_EQUAL);
	static Regex req_quotedString ("^" SIPREG_QUOTED_STRING);
	
	switch (field_id)
	{
		case id_pvalue:
			//logfile << "AuthParam::id_pvalue ATTEMPT: " << std::endl;
			reg_authParam.AssertMatch(buffer, this);
			//logfile << "AuthParam::id_pvalue len: " << reg_authParam.GetMatchedLength() << std::endl;
			SetHypFieldLength(field_id, reg_authParam.GetMatchedLength());
			break;
		case id_pname:
			//logfile << "AuthParam::id_pname ATTEMPT: " << std::endl;
			reg_authSep.AssertMatch(buffer, this);
			reg_authSep.MovePast(buffer);
			//logfile << "AuthParam::separator match: " << std::endl;

			//TODO: process quoted strings/tokens...
			if(req_quotedString.Match(buffer))
			{
				//logfile << "AuthParam::pname len: " << reg_authParam.GetMatchedLength() << std::endl;
				SetHypFieldLength(field_id, req_quotedString.GetMatchedLength());
			}
			else
			{//value is Token
				reg_authParam.AssertMatch(buffer, this);
				//logfile << "AuthParam::pname len: " << reg_authParam.GetMatchedLength() << std::endl;
				SetHypFieldLength(field_id, reg_authParam.GetMatchedLength());
			}
			break;
		default:
			break;
	}
}

//type set of AuthParam AuthParamList;
//------------------------------------------------------------
//this is called by the "Digest" type, if it detects the presence of the matching field...
//============================================================
void AuthParamList::PreEncodeField(int id, Buffer& buffer) throw (EncodeError)
{
	Charstring cs;
	cs.SetValue(", ");
	cs.Encode(buffer);
}

void AuthParamList::PostDecodeField(int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "AuthParamList::PostDecodeField: " << id << std::endl;
	logfile.close();
#endif

	if(detect_comma(buffer))
		SetHypSize(GetSize() +1);
	else
		SetHypSize(-2);
}

//type charstring Qop_Value;
//------------------------------------------------------------
//this is called by the "Digest" type, if it detects the presence of the matching field...
//============================================================
//starts with DOUBLE_QUOTE, and ends With SOUBLE_QUOTE
void Qop_ValueList::PreEncode(Buffer& buffer) throw (EncodeError)
{
	Charstring cs;
	cs.SetValue("\"");
	cs.Encode(buffer);
}

void Qop_ValueList::PostEncode(Buffer& buffer) throw (EncodeError)
{
	Charstring cs;
	cs.SetValue("\"");
	cs.Encode(buffer);
}

void Qop_ValueList::PreEncodeField(int id, Buffer& buffer) throw (EncodeError)
{
	if(id == 0)
		return;
	Charstring cs;
	cs.SetValue(", ");
	cs.Encode(buffer);
}

void Qop_ValueList::PreDecode(Buffer& buffer) throw (DecodeError)
{
	//read starting double quote
	static Regex reg_startingDblQuote("^" SIPREG_SWS "\"" SIPREG_SWS);
	reg_startingDblQuote.AssertMatch(buffer, this);
	reg_startingDblQuote.MovePast(buffer);
}

void Qop_ValueList::PreDecodeField(int field_id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "Qop_ValueList::PreDecodeField: " << std::endl;
	logfile.close();
#endif

	static Regex reg_token(RFC4975_TOKEN);
	//detect next comma separated value
	if(field_id == 0)
	{
		//logfile << "Qop_ValueList::PreDecodeField:0" << std::endl;
		reg_token.AssertMatch(buffer, this);
		//logfile << "Qop_ValueList::PreDecodeField:length:"<< reg_token.GetMatchedLength() << std::endl;
		SetHypFieldLength(reg_token.GetMatchedLength());
	}
	else if(detect_comma(buffer))
	{
		//logfile << "Qop_ValueList::PreDecodeField: more found" << std::endl;
		SetHypSize(GetSize() + 1);
		reg_token.AssertMatch(buffer, this);
		//logfile << "Qop_ValueList::PreDecodeField:length:" << reg_token.GetMatchedLength() <<std::endl;
		SetHypFieldLength(reg_token.GetMatchedLength());
	}
	else
		SetHypSize(-2);
}

void Qop_ValueList::PostDecode(Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "Qop_ValueList::PostDecode: " << std::endl;
	logfile.close();
#endif

	//read ending double quote
	static Regex reg_dblQuote("^" SIPREG_SWS "\"" SIPREG_SWS);
	reg_dblQuote.AssertMatch(buffer, this);
	reg_dblQuote.MovePast(buffer);
}


//TODO:
//Digest
/*type record Digest {	
	charstring realm optional, 	// quoted-string
    charstring nonce optional,	// quoted-string
    charstring opaque optional,	// quoted-string
    charstring stale optional,	// "true" / "false" (no quates)
    charstring algorithm optional, // "MD5" / token (no quates)
    Qop_ValueList qopOptions optional,	// quoted-string
    AuthParamList authParams optional	
}
*/
//------------------------------------------------------------
//============================================================
void Digest::PostEncode(Buffer& buffer) throw (EncodeError)
{
	b_needComma = false;
}
void Digest::PreEncodeField(int field_id, Buffer& buffer) throw (EncodeError)
{
	//TODO, only in case there are more fields to encode
	if(IsPresent(field_id) && b_needComma)
	{
		Charstring cs;
		cs.SetValue(", ");
		cs.Encode(buffer);
		b_needComma = false;
		return;
	}
}
void Digest::PreDecodeField(int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "Digest::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_optionalWSP ("^" SIPREG_SWS);
	static Regex req_quotedString ("^" SIPREG_QUOTED_STRING);
	static Regex reg_tokenVal (RFC4975_TOKEN);
	
	static Regex reg_realmParam ("^realm=");
	static Regex reg_nonceParam ("^nonce=");
	static Regex reg_opaqueParam ("^opaque=");
	static Regex reg_staleParam ("^stale=");
	static Regex reg_staleVal("^(true|false)");
	static Regex reg_algorithmParam ("^algorithm=");
	static Regex reg_qopListParam ("^qop=");
	
	static Regex reg_authParam (RFC4975_TOKEN);
	static Regex reg_authSep ("^" SIPREG_EQUAL);

	static Regex reg_paramSep ("^" SIPREG_COMMA);
	
	//TODO: who removes the separator?
	//TODO:quoted string processing
	if(reg_paramSep.Match(buffer))
		reg_paramSep.MovePast(buffer);

	switch (id)
	{//all optional, all have to be detected
		case id_realm:
			if(reg_realmParam.Match(buffer))
			{
				//logfile << "::realm found" << std::endl;
				reg_realmParam.MovePast(buffer);
				SetHypFieldIsPresent(id, 1);
				if(reg_optionalWSP.Match(buffer))
					reg_optionalWSP.MovePast(buffer);
				req_quotedString.AssertMatch(buffer, this);
				SetHypFieldLength (id, req_quotedString.GetMatchedLength());
			}
			else
				SetHypFieldIsPresent(id, 0);
			break;
		case id_nonce:
			if(reg_nonceParam.Match(buffer))
			{
				//logfile << "::nonce found" << std::endl;
				reg_nonceParam.MovePast(buffer);
				SetHypFieldIsPresent(id, 1);
				if(reg_optionalWSP.Match(buffer))
					reg_optionalWSP.MovePast(buffer);
				req_quotedString.AssertMatch(buffer, this);
				SetHypFieldLength (id, req_quotedString.GetMatchedLength());
			}
			else
				SetHypFieldIsPresent(id, 0);
			break;
		case id_opaque:
			if(reg_opaqueParam.Match(buffer))
			{
				//logfile << "::opaque found" << std::endl;
				reg_opaqueParam.MovePast(buffer);
				SetHypFieldIsPresent(id, 1);
				if(reg_optionalWSP.Match(buffer))
					reg_optionalWSP.MovePast(buffer);
				req_quotedString.AssertMatch(buffer, this);
				SetHypFieldLength (id, req_quotedString.GetMatchedLength());
			}
			else
				SetHypFieldIsPresent(id, 0);
			break;
		case id_stale:
			if(reg_staleParam.Match(buffer))
			{
				//logfile << "::stale found" << std::endl;
				reg_staleParam.MovePast(buffer);
				SetHypFieldIsPresent(id, 1);
				if(reg_optionalWSP.Match(buffer))
					reg_optionalWSP.MovePast(buffer);
				reg_staleVal.AssertMatch(buffer, this);
				SetHypFieldLength (id, reg_staleVal.GetMatchedLength());
			}
			else
				SetHypFieldIsPresent(id, 0);
			break;
		case id_algorithm:
			if(reg_algorithmParam.Match(buffer))
			{
				//logfile << "::algorithm found" << std::endl;
				reg_algorithmParam.MovePast(buffer);
				SetHypFieldIsPresent(id, 1);
				if(reg_optionalWSP.Match(buffer))
					reg_optionalWSP.MovePast(buffer);
				reg_tokenVal.AssertMatch(buffer, this);
				SetHypFieldLength (id, reg_tokenVal.GetMatchedLength());
			}
			else
				SetHypFieldIsPresent(id, 0);
			break;
		case id_qopOptions:
			//static Regex reg_qopListStart("^" SIPREG_SWS "\"");
			if(reg_qopListParam.Match(buffer))
			{
				//logfile << "::qop found" << std::endl;
				reg_qopListParam.MovePast(buffer);
				SetHypFieldIsPresent(id, 1);
				//reg_tokenVal.AssertMatch(buffer, this);
				//SetHypFieldLength (id, reg_tokenVal.GetMatchedLength());
			}
			else
				SetHypFieldIsPresent(id, 0);
			break;
		case id_authParams:
			if(reg_authParam.Match(buffer))
			{
				//logfile << "::more auth params found" << std::endl;
				SetHypFieldIsPresent(id, 1);
			}
			else
				SetHypFieldIsPresent(id, 0);
			break;
		default:
			break;
	}
}

//DigestResponse
//------------------------------------------------------------
//============================================================
/*type record DigestResponse {	
	charstring username optional, // quoted-string
    charstring realm optional, // quoted-string
    charstring nonce optional, // quoted-string
    charstring response optional, // DQUOTE 32LHEX DQUOTE; LHEX = DIGIT / %x61-66 ;lowercase a-f
    charstring algorithm optional, // "MD5" / token
    charstring cnonce optional, // quoted-string
    charstring opaque optional, // quoted-string
    Qop_Value message_qop optional, // no quates
    charstring nonce_count optional, // no quates
    AuthParamList authParams optional
}*/
void DigestResponse::PostEncode(Buffer& buffer) throw (EncodeError)
{
	b_needComma = false;
}
void DigestResponse::PreEncodeField(int field_id, Buffer& buffer) throw (EncodeError)
{
	//TODO, only in case there are more fields to encode
	if(IsPresent(field_id) && b_needComma)
	{
		Charstring cs;
		cs.SetValue(", ");
		cs.Encode(buffer);
		b_needComma = false;
		return;
	}
}
void DigestResponse::PreDecodeField(int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "DigestResponse::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_usernameParam ("^username=");
	static Regex reg_realmParam ("^realm=");
	static Regex reg_nonceParam ("^nonce=");
	static Regex reg_responseParam ("^response=");
	//LHEX = DIGIT / %x61-66 ;lowercase a-f
	static Regex reg_responseVal ("^\"([0-9\x61-\x66]{32})\"");
	static Regex reg_algorithmParam ("^algorithm=");
	static Regex reg_cnonceParam ("^cnonce=");
	static Regex reg_opaqueParam ("^opaque=");
	static Regex reg_messageqopParam ("^qop=");
	static Regex reg_noncecountParam ("^nc=");
	//nc-value = 8LHEX
	static Regex reg_noncecountVal ("^[0-9\x61-\x66]{8}");

	static Regex reg_optionalWSP ("^" SIPREG_SWS);
	static Regex req_quotedString ("^" SIPREG_QUOTED_STRING);
	static Regex reg_tokenVal (RFC4975_TOKEN);
	static Regex reg_authParam (RFC4975_TOKEN);
	static Regex reg_paramSep ("^" SIPREG_COMMA);
	
	if(reg_paramSep.Match(buffer))
		reg_paramSep.MovePast(buffer);
	//TODO: who removes the separator?
	//TODO:quoted string processing
	switch (id)
	{//all optional, all have to be detected
//charstring username optional, // quoted-string
		case id_username:
			if(reg_usernameParam.Match(buffer))
			{
				//logfile << "::username found" << std::endl;
				reg_usernameParam.MovePast(buffer);
				SetHypFieldIsPresent(id, 1);
				if(reg_optionalWSP.Match(buffer))
					reg_optionalWSP.MovePast(buffer);
				req_quotedString.AssertMatch(buffer, this);
				SetHypFieldLength (id, req_quotedString.GetMatchedLength());
			}
			else
				SetHypFieldIsPresent(id, 0);
			break;
//charstring realm optional, // quoted-string
		case id_realm:
			if(reg_realmParam.Match(buffer))
			{
				//logfile << "::realm found" << std::endl;
				reg_realmParam.MovePast(buffer);
				SetHypFieldIsPresent(id, 1);
				if(reg_optionalWSP.Match(buffer))
					reg_optionalWSP.MovePast(buffer);
				req_quotedString.AssertMatch(buffer, this);
				SetHypFieldLength (id, req_quotedString.GetMatchedLength());
			}
			else
				SetHypFieldIsPresent(id, 0);
			break;
//charstring nonce optional, // quoted-string
		case id_nonce:
			if(reg_nonceParam.Match(buffer))
			{
				//logfile << "::nonce found" << std::endl;
				reg_nonceParam.MovePast(buffer);
				SetHypFieldIsPresent(id, 1);
				if(reg_optionalWSP.Match(buffer))
					reg_optionalWSP.MovePast(buffer);
				req_quotedString.AssertMatch(buffer, this);
				SetHypFieldLength (id, req_quotedString.GetMatchedLength());
			}
			else
				SetHypFieldIsPresent(id, 0);
			break;
//charstring response optional, // DQUOTE 32LHEX DQUOTE; LHEX = DIGIT / %x61-66 ;lowercase a-f
		case id_response:
			if(reg_responseParam.Match(buffer))
			{
				//logfile << "::response found" << std::endl;
				reg_responseParam.MovePast(buffer);
				SetHypFieldIsPresent(id, 1);
				if(reg_optionalWSP.Match(buffer))
					reg_optionalWSP.MovePast(buffer);
				reg_responseVal.AssertMatch(buffer, this);
				SetHypFieldLength (id, reg_responseVal.GetMatchedLength());
			}
			else
				SetHypFieldIsPresent(id, 0);
			break;
//charstring algorithm optional, // "MD5" / token
		case id_algorithm:
			if(reg_algorithmParam.Match(buffer))
			{
				//logfile << "::algorithm found" << std::endl;
				reg_algorithmParam.MovePast(buffer);
				SetHypFieldIsPresent(id, 1);
				if(reg_optionalWSP.Match(buffer))
					reg_optionalWSP.MovePast(buffer);
				reg_tokenVal.AssertMatch(buffer, this);
				SetHypFieldLength (id, reg_tokenVal.GetMatchedLength());
			}
			else
				SetHypFieldIsPresent(id, 0);
			break;
//charstring cnonce optional, // quoted-string
		case id_cnonce:
			//static Regex reg_qopListStart("^" SIPREG_SWS "\"");
			if(reg_cnonceParam.Match(buffer))
			{
				//logfile << "::cnonce found" << std::endl;
				reg_cnonceParam.MovePast(buffer);
				SetHypFieldIsPresent(id, 1);
				req_quotedString.AssertMatch(buffer, this);
				SetHypFieldLength (id, req_quotedString.GetMatchedLength());
			}
			else
				SetHypFieldIsPresent(id, 0);
			break;
//charstring opaque optional, // quoted-string
		case id_opaque:
			//static Regex reg_qopListStart("^" SIPREG_SWS "\"");
			if(reg_opaqueParam.Match(buffer))
			{
				//logfile << "::opaque found" << std::endl;
				reg_opaqueParam.MovePast(buffer);
				SetHypFieldIsPresent(id, 1);
				req_quotedString.AssertMatch(buffer, this);
				SetHypFieldLength (id, req_quotedString.GetMatchedLength());
			}
			else
				SetHypFieldIsPresent(id, 0);
			break;
//Qop_Value message_qop optional, // no quates
		case id_message_qop:
			//static Regex reg_qopListStart("^" SIPREG_SWS "\"");
			if(reg_messageqopParam.Match(buffer))
			{
				//logfile << "::qop found" << std::endl;
				reg_messageqopParam.MovePast(buffer);
				SetHypFieldIsPresent(id, 1);
				reg_tokenVal.AssertMatch(buffer, this);
				SetHypFieldLength (id, reg_tokenVal.GetMatchedLength());
			}
			else
				SetHypFieldIsPresent(id, 0);
			break;
//charstring nonce_count optional, // no quates
		case id_nonce_count:
			//static Regex reg_qopListStart("^" SIPREG_SWS "\"");
			if(reg_noncecountParam.Match(buffer))
			{
				//logfile << "::nonce_count found" << std::endl;
				reg_noncecountParam.MovePast(buffer);
				SetHypFieldIsPresent(id, 1);
				reg_noncecountVal.AssertMatch(buffer, this);
				SetHypFieldLength (id, reg_noncecountVal.GetMatchedLength());
			}
			else
				SetHypFieldIsPresent(id, 0);
			break;
		//AuthParamList authParams optional
		case id_authParams:
			if(reg_authParam.Match(buffer))
			{
				//logfile << "::more auth params found" << std::endl;
				SetHypFieldIsPresent(id, 1);
			}
			else
				SetHypFieldIsPresent(id, 0);
			break;
		default:
			break;
	}
}
//MsrpWWWAuthenticate
//WWW-Authenticate = "WWW-Authenticate:" SP "Digest" SP digest-param *("," SP digest-param)
//------------------------------------------------------------
//============================================================
void MsrpWWWAuthenticate::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	if(field_id != id_headerName)
		return;
	Charstring cs;
	cs.SetValue(SP);
	cs.Encode(buffer);
}
/*
void MsrpWWWAuthenticate::PostDecodeField(int id, Buffer& buffer) throw (DecodeError)
{
	//digest const field
	

	//digest-param
}*/

void MsrpWWWAuthenticate::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "MsrpWWWAuthenticate::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_headerName ("^" REG_HDR_WWW_Authenticate_TOKEN);
	static Regex reg_digest ("^" SIPREG_SWS "Digest" SIPREG_SWS);
	

	switch (id) {
	case id_headerName:
		reg_headerName.AssertMatch (buffer, this);
		SetHypFieldLength (id, reg_headerName.GetMatchedLength());
		break;
	case id_digest:
		reg_digest.AssertMatch(buffer, this);
		reg_digest.MovePast(buffer);		
		break;
	/*case id_digest:
		msrp_read_sp(buffer, this);
		reg_digest.AssertMatch (buffer, this);
		SetHypFieldLength (id, reg_digest.GetMatchedLength());
		break;
	case id_digestParam_List:
		msrp_read_sp(buffer, this);
		reg_digestParam_List.AssertMatch (buffer, this);
		SetHypFieldLength (id, reg_digestParam_List.GetMatchedLength());
		break;*/
		default:
			break;
	}
}


//MsrpAuthorization
//Authorization = "Authorization:" SP credentials
//------------------------------------------------------------
/*
credentials = "Digest" SP digest-response *( "," SP digest-response)
digest-response = ( username / realm / nonce / response / [algorithm ] /
					cnonce / [opaque] / message-qop /
					[nonce-count] / [auth-param] )

//realm, nonce, algorithm, nonce-value, opaque, auth-param: already defined
*/
//============================================================
void MsrpAuthorization::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	if(field_id != id_headerName)
		return;
	Charstring cs;
	cs.SetValue(SP);
	cs.Encode(buffer);
}

void MsrpAuthorization::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "MsrpAuthorization::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_headerName ("^" REG_HDR_Authorization_TOKEN);
	static Regex reg_digest ("^" SIPREG_SWS "Digest" SIPREG_SWS);
	//static Regex reg_optionalWSP ("^" SIPREG_SWS);


	switch (id) {
	case id_headerName:
		reg_headerName.AssertMatch (buffer, this);
		SetHypFieldLength (id, reg_headerName.GetMatchedLength());
		break;
	case id_digestResponse:

		reg_digest.AssertMatch(buffer, this);
		reg_digest.MovePast(buffer);
		
		break;
	default:
		break;
	}
}

//MsrpAuthenticationInfo
//Authentication-Info = "Authentication-Info:" SP ainfo *("," ainfo)
/*ainfo = nextnonce / message-qop / response-auth / cnonce / nonce-count*/
//------------------------------------------------------------
//============================================================
//TODO: all similar, ainfo list should put the SP in preencode? or if(field_id != 0)
void MsrpAuthenticationInfo::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	if(field_id != id_headerName)
		return;
	Charstring cs;
	cs.SetValue(SP);
	cs.Encode(buffer);
}

void MsrpAuthenticationInfo::PreDecodeField(int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "PreDecodeField::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_headerName ("^" REG_HDR_Authentication_Info_TOKEN);
	
	switch (id) {
		case id_headerName:
			//logfile << "MsrpAuthenticationInfo::PreDecodeField:MatchingFieldName ";
			reg_headerName.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_headerName.GetMatchedLength());
			//logfile << "== OK"<< std::endl;
			break;
			//Authentication-Info = "Authentication-Info:" SP ainfo *("," ainfo)
		/*case id_ainfo_list:
			msrp_read_sp(buffer, this);
			reg_ainfo_list.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_ainfo_list.GetMatchedLength());
			break;*/
		default:
			break;
	}
}

//AInfo
//ainfo = nextnonce / message-qop / response-auth / cnonce / nonce-count
//------------------------------------------------------------
//============================================================
/*
type set AInfo {	// order is not important
	charstring nextnonce optional,
	Qop_Value message_qop optional,  // no quates	
	charstring response_auth optional,
	charstring cnonce optional,
	charstring nonce_count optional	// no quates
}
*/
void AInfo::PreEncodeField(int field_id, Buffer& buffer) throw (EncodeError)
{
	Charstring cs;
	
	if(field_id == id_nextnonce)
		cs.SetValue("nextnonce=");
	else if(field_id == id_response_auth)
		cs.SetValue("rspauth=");
	else if(field_id == id_cnonce)
		cs.SetValue("cnonce=");
	else if(field_id == id_nonce_count)
		cs.SetValue("nc=");
	else if(field_id == id_message_qop)
		cs.SetValue("qop=");
	else
		return;
	//TODO: comma and quoted strings...
	if(IsPresent(field_id))
		cs.Encode(buffer);
}

void AInfo::PreDecode(Buffer& buffer) throw (DecodeError)
{
	static Regex reg_optionalWSP ("^" SIPREG_SWS);
	if(reg_optionalWSP.Match(buffer))
		reg_optionalWSP.MovePast(buffer);

	bIsFirstField = true;
}
void AInfo::PreDecodeField(Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "AInfo::PreDecodeField: " << std::endl;
	logfile.close();
#endif

	static Regex reg_crlf ("^\r\n");

	static Regex reg_nextnonceParam ("^nextnonce=");
	static Regex req_quotedString ("^" SIPREG_QUOTED_STRING);
	static Regex reg_respAuthParam ("^rspauth=");
	static Regex reg_respAuthVal ("^\"([0-9\x61-\x66]*)\"");
	static Regex reg_cnonceParam ("^cnonce=");
	static Regex reg_noncecountParam ("^nc=");
	static Regex reg_noncecountVal ("^[0-9\x61-\x66]{8}");
	static Regex reg_qopParam ("^qop=");
	static Regex reg_genericVal (RFC4975_TOKEN);

	if (bIsFirstField || detect_comma(buffer))
	{
		bIsFirstField = false;
		if(reg_nextnonceParam.Match(buffer))
		{
			//logfile << "AInfo::NextField: nextnoce detected" << std::endl;
			reg_nextnonceParam.MovePast(buffer);
			SetHypNextField (id_nextnonce);
			req_quotedString.AssertMatch(buffer, this);
			SetHypFieldLength (id_nextnonce, req_quotedString.GetMatchedLength());
		}
		else if(reg_respAuthParam.Match(buffer))
		{
			//logfile << "AInfo::NextField: rspauth detected" << std::endl;
			reg_respAuthParam.MovePast(buffer);
			SetHypNextField (id_response_auth);
			reg_respAuthVal.AssertMatch(buffer, this);
			SetHypFieldLength (id_response_auth, reg_respAuthVal.GetMatchedLength());
		}
		else if(reg_cnonceParam.Match(buffer))
		{
			//logfile << "AInfo::NextField: cnonce detected" << std::endl;
			reg_cnonceParam.MovePast(buffer);
			SetHypNextField (id_cnonce);
			req_quotedString.AssertMatch(buffer, this);
			SetHypFieldLength (id_cnonce, req_quotedString.GetMatchedLength());
		}
		else if(reg_noncecountParam.Match(buffer))
		{
			//logfile << "AInfo::NextField: noncecount detected" << std::endl;
			reg_noncecountParam.MovePast(buffer);
			SetHypNextField (id_nonce_count);
			reg_noncecountVal.AssertMatch(buffer, this);
			SetHypFieldLength (id_nonce_count, reg_noncecountVal.GetMatchedLength());
		}
		else if(reg_qopParam.Match(buffer))
		{
			//logfile << "AInfo::NextField: quop detected" << std::endl;
			reg_qopParam.MovePast(buffer);
			SetHypNextField (id_message_qop);
			reg_genericVal.AssertMatch(buffer, this);
			SetHypFieldLength (id_message_qop, reg_genericVal.GetMatchedLength());
		}
		else
		{
			//logfile << "AInfo::NextField: NO FIELDS detected" << std::endl;
			SetHypNextField (-2);
		}
	} else {
		//logfile << "AInfo::NextField: no additional params detected" << std::endl;
		SetHypNextField (-2);
	}
}

//ExtHeader
//ext-header = hname ":" SP hval CRLF
//------------------------------------------------------------
//============================================================
void ExtHeader::PostEncode (Buffer& buffer) throw (EncodeError)
{
	Charstring cs;
	cs.SetValue(CRLF);
	cs.Encode(buffer);
}

void ExtHeader::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	if(field_id != id_hname)
		return;
	
	Charstring cs;
	cs.SetValue(": ");
	cs.Encode(buffer);
}

void ExtHeader::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "ExtHeader::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_hname (HNAME_TOKEN);
	static Regex reg_hval (HVAL_TOKEN);
	static Regex reg_sep ("^" SIPREG_COLON);

	switch (id) {
	case id_hname:
			reg_hname.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_hname.GetMatchedLength());
			break;
		case id_hval:
			skip_mandatory(&reg_sep, buffer, this);
			reg_hval.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_hval.GetMatchedLength());
			break;
		default:
			break;
	}
}

void ExtHeader::PostDecode (Buffer& buffer) throw (DecodeError)
{
	skip_mandatory_CRLF(buffer, this, "ExtHeader");
}


//HeaderList
/*
type record HeaderList {
//RFC 4975
    MessageID messageID optional,
    SuccessReport successReport optional, 
    FailureReport failureReport optional,
    ByteRange byteRange optional,
    MsrpStatus status optional,
//RFC 4976
    MsrpExpires expires optional,
    MsrpMinExpires minExpires optional,
    MaxExpires maxExpires optional,
    UsePath usePath optional,
    MsrpWWWAuthenticate wwwAuthenticate optional,
    MsrpAuthorization authorization optional,
    MsrpAuthenticationInfo authenticationInfo optional,
	ExtHeaderList extHeaders optional
}
*/
//------------------------------------------------------------
//============================================================
void HeaderList::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	if(!IsPresent(field_id) || field_id == id_extHeaders)
		return;
	Charstring csSpace;
	csSpace.SetValue(CRLF);
	csSpace.Encode(buffer);
}

void HeaderList::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "HeaderList::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg[]={
		("^" REG_HDR_MESSAGE_ID_TOKEN),
		("^" REG_HDR_SUCCESS_REPORT_TOKEN),
		("^" REG_HDR_FAILURE_REPORT_TOKEN),
		("^" REG_HDR_BYTE_RANGE_TOKEN),
		("^" REG_HDR_STATUS_TOKEN),
		("^" REG_HDR_Expires_TOKEN),
		("^" REG_HDR_Min_Expires_TOKEN),
		("^" REG_HDR_Max_Expires_TOKEN),
		("^" REG_HDR_Use_Path_TOKEN),
		("^" REG_HDR_WWW_Authenticate_TOKEN),
		("^" REG_HDR_Authorization_TOKEN),
		("^" REG_HDR_Authentication_Info_TOKEN),
		("^(" HNAME ")" MSRPREG_HEADER_COLON)
	};
	
	int nPresent = 0;
	if(reg[id].Match(buffer))
	{
		nPresent = 1;
		if(id == id_extHeaders)//special handling
		{
			std:string match = reg[id].GetMatchedString(1);
			//is a MIME field?
			if(match.length() >= 8 && !match.substr(0, 8).compare("Content-"))
				nPresent = 0;
		}
	}
	SetHypFieldIsPresent(id, nPresent);
}

void HeaderList::PostDecodeField (int field_id, Buffer& buffer) throw (DecodeError)
{
	if(!IsPresent(field_id) || field_id == id_extHeaders)
		return;
	skip_mandatory_CRLF(buffer, this, "HeaderList");
}

//ExtHeaderList
//
//------------------------------------------------------------
//============================================================
void ExtHeaderList::PostDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
	static Regex reg_nexthname ("^" HNAME MSRPREG_HEADER_COLON);
	static Regex reg_nextMimeHdr ("^" REG_HDR_MIME_ANY_TOKEN_GR);
	//additional check is in order...
	//"Content-" fields might be consumed
	if (reg_nexthname.Match(buffer) && !reg_nextMimeHdr.Match(buffer))
		SetHypSize (GetSize() + 1);
	else
		SetHypSize (-2);
}



//Headers
//headers = To-Path CRLF From-Path CRLF 1*( header CRLF )
//header = Message-ID / Success-Report / Failure-Report / Byte-Range / Status / ext-header
//------------------------------------------------------------
/*
type record Headers
{
	ToPath toPath,
    FromPath fromPath,
    HeaderList headers optional
} 
*/
//============================================================
void Headers::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	if(field_id == id_headers)
		return;
	Charstring cs;
	cs.SetValue(CRLF);
	cs.Encode(buffer);
}

void Headers::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "Headers::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_nexthname ("^" HNAME MSRPREG_HEADER_COLON);
	if(id == id_headers)
	{
		//logfile << "Looking for additional headers: ";
		if(reg_nexthname.Match(buffer))
		{
			//logfile << "FOUND additional headers" << std::endl;
			SetHypFieldIsPresent(id, 1);
		}
		else
		{
			//logfile << "No additional headers found." << std::endl;
			SetHypFieldIsPresent(id, 0);
		}
	}
}

void Headers::PostDecodeField(int field_id, Buffer& buffer) throw(DecodeError)
{
	if(field_id == id_headers)
		return;
	skip_mandatory_CRLF(buffer, this, "Headers");
}

//MsrpGenericParam
//gen-param = pname [ "=" pval ]
//------------------------------------------------------------
//============================================================
void MsrpGenericParam::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	if(field_id == id_paramID && IsPresent(id_paramValue))
	{
		Charstring cs;
		cs.SetValue("=");
		cs.Encode(buffer);
	}
}
void MsrpGenericParam::PostDecode(Buffer& buffer) throw (DecodeError)
{
	//TODO:Token value, should be lowercased
	process_token_value(Get_paramID());

	if (IsPresent (id_paramValue))
	{
		Charstring& value = Get_paramValue();

		if (value.GetLength() &&
		    (*value.GetValueBin() == '"')) {
			normalise_quoted_string (value, true);
		}else {
			process_token_value(value);
			//TODO:Token value, should be lowercased
		}
		/* else {
			const char* par_name = Get_id().GetValue();
			
			//TODO: add unescaped params ???
			if (strcmp (parent_type, "Unescaped") == 0)
					goto skip_escape;
do_escape:
			normalise_escaped_string (value);
skip_escape: ;

		}*/
	}
}

void MsrpGenericParam::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "GenericParam::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_paramID (PNAME_TOKEN);
	static Regex reg_sepEqual("^" SIPREG_EQUAL);
	static Regex reg_paramValue (PVAL_TOKEN);

	switch (id) {
		case id_paramID:
			reg_paramID.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_paramID.GetMatchedLength());
			break;
		case id_paramValue:
			if(detect_assign(buffer))//TODO: check all places, if this is skipped
			{
				//skip_mandatory(&reg_sepEqual, buffer, this);
				SetHypFieldIsPresent(id, 1);
				reg_paramValue.AssertMatch (buffer, this);
				SetHypFieldLength (id, reg_paramValue.GetMatchedLength());
			}
			else
				SetHypFieldIsPresent(id, 0);
			break;
		default:
			break;
	}
}

//URIParams
//URI-parameter = token ["=" token]
//------------------------------------------------------------
//============================================================


//MsrpSchemes
//msrp-scheme = "msrp" / "msrps"
//------------------------------------------------------------
/*
type union MsrpSchemes {
	MsrpKeywords scheme (e_SCHEME),
    MsrpKeywords secureScheme (e_SCHEMES)
}
*/
//============================================================
void MsrpSchemes::PreDecode (Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "MsrpSchemes::PreDecode" << std::endl;
	logfile.close();
#endif

	static Regex reg_msrps ("^msrps");
	
	//mPosition = buffer.GetPosition();
	SetHypChosenId (
		reg_msrps.Match (buffer)
			? id_secureScheme
			: id_scheme
	);
}


//Authority
//authority   = [ userinfo "@" ] host [ ":" port ]
//------------------------------------------------------------
/*type record Authority {	// authority   = [ userinfo "@" ] host [ ":" port ]
	charstring userinfo optional,
    charstring host, // if host is IPv6 the "[" and "]" should be removed when decoding and added when encoding	
    integer portNumber optional
}*/
void Authority::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	static Regex reg_ipv6("^" SIPREG_IP6_INTERNAL);
	//#define IPvFUTURE "v[" HEXDIG_IN_SET "]+\\.[" UNRESERVED_IN_SET SUB_DELIMS_IN_SET ":]+" 
	//static Regex reg_vFut("^[" HEXDIG_IN_SET "]+\\.[" UNRESERVED_IN_SET SUB_DELIMS_IN_SET ":]+");
	
	Charstring cs;
	switch(field_id) {
	case id_host:
		if(IsPresent(id_userinfo))
		{
			cs.SetValue("@");
			cs.Encode(buffer);
		}
		//TODO: put IPv6 delimiters back...
		break;
	case id_portNumber:
		if(IsPresent(id_portNumber))
		{
			Get_portNumber().SetFormat(Integer::AsciiDecimal);
			cs.SetValue(":");
			cs.Encode(buffer);
		}
		break;
	default:
		break;
	}
}

void Authority::PostDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "Authority::PostDecodeField: " << id << std::endl;
	logfile.close();
#endif
	
	static Regex reg_userinfoEnd ("^" SIPREG_SWS "@");
	switch (id) {
		case id_userinfo:
			if(IsPresent(id_userinfo))
			{
				//logfile << "Authority::PostDecodeField:Skipping: " << reg_userinfoEnd.GetMatchedString() << std::endl;
				skip_mandatory(&reg_userinfoEnd, buffer, this);
			}
			break;
		case id_host:
			if(*Get_host().GetValue() == '[')//is IPv6 or future
			{
				const char * pStr = Get_host().GetValue()+1;
				const char * pEnd = pStr + Get_host().GetLength()/8;
				for(; pStr != pEnd; pStr++)
				{
					if(*pStr == 'v' || *pStr == 'V')
					{
						pStr++;
						break;
					}
					else if(*pStr != ' ' && 
						*pStr != '\t' &&
						*pStr != '\v' && 
						*pStr != '\f')
						break;
				}
				std::string result(pStr, pEnd-1);
				Get_host().SetValue(result.c_str());
			}
			//TODO:
			//when encoding how do i know if it is IPv6?
			//test to see if it matches?
			//if host is IPv6 the "[" and "]" should be removed when 
			//decoding and added when encoding	
			break;
		default:
			break;
	}
}
void Authority::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "Authority::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	/*type record Authority {	// authority   = [ userinfo "@" ] host [ ":" port ]
		charstring userinfo optional,
		charstring host, // if host is IPv6 the "[" and "]" should be removed when decoding and added when encoding	
		integer portNumber optional
	*/
	//#define AUTHORITY "(" USERINFO "@)?" HOST "(:" PORT ")?"
	//#define HOST "(" IP_LITERAL "|" IPv4ADDRESS "|" REG_NAME ")"
	
	//authority   = [ userinfo "@" ] host [ ":" port ]
	
	//userinfo      = *( unreserved / pct-encoded / sub-delims / ":" )
	//host          = IP-literal / IPv4address / reg-name
	//port          = *DIGIT
	
	static Regex reg_userinfo ("^(" USERINFO ")" SIPREG_SWS "@");
	//static Regex reg_host ("^" HOST);
	static Regex reg_host ("^" SIPREG_HOSTNAME);
	static Regex reg_colon ("^" SIPREG_COLON);
	static Regex reg_port ("^" PORT);

	//host          = IP-literal / IPv4address / reg-name
	//IP-literal = "[" ( IPv6address / IPvFuture  ) "]"
	//IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet

	//reg-name = *( unreserved / pct-encoded / sub-delims )
	//unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
	//pct-encoded   = "%" HEXDIG HEXDIG
	//sub-delims    = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="

	/*SIP definitions
	host             =  hostname / IPv4address / IPv6reference
	hostname         =  *( domainlabel "." ) toplabel [ "." ]
	domainlabel      =  alphanum / alphanum *( alphanum / "-" ) alphanum
	toplabel         =  ALPHA / ALPHA *( alphanum / "-" ) alphanum
	alphanum  =  ALPHA / DIGIT
	*/

	switch (id) {
		case id_userinfo:
			if(reg_userinfo.Match(buffer))
			{
				//logfile << "Authority::UserInfo:Detected: " << reg_userinfo.GetMatchedString(1) << std::endl;
				SetHypFieldIsPresent(id, 1);
				SetHypFieldLength(id, reg_userinfo.GetMatchedLength(1));
			}
			else
			{
				//logfile << "Authority::UserInfo:NotPresent" << std::endl;
				SetHypFieldIsPresent(id, 0);
			}
			break;
		case id_host:
			reg_host.AssertMatch(buffer, this);
			SetHypFieldLength(id, reg_host.GetMatchedLength());
			//logfile << "Authority::Host: " << reg_host.GetMatchedString() << std::endl;
			break;
		case id_portNumber:
			if(reg_colon.Match(buffer))
			{
				buffer.SetPosition(buffer.GetPosition() + reg_colon.GetMatchedLength());
				SetHypFieldIsPresent(id, 1);
				Get_portNumber().SetFormat(Integer::AsciiDecimal);
				reg_port.AssertMatch(buffer, this);
				SetHypFieldLength(id, reg_port.GetMatchedLength());
				//logfile << "Authority::Port:Detected: " << reg_port.GetMatchedString() << std::endl;
			}
			else
			{
				//logfile << "Authority::Port:NotPresent: "<< std::endl;
				SetHypFieldIsPresent(id, 0);
			}
			break;
		default:
			break;
	}
}

//============================================================
//MsrpURI
//MSRP-URI = msrp-scheme "://" authority ["/" session-id] ";" transport *( ";" URI-parameter)
//; authority as defined in RFC3986
//------------------------------------------------------------
/*
type record MsrpURI { // scheme://domain:port/path?query_string#fragment_id
    MsrpSchemes scheme, //Union
    Authority authority, //
    SessionID sessionID optional,
    charstring transport, // transport = "tcp" / 1*ALPHANUM
    URIParams uriParams optional // List of URI-parameter
}
*/
//============================================================
void MsrpURI::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	Charstring cs;
	//MSRP-URI = msrp-scheme "://" authority ["/" session-id] ";" transport *( ";" URI-parameter)
	switch(field_id) {
	case id_authority:
		cs.SetValue("://");
		cs.Encode(buffer);
		break;
	case id_sessionID:
		if(IsPresent(id_sessionID))
		{
			cs.SetValue("/");
			cs.Encode(buffer);
		}
		break;
	case id_transport:
		cs.SetValue(";");
		cs.Encode(buffer);
		break;
	default:
		break;
	}
}

void MsrpURI::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "MsrpURI::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_msrpScheme(MSRP_SCHEME_TOKEN);
	static Regex reg_authSep ("^" SIPREG_SWS "://" SIPREG_SWS);
	//static Regex reg_authority (AUTHORITY_TOKEN);
	static Regex reg_sessSep ("^" SIPREG_SLASH);
	static Regex reg_sessionID (SESSION_ID_TOKEN);
	static Regex reg_transportSep ("^" SIPREG_SEMI);
	static Regex reg_transport (TRANSPORT_TOKEN);
	
	switch (id) {
		case id_scheme:
			msrp_read_sp(buffer, this);
			reg_msrpScheme.AssertMatch (buffer, this);
			//logfile << "Match: " << reg_msrpScheme.GetMatchedString().c_str() << std::endl;
			SetHypFieldLength (id, reg_msrpScheme.GetMatchedLength());
			break;
		case id_authority:
			skip_mandatory(&reg_authSep, buffer, this);

			//logfile << "Authority value: ";
			//reg_authority.AssertMatch (buffer, this);
			//logfile << "Match: " << reg_authority.GetMatchedString().c_str() << std::endl;
			//SetHypFieldLength (id, reg_authority.GetMatchedLength());
			break;
		case id_sessionID:
			//logfile << "Session ID: ";
			if(reg_sessSep.Match(buffer))
			{
				reg_sessSep.MovePast(buffer);
				//logfile << "Present " << std::endl;
				reg_sessionID.AssertMatch(buffer, this);
				//logfile << "Session ID value: " << reg_sessionID.GetMatchedString().c_str() << std::endl;
				SetHypFieldIsPresent(id, 1);
				SetHypFieldLength (id, reg_sessionID.GetMatchedLength());
			}
			else
			{
				//logfile << "Not Present " << std::endl;
				SetHypFieldIsPresent(id, 0);
			}
			break;
		case id_transport:
			skip_mandatory(&reg_transportSep, buffer, this);
			
			//logfile << "Transport value: ";
			reg_transport.AssertMatch(buffer, this);
			//logfile << reg_transport.GetMatchedString().c_str() << std::endl;
			SetHypFieldLength (id, reg_transport.GetMatchedLength());
			break;
		case id_uriParams:
			//logfile << "Looking For URI-Params:";
			if(detect_semi(buffer))
			{
				//logfile << "Detected " << std::endl;
				SetHypFieldIsPresent(id, 1);
			}
			else
			{
				//logfile << "Not found" << std::endl;
				SetHypFieldIsPresent(id, 0);
			}
			break;
		default:
			break;
	}
}

//MsrpURIs
//MSRP-URI = msrp-scheme "://" authority
//------------------------------------------------------------
//type set of MsrpURI MsrpURIs;// length (1..infinity);
//============================================================
void MsrpURIs::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	if(field_id == 0)
		return;
	Charstring csSpace;
	csSpace.SetValue(SP);
	csSpace.Encode(buffer);
}

void MsrpURIs::PostDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "MsrpURIs::PostDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_next ("^" SIPREG_SWS MSRP_SCHEME);
	if (reg_next.Match(buffer))
	{
		SetHypSize (GetSize() + 1);
		//logfile << "MsrpURIs::PreDecodeField:FoundAnotherURI, new size: " << GetSize() << std::endl;
	}
	else
	{
		SetHypSize (-2);
		//logfile << "MsrpURIs::PreDecodeField:No new URI found, size: " << GetSize() << std::endl;
	}
}

//ToPath
//To-Path = "To-Path:" SP MSRP-URI *( SP MSRP-URI )
//------------------------------------------------------------
/*
type record ToPath {
	HeaderName headerName (TO_PATH_E),
	MsrpURIs msrpURIs
}
*/
//============================================================
void ToPath::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	if(field_id != id_headerName)
		return;
	Charstring cs;
	cs.SetValue(SP);
	cs.Encode(buffer);
}

void ToPath::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "ToPath::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_headerName("^" REG_HDR_To_Path_TOKEN);

	switch (id) {
	case id_headerName:
			reg_headerName.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_headerName.GetMatchedLength());
			break;
		/*case id_msrpURIs:
			msrp_read_sp(buffer, this);
			break;*/
		default:
			break;
	}
}

//FromPath
//From-Path = "From-Path:" SP MSRP-URI *( SP MSRP-URI )
//------------------------------------------------------------
//============================================================
void FromPath::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	if(field_id != id_headerName)
		return;
	Charstring cs;
	cs.SetValue(SP);
	cs.Encode(buffer);
}

void FromPath::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "FromPath::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_headerName("^" REG_HDR_From_Path_TOKEN);
	
	switch (id) {
	case id_headerName:
			reg_headerName.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_headerName.GetMatchedLength());
			break;
		/*case id_msrpURIs:
			msrp_read_sp(buffer, this);
			break;*/
		default:
			break;
	}
}

//MimeExtensionFieldList
//*(Other-Mime-header CRLF)
//------------------------------------------------------------
//type set of OtherMimeHeader MimeHeaders;
//type set of MimeExtensionField MimeExtensionFieldList;
void MimeExtensionFieldList::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	Charstring csCRLF;
	csCRLF.SetValue(CRLF);
	csCRLF.Encode(buffer);
}

void MimeExtensionFieldList::PostDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "MimeExtensionFieldList::PostDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_nextmimehdr ("^" REG_HDR_MIME_ANY_TOKEN_GR);

	skip_mandatory_CRLF(buffer, this, "MimeExtensionFieldList");
	
	int nMatch = 0;
	if(reg_nextmimehdr.Match(buffer))
	{
		nMatch = 1;
		//TODO:additional check anti "Content-Type"
		std:string match = reg_nextmimehdr.GetMatchedString(1);
		if(match.length() == strlen(KW_CONTENT_TYPE_HEADER_NAME) 
				&& !match.compare(KW_CONTENT_TYPE_HEADER_NAME))
			nMatch = 0;
	}
	if (nMatch)
		SetHypSize (GetSize() + 1);
	else
		SetHypSize (-2);
}

//MimeHeaders
//*(Other-Mime-header CRLF)
//------------------------------------------------------------
//type set of OtherMimeHeader MimeHeaders;
/*
type record MimeHeaders {
	ContentID contentID optional,
    ContentDescription contentDescription optional,
    MsrpContentDisposition contentDisposition optional,
    MimeExtensionFieldList mimeExtensionFields optional
}

*/
//============================================================
void MimeHeaders::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	if(!IsPresent(field_id) || field_id == id_mimeExtensionFields)
		return;
	Charstring csCRLF;
	csCRLF.SetValue(CRLF);
	csCRLF.Encode(buffer);
}

void MimeHeaders::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "MimeHeaders::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif
	//this will not react good on type structure changes...
	
	static Regex reg_fields[] = {
		("^" REG_HDR_Content_ID_TOKEN),
		("^" REG_HDR_Content_Description_TOKEN),
		("^" REG_HDR_Content_Disposition_TOKEN),
		("^" REG_HDR_MIME_ANY_TOKEN_GR)
	};
	int nMatch = 0;
	if(reg_fields[id].Match(buffer))
	{
		nMatch = 1;
		if(id == id_mimeExtensionFields)
		{
			//additional check anti "Content-Type"
			std:string match = reg_fields[id].GetMatchedString(1);
			if(match.length() == strlen(KW_CONTENT_TYPE_HEADER_NAME) 
				&& !match.compare(KW_CONTENT_TYPE_HEADER_NAME))
				nMatch = 0;
		}
	}
	SetHypFieldIsPresent(id, nMatch);
}

void MimeHeaders::PostDecodeField(int field_id, Buffer& buffer) throw (DecodeError)
{
	if(!IsPresent(field_id) || field_id == id_mimeExtensionFields)
		return;
	skip_mandatory_CRLF(buffer, this, "MimeHeaders");
}

//GenParam
//gen-param = pname [ "=" pval ]
//------------------------------------------------------------
/*
type record GenParam {
	Token pname,
	octetstring pval optional
}
*/
//============================================================
void GenParam::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	if(field_id == id_pname && IsPresent(id_pval))
	{
		Charstring cs;
		cs.SetValue("=");
		cs.Encode(buffer);
	}
}

void GenParam::PostDecode(Buffer& buffer) throw (DecodeError)
{
	//TODO:Token value, should be lowercased
	process_token_value(Get_pname());

	if (IsPresent (id_pval))
	{
		Charstring& value = Get_pval();

		if (value.GetLength() &&
		    (*value.GetValueBin() == '"')) {
			normalise_quoted_string (value, true);
		} else {
			process_token_value(value);
		}
		/*	const char* par_name = Get_id().GetValue();
			
			//TODO: add unescaped params ???
			if (strcmp (parent_type, "Unescaped") == 0)
					goto skip_escape;
do_escape:
			normalise_escaped_string (value);
skip_escape: ;

		}*/
	}
}

void GenParam::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "GenParam::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_paramID (PNAME_TOKEN);
	static Regex reg_paramValue (PVAL_TOKEN);
	static Regex reg_sepEqual ("^" SIPREG_EQUAL);
	switch (id) {
	case id_pname:
			reg_paramID.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_paramID.GetMatchedLength());
			break;
		case id_pval:
			if(detect_assign(buffer))
			{
				SetHypFieldIsPresent(id, 1);
				//skip_mandatory(&reg_sepEqual, buffer, this);
				reg_paramValue.AssertMatch(buffer, this);
				SetHypFieldLength (id, reg_paramValue.GetMatchedLength());
			}
			else
				SetHypFieldIsPresent(id, 0);
			break;
		default:
			break;
	}
}

//TODO: is separated by semi?
//GenParams
//gen-param = pname [ "=" pval ]
//------------------------------------------------------------
//============================================================
void GenParams::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	Charstring csSpace;
	csSpace.SetValue(";");
	csSpace.Encode(buffer);
}

void GenParams::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "GenParams::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif
	//TODO:
	static Regex reg_sepSemi ("^" SIPREG_SEMI);
	if (reg_sepSemi.Match(buffer))
		reg_sepSemi.MovePast(buffer);
}

void GenParams::PostDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
	if (detect_semi(buffer))
		SetHypSize (GetSize() + 1);
	else
		SetHypSize (-2);
}

//MediaType
//media-type = type "/" subtype *( ";" gen-param )
//------------------------------------------------------------
/*
type record MediaType
{
	Token mediaType,
    Token subType,
    GenParams genParams optional
} 
*/
//============================================================
void MediaType::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	if(field_id != id_mediaType)
		return;
	Charstring cs;
	cs.SetValue("/");
	cs.Encode(buffer);
}

void MediaType::PostDecode(Buffer& buffer) throw (DecodeError)
{
	//TODO:Token value, should be lowercased
	process_token_value(Get_mediaType());
	process_token_value(Get_subType());
}

void MediaType::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "MediaType::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_typeToken ("^[" RFC4975_TOKEN_IN_SET "]+");
	static Regex reg_sepSlash ("^" SIPREG_SLASH);

	
	switch (id) {
		case id_mediaType:
			reg_typeToken.AssertMatch(buffer, this);
			SetHypFieldLength (id, reg_typeToken.GetMatchedLength());
			//logfile << "MediaType::mediaTypeToken length: " << reg_typeToken.GetMatchedString() << std::endl;
			break;
		case id_subType:
			skip_mandatory(&reg_sepSlash, buffer, this);
			reg_typeToken.AssertMatch(buffer, this);
			SetHypFieldLength (id, reg_typeToken.GetMatchedLength());
			//logfile << "MediaType::subTypeToken length: " << reg_typeToken.GetMatchedString() << std::endl;
			break;
		case id_genParams:
			if(detect_semi(buffer))
			{
				//logfile << "MediaType::GenParams are present" << std::endl;
				SetHypFieldIsPresent(id, 1);
			}
			else
			{
				//logfile << "MediaType::GenParams are missing" << std::endl;
				SetHypFieldIsPresent(id, 0);
			}
			break;
		default:
			break;
	}
}

//MsrpContentType
//Content-Type = "Content-Type:" SP media-type
//------------------------------------------------------------
/*
type record MsrpContentType
{
    HeaderName headerName (CONTENT_TYPE_E),
	MediaType mediaType
}
*/
//============================================================
void MsrpContentType::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	if(field_id != id_headerName)
		return;
	Charstring cs;
	cs.SetValue(SP);
	cs.Encode(buffer);
}

void MsrpContentType::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "MsrpContentType::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif
	//Content-Type = "Content-Type:" SP media-type
	static Regex reg_headerName("^" REG_HDR_CONTENT_TYPE_TOKEN);
	
	switch (id) {
	case id_headerName:
			reg_headerName.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_headerName.GetMatchedLength());
			break;
	case id_mediaType:
			msrp_read_sp(buffer, this);
			break;
	default:
		break;
	}
}

//ContentID
//"Content-ID" ":" msg-id
//msg-id = "<" addr-spec ">" ; Unique message id
//addr-spec   =  local-part "@" domain        ; global address
//local-part  =  word *("." word)             ; uninterpreted
//                                                 ; case-preserved
//domain      =  sub-domain *("." sub-domain)
//sub-domain  =  domain-ref / domain-literal
//domain-ref  =  atom                         ; symbolic reference

//------------------------------------------------------------
/*
type record ContentID
{
    HeaderName headerName (CONTENT_ID_E),
	charstring msgID
}
*/
//============================================================
void ContentID::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	if(field_id != id_headerName)
		return;
	Charstring cs;
	cs.SetValue(SP);
	cs.Encode(buffer);
}

void ContentID::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "ContentID::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_headerName("^" REG_HDR_Content_ID_TOKEN);
	static Regex reg_msgID("^<[^>]*>");//workaround...

	switch (id) {
		case id_headerName:
			reg_headerName.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_headerName.GetMatchedLength());
			break;
		case id_msgId:
			msrp_skip_sp(buffer);
			reg_msgID.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_msgID.GetMatchedLength());
			break;
	default:
		break;
	}
}

//ContentDescription
//description := "Content-Description" ":" *text
//text        =  <any CHAR, including bare    ; => atoms, specials,
//                     CR & bare LF, but NOT       ;  comments and
//                     including CRLF>             ;  quoted-strings are
//                                                 ;  NOT recognized.
//------------------------------------------------------------
/*
type record ContentDescription
{
    HeaderName headerName (CONTENT_DESCRIPTION_E),
	charstring text
}
*/
//============================================================
void ContentDescription::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	if(field_id != id_headerName)
		return;
	Charstring cs;
	cs.SetValue(SP);
	cs.Encode(buffer);
}

void ContentDescription::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "ContentDescription::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_headerName("^" REG_HDR_Content_Description_TOKEN);
	static Regex reg_text("^([^\r]*|\r[^\n])*");//workaround

	switch (id) {
		case id_headerName:
			reg_headerName.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_headerName.GetMatchedLength());
			break;
		case id_text:
			msrp_skip_sp(buffer);
			reg_text.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_text.GetMatchedLength());
			break;
	default:
		break;
	}
}

//MsrpContentDisposition
//disposition := "Content-Disposition" ":" disposition-type *(";" disposition-parm)
//disposition-type := "inline"
//			/ "attachment"
//			/ extension-token
//			; values are not case-sensitive
//extension-token := ietf-token / x-token
//ietf-token := <An extension token defined by a
//                    standards-track RFC and registered
//                    with IANA.>
//x-token := <The two characters "X-" or "x-" followed, with
//                 no intervening white space, by any token>
//token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
//                 or tspecials>
//33-126 (\x21-\x7E)
//tspecials :=  
//<"> /22
//"(" /28
//")" /29
//"," /2C
//"/" /2F
//":" /3A
//";" /3B
//"<" /3C
//"=" /3D
//">" /3E
//"?" /3F
//"@" /40
//"[" /5B
//"\" /5C
//"]" /5D
//                   ; Must be in quoted-string,
//                   ; to use within parameter values




//any CHAR, excluding CTLs, SPACE, and ":"        33-57, 59-126
//													decimal
//CHAR        =  <any ASCII character>        ; (	0.-127.)
//SPACE       =  <ASCII SP, space>            ; (		32.)
//":"											(		58.)//3A
//CTL         =  <any ASCII control           ; (	0.- 31.)
// character and DEL>						  ; (		127.)
//------------------------------------------------------------
/*
type record MsrpContentDisposition
{
    HeaderName headerName (CONTENT_ID_E),
	charstring dispositionType,
	GenParams dispositionParams optional
}
*/
//============================================================
void MsrpContentDisposition::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	if(field_id != id_headerName)
		return;
	Charstring cs;
	cs.SetValue(SP);
	cs.Encode(buffer);
}
#define CONTENT_DISPOSITION_TYPE_CHARSET "\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7E"
void MsrpContentDisposition::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "MsrpContentDisposition::PreDecodeField: " << id << std::endl;
	logfile << "MsrpContentDisposition::DispositionTypeCharset: " << CONTENT_DISPOSITION_TYPE_CHARSET << std::endl;
	logfile.close();
#endif

	static Regex reg_headerName("^" REG_HDR_Content_Disposition_TOKEN);
	static Regex reg_contentDispositionType("^["CONTENT_DISPOSITION_TYPE_CHARSET"]+");
	//disposition := "Content-Disposition" ":" disposition-type *(";" disposition-parm)
	switch (id) {
		case id_headerName:
			reg_headerName.AssertMatch (buffer, this);
			SetHypFieldLength (id, reg_headerName.GetMatchedLength());
			break;
		case id_dispositionType:
			msrp_skip_sp(buffer);
			reg_contentDispositionType.AssertMatch(buffer, this);
			SetHypFieldLength (id, reg_contentDispositionType.GetMatchedLength());
			break;
		case id_dispositionParams:
			if(detect_semi(buffer))
				SetHypFieldIsPresent(id, 1);
			else
				SetHypFieldIsPresent(id, 0);
			break;
	default:
		break;
	}
}


//MimeExtensionField
//------------------------------------------------------------
/*
type record MimeExtensionField {
	HeaderName headerName (MIME_EXT_FIELD_E),
    charstring hname,
    charstring hval
}
*/
//============================================================
void MimeExtensionField::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{
	if(field_id != id_hname)
		return;
	Charstring cs;
	cs.SetValue(SP);
	cs.Encode(buffer);
}
void MimeExtensionField::PostDecode (Buffer& buffer) throw (DecodeError)
{
	Get_hname().SetValue(m_shname.c_str());
}

void MimeExtensionField::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "MimeExtensionField::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_headerName("^" REG_HDR_MIME_ANY_TOKEN_GR);
	//static Regex reg_hname(HNAME_TOKEN);
	static Regex reg_hval(HVAL_TOKEN);
	
	switch (id) {
		case id_headerName:
			reg_headerName.AssertMatch (buffer, this);
			m_shname.assign(reg_headerName.GetMatchedString(1));
			SetHypFieldLength (id, reg_headerName.GetMatchedLength());
			break;
		case id_hname:
			
			SetHypFieldLength(id, 0);
			break;
		case id_hval:
			reg_hval.AssertMatch(buffer, this);
			SetHypFieldLength (id, reg_hval.GetMatchedLength());
			break;
		default:
			break;
	}
}

//ContentStuff
//content-stuff = *(Other-Mime-header CRLF) Content-Type 2CRLF data CRLF
//------------------------------------------------------------
/*
type record ContentStuff
{
	MimeHeaders mimeHeaders optional,
    MsrpContentType contentType,
    Data data        
}
*/
//============================================================
void ContentStuff::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError)
{	
	Charstring cs;
	cs.SetValue(CRLF);
	switch(field_id)
	{
		case id_contentType:
			cs.Encode(buffer);//x2 times
		case id_data:
			cs.Encode(buffer);
			break;
		default:
			break;
	}
}

void ContentStuff::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "ContentStuff::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_mimeHeaders ("^" REG_HDR_MIME_ANY_TOKEN_GR);
	static Regex reg_contentType ("^" REG_HDR_CONTENT_TYPE_TOKEN);
	static Regex reg_sepForData("^\r\n");
	static Regex reg_data ("^([^\r]*|\r[^\n])*");//data = *OCTET
	
	//content-stuff = *(Other-Mime-header CRLF) Content-Type 2CRLF data CRLF
	if(id == id_mimeHeaders){
		//logfile << "Looking for Other-mime-headers: ";
		if(reg_contentType.Match(buffer))
		{
			//logfile << "Only Content-Type found" << std::endl;
			SetHypFieldIsPresent(id, 0);
		}
		else if(reg_mimeHeaders.Match(buffer))
		{
			//logfile << "Additional header found:" << reg_mimeHeaders.GetMatchedString().c_str() << std::endl;
			SetHypFieldIsPresent(id, 1);
		}
		else//Other-Mime-header CRLF
		{
			//logfile << "No Content headers?" << std::endl;
			SetHypFieldIsPresent(id, 0);
		}
	}
	else if(id == id_data) {
		skip_mandatory(&reg_sepForData, buffer, this);
		reg_data.AssertMatch (buffer, this);
		//logfile << "Data length: " << reg_data.GetMatchedLength() << std::endl;
		//logfile << "StringValue: \"" << reg_data.GetMatchedString() << '"' <<std::endl;
		SetHypFieldLength (id, reg_data.GetMatchedLength());
	}
}

void ContentStuff::PostDecodeField (int field_id, Buffer& buffer) throw (DecodeError)
{
	if(field_id == id_mimeHeaders)
		return;
	skip_mandatory_CRLF(buffer, this, "ContentStuff");
}

///default handling for the following types:::

//TODO: optional [ content-stuff ] field detection

//SEND_request
//msrp-request = req-start headers [content-stuff] end-line
//------------------------------------------------------------
/*
type record SEND_request
{
	MsrpRequestLine startLine,
    Headers headers,
    ContentStuff contentStuff optional,
    EndLine endLine
}*/
//============================================================
void SEND_request::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "SEND_request::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	//TODO: any more like this?
	static Regex reg_contentHeaders ("^Content-[" RFC4975_TOKEN_IN_SET "]+" MSRPREG_HEADER_COLON);
		
	if(id == id_contentStuff)
	{
		if(reg_contentHeaders.Match(buffer))
		{
			//logfile << "FOUND content headers" << std::endl;
			SetHypFieldIsPresent(id, 1);
		}
		else
		{
			//logfile << "No content headers found." << std::endl;
			SetHypFieldIsPresent(id, 0);
		}
	}
}

//REPORT_request
//msrp-request = req-start headers [content-stuff] end-line
//------------------------------------------------------------
//============================================================
void REPORT_request::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "REPORT_request::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_contentHeaders ("^Content-[" RFC4975_TOKEN_IN_SET "]+" MSRPREG_HEADER_COLON);
		
	if(id == id_contentStuff)
	{
		if(reg_contentHeaders.Match(buffer))
		{
			//logfile << "FOUND content headers" << std::endl;
			SetHypFieldIsPresent(id, 1);
		}
		else
		{
			//logfile << "No content headers found." << std::endl;
			SetHypFieldIsPresent(id, 0);
		}
	}
}

//AUTH_request
//msrp-request = req-start headers [content-stuff] end-line
//------------------------------------------------------------
//============================================================
void AUTH_request::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "AUTH_request::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif

	static Regex reg_contentHeaders ("^Content-[" RFC4975_TOKEN_IN_SET "]+" MSRPREG_HEADER_COLON);
		
	if(id == id_contentStuff)
	{
		if(reg_contentHeaders.Match(buffer))
		{
			//logfile << "FOUND content headers" << std::endl;
			SetHypFieldIsPresent(id, 1);
		}
		else
		{
			//logfile << "No content headers found." << std::endl;
			SetHypFieldIsPresent(id, 0);
		}
	}
}

//RECEIVE_response
//msrp-response = resp-start headers end-line
//------------------------------------------------------------
//============================================================
//No need for additional processing, just for logging
void RECEIVE_response::PreDecodeField (int id, Buffer& buffer) throw (DecodeError)
{
#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "RECEIVE_response::PreDecodeField: " << id << std::endl;
	logfile.close();
#endif
}


//TTCN-3 specific enumerated types
//MsrpKeywords
//------------------------------------------------------------
//============================================================

const char* MsrpKeywords::msKeywordEnums[] = { 
        "e_MSRP",
        "e_SCHEME",
        "e_SCHEMES",
        "e_YES",
        "e_NO",
        "e_PARTIAL",
		"e_WILDCARD",
		"" };

const char* MsrpKeywords::msKeywordStrings[] = { 
        "MSRP", //"e_MSRP",
        "msrp", //"e_SCHEME",
        "msrps", //"e_SCHEMES",
        "yes", //"e_YES",
        "no", //"e_NO",
        "partial", //"e_PARTIAL",
		"*", //"e_WILDCARD"
		"" };

void MsrpKeywords::Encode (Buffer& buffer) throw (EncodeError)
{
	Charstring c;

	const char * pStr = GetValueString();
	for(int i=0; strlen(msKeywordEnums[i]); i++)
	{
		if(!strcmp(msKeywordEnums[i], pStr))
		{
			c.SetValue (msKeywordStrings[i]);
			c.Encode(buffer);
			break;
		}
	}
	
}

void MsrpKeywords::Decode (Buffer& buffer) throw (DecodeError)
{
	//this can cause problems with ByteRange field and the header CRLF
	static Regex reg_kw_name ("^" SIPREG_SWS "([A-Za-z]+|\\*)" /*SIPREG_SWS*/);//TODO:

	reg_kw_name.AssertMatch (buffer, this);
	const char * pStr = reg_kw_name.GetMatchedString(1).c_str();

#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "MsrpKeywords::Decode:KeywordMatch: \""<< pStr << '"';
	logfile.close();
#endif	
	
	for(int i=0; strlen(msKeywordStrings[i]);i++)
	{
		if(!strcmp(msKeywordStrings[i], pStr))
		{
			//logfile << "->\""<< msKeywordEnums[i] << '"' << std::endl;
			SetValueString (msKeywordEnums[i]);
			buffer.SetPosition(buffer.GetPosition() + reg_kw_name.GetMatchedLength(1));
			break;
		}
	}
}


//TTCN-3 specific enumerated types
//HeaderName
//------------------------------------------------------------
//============================================================
const char* HeaderName::msHeaderEnumNames[] = { 
		//RFC 4975
			"TO_PATH_E", // "To-Path"
        	"FROM_PATH_E", // "From-Path"
            "MESSAGE_ID_E", // "Message-ID"
            "SUCCESS_REPORT_E", //"Success-Report"
            "FAILURE_REPORT_E", //"Failure-Report"
            "BYTE_RANGE_E", // "Byte-Range"
            "STATUS_E", // "Status"
		//MIME headers
            "CONTENT_ID_E",	// "Content-ID"
            "CONTENT_DESCRIPTION_E", // "Content-Description"
            "CONTENT_DISPOSITION_E", // "Content-Disposition"
            "MIME_EXT_FIELD_E", // RFC2045 Section 9. "Content-*"
			"CONTENT_TYPE_E", // "Content-Type"
        //RFC 4976
            "EXPIRES_E", //"Expires"
            "MIN_EXPIRES_E", // "Min-Expires" 
            "MAX_EXPIRES_E", // "Max-Expires"
            "USE_PATH_E",  // "Use-Path"
            "WWW_AUTHENTICATE_E", // "WWW-Authenticate" 
            "AUTHORIZATION_E", // "Authorization"
            "AUTHENTICATION_INFO_E", // "Authentication-Info"
            "EXT_HEADER_E", //any other header
			"" };

const char* HeaderName::msHeaderStringValues[] = { 
			KW_TO_PATH_HEADER_NAME, //"TO_PATH_E", // 
        	KW_FROM_PATH_HEADER_NAME, //"FROM_PATH_E", // 
            KW_MESSAGE_ID_HEADER_NAME, //"MESSAGE_ID_E", // 
            KW_SUCCESS_REPORT_HEADER_NAME, //"SUCCESS_REPORT_E", //
            KW_FAILURE_REPORT_HEADER_NAME, //"FAILURE_REPORT_E", //
            KW_BYTE_RANGE_HEADER_NAME, //"BYTE_RANGE_E", // 
            KW_STATUS_HEADER_NAME, //"STATUS_E", // 
            //MIME headers
            KW_Content_ID_HEADER_NAME, //"CONTENT_ID_E",	// "Content-ID"
            KW_Content_Description_HEADER_NAME, //"CONTENT_DESCRIPTION_E", // "Content-Description"
            KW_Content_Disposition_HEADER_NAME, //"CONTENT_DISPOSITION_E", // "Content-Disposition"
            "MIME_EXT_FIELD_E", // RFC2045 Section 9. "Content-*"
			KW_CONTENT_TYPE_HEADER_NAME, //"CONTENT_TYPE_E", // 
            //RFC 4976
            KW_Expires_HEADER_NAME, //"EXPIRES_E", //
            KW_Min_Expires_HEADER_NAME, //"MIN_EXPIRES_E", //  
            KW_Max_Expires_HEADER_NAME, //"MAX_EXPIRES_E", // 
            KW_Use_Path_HEADER_NAME, //"USE_PATH_E",  // 
            KW_WWW_Authenticate_HEADER_NAME, //"WWW_AUTHENTICATE_E", //  
            KW_Authorization_HEADER_NAME, //"AUTHORIZATION_E", // 
            KW_Authentication_Info_HEADER_NAME, //"AUTHENTICATION_INFO_E", // 
            "EXT_HEADER_E", //any other header
			"" };

void HeaderName::Encode (Buffer& buffer) throw (EncodeError)
{
	Charstring c;
	std::string tmp;
	const char* pStr = GetValueString();
	for(int i=0; strlen(msHeaderEnumNames[i]); i++)
	{
		if(!strcmp(msHeaderEnumNames[i], pStr))
		{
			//not encoded
			if(!strcmp("MIME_EXT_FIELD_E", pStr) || !strcmp("EXT_HEADER_E", pStr))
				break;
			tmp.assign(msHeaderStringValues[i]);
			tmp.append(":");
			c.SetValue (tmp.c_str());
			c.Encode(buffer);
			break;
		}
	}
	tmp.clear();
}

void HeaderName::Decode (Buffer& buffer) throw (DecodeError)
{
	static Regex reg_header_name ("^([" RFC822_ANY_HEADER_NAME_CHAR "]+)" MSRPREG_HEADER_COLON);
	int nIsKnown = 0;
	reg_header_name.AssertMatch (buffer, this);
	const char* pStr = reg_header_name.GetMatchedString (1).c_str();

#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "HeaderName::Decode: "<< pStr << std::endl;
	logfile.close();
#endif

	for(int i=0; strlen(msHeaderStringValues[i]); i++)
	{
		if(!strcmp(msHeaderStringValues[i], pStr))
		{
			nIsKnown = 1;
			SetValueString (msHeaderEnumNames[i]);
			//logfile << "HeaderName::Decode:MatchFound: "<< msHeaderEnumNames[i] << std::endl;
			buffer.SetPosition(buffer.GetPosition() + reg_header_name.GetMatchedLength());
			//logfile.close();
			return;
		}
	}
	if(!nIsKnown)
	{
		std::string headerName = reg_header_name.GetMatchedString(1);
		if(headerName.length() >= 8 && !headerName.substr(0,8).compare("Content-"))
			SetValueString ("MIME_EXT_FIELD_E");
		else
			SetValueString ("EXT_HEADER_E");
		buffer.SetPosition(buffer.GetPosition() + reg_header_name.GetMatchedLength());
	}
	
}

//TTCN-3 specific enumerated types
//MsrpMethod
//------------------------------------------------------------
//============================================================
const char* MsrpMethod::msMethodEnumNames[] = { 
			"SEND_E", // mSEND = %x53.45.4e.44 ; SEND in caps
            "REPORT_E", // mREPORT = %x52.45.50.4f.52.54; REPORT in caps
            //RFC 4976
            "AUTH_E", // mAUTH = %x41.55.54.48 ; AUTH in caps
            "UNKNOWN_METHOD_E",
			"" };

const char* MsrpMethod::msMethodStringValues[] = {
			KW_SEND_UTF8, //SEND_E, // mSEND = %x53.45.4e.44 ; SEND in caps
            KW_REPORT_UTF8, //REPORT_E, // mREPORT = %x52.45.50.4f.52.54; REPORT in caps
            //RFC 4976
            KW_AUTH_UTF8, //AUTH_E, // mAUTH = %x41.55.54.48 ; AUTH in caps
            "UNKNOWN_METHOD_E", 
			"" };

void MsrpMethod::Encode (Buffer& buffer) throw (EncodeError)
{
	Charstring c;
	const char* pStr = GetValueString();
	for(int i=0; strlen(msMethodEnumNames[i]); i++)
	{
		if(!strcmp(msMethodEnumNames[i], pStr))
		{
			c.SetValue (msMethodStringValues[i]);
			c.Encode(buffer);
			return;
		}
	}
}

void MsrpMethod::Decode (Buffer& buffer) throw (DecodeError)
{
	static Regex reg_header_name ("^([A-Za-z\\-]+)");

	reg_header_name.AssertMatch (buffer, this);
	int nIsKnown = 0;
	const char* pStr = reg_header_name.GetMatchedString().c_str();

#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "MsrpMethod::Decode: "<< pStr << std::endl;
	logfile.close();
#endif

	for(int i=0; strlen(msMethodStringValues[i]); i++)
	{
		if(!strcmp(msMethodStringValues[i], pStr))
		{
			nIsKnown = 1;
			SetValueString (msMethodEnumNames[i]);
			buffer.SetPosition(buffer.GetPosition() + reg_header_name.GetMatchedLength());
			break;
		}
	}
	if(!nIsKnown)
	{
		SetValueString ("UNKNOWN_METHOD_E");
		buffer.SetPosition(buffer.GetPosition() + reg_header_name.GetMatchedLength());
	}
}

//TTCN-3 specific enumerated types
//ContinuationFlag
//------------------------------------------------------------
//============================================================

const char* ContinuationFlag::msContinuationFlagNames[] = { 
			"e_endMessage", // "$"
        	"e_continueMessage", // "+"s
        	"e_cancelMessage", // "#"
			"" };
const char* ContinuationFlag::msContinuationFlagValues[] = { 
			"$",
        	"+",
        	"#",
			"" };

void ContinuationFlag::Encode (Buffer& buffer) throw (EncodeError)
{
	Charstring c;
	const char * sVal = GetValueString();
	for(int i=0; strlen(msContinuationFlagNames[i]); i++)
	{
		if(!strcmp(sVal, msContinuationFlagNames[i]))
		{
			c.SetValue(msContinuationFlagValues[i]);
			c.Encode(buffer);
			return;
		}
	}
}

void ContinuationFlag::Decode (Buffer& buffer) throw (DecodeError)
{
	static Regex reg_header_name ("^" CONTINUATION_FLAG);

	reg_header_name.AssertMatch (buffer, this);
	const char * sVal = reg_header_name.GetMatchedString().c_str();

#ifdef DEBUG_LOG
	std::ofstream logfile("C:\\Temp\\LibMsrp.log", ios::app);
	logfile << "ContinuationFlag::Decode: "<< sVal << std::endl;
	logfile.close();
#endif

	for(int i=0; strlen(msContinuationFlagValues[i]); i++)
	{
		if(!strcmp(sVal, msContinuationFlagValues[i]))
		{
			SetValueString(msContinuationFlagNames[i]);
			buffer.SetPosition(buffer.GetPosition() + reg_header_name.GetMatchedLength());
			return;
		}
	}
}

}} // namespaces
