/*
* Copyright (C) 2012 Doubango Telecom <http://www.doubango.org>
* License: BSD
* This file is part of Open Source sipML5 solution <http://www.sipml5.org>
*/
function prev_not_comma(o_ragel_state, i_p){
	return (o_ragel_state.i_pe <= i_p) || (o_ragel_state.o_data[i_p - 1] != ',');
}

%%{
	machine tsip_machine_parser_message;

	#// Tag the buffer (start point)
	action tag {
		o_ragel_state.i_tag_start = p;
	}

	#// SIP method
	action parse_method {
	    o_ragel_state.i_tag_end = p;
		if(o_msg.e_type == tsip_message_type_e.UNKNOWN){
			o_msg.e_type = tsip_message_type_e.REQUEST;
			if(!o_msg.line.request.s_method){
			    o_msg.line.request.s_method = tsk_ragel_parser_get_string(o_ragel_state.s_data, p, o_ragel_state.i_tag_start);
				o_msg.line.request.e_type = tsip_message.prototype.GetRequestType(o_msg.line.request.s_method);
			}
		}
		else{
			o_ragel_state.cs = tsip_machine_parser_message_error;
		}
	}

	#// Request URI parsing
	action parse_requesturi {
	    o_ragel_state.i_tag_end = p;
		if(!o_msg.line.request.o_uri){
		    var s_uri = tsk_ragel_parser_get_string(o_ragel_state.s_data, p, o_ragel_state.i_tag_start);
			o_msg.line.request.o_uri = tsip_uri.prototype.Parse(s_uri);
		}
	}

	#// Sip Version
	action parse_sipversion {
	    o_ragel_state.i_tag_end = p;
		o_msg.s_version = tsk_ragel_parser_get_string(o_ragel_state.s_data, p, o_ragel_state.i_tag_start);
	}

	#// Status Code
	action parse_status_code {
	    o_ragel_state.i_tag_end = p;	
		if(o_msg.e_type == tsip_message_type_e.UNKNOWN){
			o_msg.e_type = tsip_message_type_e.RESPONSE;
			var s_status_code = tsk_ragel_parser_get_string(o_ragel_state.s_data, p, o_ragel_state.i_tag_start);
			o_msg.line.response.i_status_code = parseInt(s_status_code);
		}
		else{
			o_ragel_state.i_cs = tsip_machine_parser_message_error;
		}
	}

	#// Reason Phrase
	action parse_reason_phrase{
	    o_ragel_state.i_tag_end = p;
		if(!o_msg.line.response.s_reason_phrase){
			o_msg.line.response.s_reason_phrase = tsk_ragel_parser_get_string(o_ragel_state.s_data, p, o_ragel_state.i_tag_start);
		}
	}

	#// Parse sip header
	action parse_header{
	    o_ragel_state.i_tag_end = p;
		tsip_header_parse(o_ragel_state, o_msg);
	}

	#// End-Of-Headers
	action eoh{
		o_ragel_state.i_cs = cs;
		o_ragel_state.i_p = p;
		o_ragel_state.i_pe = pe;
		o_ragel_state.i_eof = eof;

		tsip_message_parser_eoh(o_ragel_state, o_msg, b_extract_content);

		cs = o_ragel_state.i_cs;
		p = o_ragel_state.i_p;
		pe = o_ragel_state.i_pe;
		eof = o_ragel_state.i_eof;
	}

	# Includes
	include tsip_machine_utils "./tsip_machine_utils.jrl";
	include tsip_machine_message "./tsip_machine_message.jrl";
	
	# Entry point
	main := SIP_message;
}%%

%%write data;

function tsip_message_parser_init(o_ragel_state){
	var cs = 0;

	// Ragel machine initialization.
	%% write init;
	
	o_ragel_state.i_cs = cs;
}

function tsip_message_parser_execute(o_ragel_state, o_msg, b_extract_content){
    var cs = o_ragel_state.i_cs;
	var p = o_ragel_state.i_p;
	var pe = o_ragel_state.i_pe;
	var eof = o_ragel_state.i_eof;
	var data = o_ragel_state.o_data;

	%% write exec;

    o_ragel_state.i_cs = cs;
	o_ragel_state.i_p = p;
	o_ragel_state.i_pe = pe;
	o_ragel_state.i_eof = eof;
}

function tsip_message_parser_eoh(o_ragel_state, o_msg, b_extract_content){
    if(o_msg && b_extract_content){
        var i_clen = o_msg.get_content_length();
        if((o_ragel_state.i_p + i_clen) < o_ragel_state.i_pe && !o_msg.o_content){
            var i_start = o_ragel_state.i_p + 1;
            var i_end = (i_start + i_clen);
			o_msg.o_content = new Array((i_end - i_start));
            for(var i = i_start, j = 0; i < i_end; ++i, ++j){
                o_msg.o_content[j] = o_ragel_state.o_data[i];
            }
            o_ragel_state.i_p += i_clen;
        }
        else{
            o_ragel_state.i_p = (o_ragel_state.i_pe - 1);
        }
    }
}

tsip_message.prototype.Parse = function(o_ragel_state, b_extract_content){
    var o_msg = null;
    if(!o_ragel_state || !o_ragel_state.o_data){
        return null;
    }
    
    o_msg = new tsip_message(tsip_message_type_e.UNKNOWN);
    
    // ragel init
    tsip_message_parser_init(o_ragel_state);
    
    // state machine execution
    tsip_message_parser_execute(o_ragel_state, o_msg, b_extract_content);
    
    if( o_ragel_state.i_cs < %%{ write first_final; }%% ){
		tsk_utils_log_error("Failed to parse message: " + o_ragel_state.s_data);
		return null;
	}
    
    return o_msg;
}