/*
 * OpenMRCP - Open Source Media Resource Control Protocol Stack
 * Copyright (C) 2007, Cepstral LLC
 *
 * Version: MPL 1.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * Author(s):
 * Arsen Chaloyan <achaloyan@yahoo.com>
 *
 * Contributor(s):
 *
 */

#include "mrcp_recognizer.h"
#include "apt_string_table.h"

/* string table of mrcp recognizer methods (mrcp_recognizer_method_id) */
static const apt_string_table_item_t v1_recognizer_method_string_table[] = {
	{"SET-PARAMS",               10,10},
	{"GET-PARAMS",               10,10},
	{"DEFINE-GRAMMAR",           14,0},
	{"RECOGNIZE",                 9,7},
	{"GET-RESULT",               10,4},
	{"RECOGNITION-START-TIMERS", 24,7},
	{"STOP",                      4,1}
};

/* string table of mrcpv2 recognizer methods (mrcp_recognizer_method_id) */
static const apt_string_table_item_t v2_recognizer_method_string_table[] = {
	{"SET-PARAMS",               10,10},
	{"GET-PARAMS",               10,10},
	{"DEFINE-GRAMMAR",           14,0},
	{"RECOGNIZE",                 9,7},
	{"GET-RESULT",               10,4},
	{"START-INPUT-TIMERS",       18,2},
	{"STOP",                      4,2}
};

/* string table of mrcp recognizer events (mrcp_recognizer_event_id) */
static const apt_string_table_item_t v1_recognizer_event_string_table[] = {
	{"START-OF-SPEECH",          15,0},
	{"RECOGNITION-COMPLETE",     20,0}
};

/* string table of mrcpv2 recognizer events (mrcp_recognizer_event_id) */
static const apt_string_table_item_t v2_recognizer_event_string_table[] = {
	{"START-OF-INPUT",           14,0},
	{"RECOGNITION-COMPLETE",     20,0}
};

/* string table of mrcp recognizer headers (mrcp_recognizer_header_id) */
static const apt_string_table_item_t v1_recognizer_header_string_table[] = {
	{"Confidence-Threshold",       20,7},
	{"Sensitivity-Level",          17,3},
	{"Speed-Vs-Accuracy",          17,4},
	{"N-Best-List-Length",         18,1},
	{"No-Input-Timeout",           16,2},
	{"Recognition-Timeout",        19,16},
	{"Waveform-Url",               12,0},
	{"Input-Waveform-Url",         18,0},
	{"Completion-Cause",           16,3},
	{"Recognizer-Context-Block",   24,12},
	{"Recognizer-Start-Timers",    23,11},
	{"Vendor-Specific-Parameters", 26,3},
	{"Speech-Complete-Timeout",    23,7},
	{"Speech-Incomplete-Timeout",  25,8},
	{"Dtmf-Interdigit-Timeout",    23,5},
	{"Dtmf-Term-Timeout",          17,10},
	{"Dtmf-Term-Char",             14,14},
	{"Fetch-Timeout",              13,4},
	{"Failed-Uri",                 10,10},
	{"Failed-Uri-Cause",           16,16},
	{"Save-Waveform",              13,5},
	{"New-Audio-Channel",          17,2},
	{"Speech-Language",            15,8},
	{"Ver-Buffer-Utterance",       20,4},
	{"Recognition-Mode",           16,12},
	{"Cancel-If-Queue",            15,5},
	{"Hotword-Max-Duration",       20,9},
	{"Hotword-Min-Duration",       20,20},
	{"DTMF-Buffer-Time",           16,1},
	{"Clear-DTMF-Buffer",          17,1},
	{"Early-No-Match",             14,0}
};

/* string table of mrcpv2 recognizer headers (mrcp_recognizer_header_id) */
static const apt_string_table_item_t v2_recognizer_header_string_table[] = {
	{"Confidence-Threshold",       20,8},
	{"Sensitivity-Level",          17,3},
	{"Speed-Vs-Accuracy",          17,4},
	{"N-Best-List-Length",         18,1},
	{"No-Input-Timeout",           16,2},
	{"Recognition-Timeout",        19,16},
	{"Waveform-Uri",               12,0},
	{"Input-Waveform-Uri",         18,0},
	{"Completion-Cause",           16,3},
	{"Recognizer-Context-Block",   24,7},
	{"Start-Input-Timers",         18,2},
	{"Vendor-Specific-Parameters", 26,3},
	{"Speech-Complete-Timeout",    23,7},
	{"Speech-Incomplete-Timeout",  25,8},
	{"Dtmf-Interdigit-Timeout",    23,5},
	{"Dtmf-Term-Timeout",          17,10},
	{"Dtmf-Term-Char",             14,14},
	{"Fetch-Timeout",              13,4},
	{"Failed-Uri",                 10,10},
	{"Failed-Uri-Cause",           16,16},
	{"Save-Waveform",              13,5},
	{"New-Audio-Channel",          17,2},
	{"Speech-Language",            15,8},
	{"Ver-Buffer-Utterance",       20,4},
	{"Recognition-Mode",           16,12},
	{"Cancel-If-Queue",            15,5},
	{"Hotword-Max-Duration",       20,9},
	{"Hotword-Min-Duration",       20,20},
	{"DTMF-Buffer-Time",           16,1},
	{"Clear-DTMF-Buffer",          17,1},
	{"Early-No-Match",             14,0}
};

/* string table of mrcp recognizer completion-cause fields (mrcp_recognizer_completion_cause_t) */
static const apt_string_table_item_t completion_cause_string_table[] = {
	{"success",                     7,7},
	{"no-match",                    8,4},
	{"no-input-timeout",           16,3},
	{"hotword-maxtime",            15,0},
	{"grammar-load-failure",       20,8},
	{"grammar-compilation-failure",27,8},
	{"recognizer-error",           16,0},
	{"speech-too-early",           16,1},
	{"success-maxtime",            15,15},
	{"uri-failure",                11,0},
	{"language-unsupported",       20,0},
	{"cancelled",                   9,0},
	{"semantics-failure",          17,2}
};


/* generates mrcp recognizer completion-cause */
static size_t mrcp_completion_cause_generate(mrcp_recognizer_completion_cause_t completion_cause, char *field)
{
	int length = 0;
	const char *name = apt_string_table_get(completion_cause_string_table,RECOGNIZER_COMPLETION_CAUSE_COUNT,completion_cause);
	if(!name) {
		return 0;
	}
	length = sprintf(field,"%03"APR_SIZE_T_FMT" %s", completion_cause,name);
	if(length < 0) {
		length = 0;
	}
	return length;
}


/* initializes recognizer header */
void mrcp_recognizer_header_init(mrcp_recognizer_header_t *recognizer_header)
{
	recognizer_header->confidence_threshold = 0;
	recognizer_header->sensitivity_level = 0;
	recognizer_header->speed_vs_accuracy = 0;
	recognizer_header->n_best_list_length = 0;
	recognizer_header->no_input_timeout = 0;
	recognizer_header->recognition_timeout = 0;
	recognizer_header->waveform_uri = NULL;
	recognizer_header->input_waveform_uri = NULL;
	recognizer_header->completion_cause = RECOGNIZER_COMPLETION_CAUSE_COUNT;
	recognizer_header->recognizer_context_block = NULL;
	recognizer_header->start_input_timers = FALSE;
	recognizer_header->vendor_specific = NULL;
	recognizer_header->speech_complete_timeout = 0;
	recognizer_header->speech_incomplete_timeout = 0;
	recognizer_header->dtmf_interdigit_timeout = 0;
	recognizer_header->dtmf_term_timeout = 0;
	recognizer_header->dtmf_term_char = 0;
	recognizer_header->fetch_timeout = 0;
	recognizer_header->failed_uri = NULL;
	recognizer_header->failed_uri_cause = NULL;
	recognizer_header->save_waveform = FALSE;
	recognizer_header->new_audio_channel = FALSE;
	recognizer_header->speech_language = NULL;
	recognizer_header->ver_buffer_utterance = FALSE;
	recognizer_header->recognition_mode = NULL;
	recognizer_header->cancel_if_queue = FALSE;
	recognizer_header->hotword_max_duration = 0;
	recognizer_header->hotword_min_duration = 0;
	recognizer_header->dtmf_buffer_time = 0;
	recognizer_header->clear_dtmf_buffer = FALSE;
	recognizer_header->early_no_match = FALSE;
}

/* destroys recognizer header */
void mrcp_recognizer_header_destroy(mrcp_recognizer_header_t *recognizer_header)
{
	/* nothing to do as data is allocated from the memory pool and
	will be destroyed with memory pool */
	mrcp_recognizer_header_init(recognizer_header);
}

/* allocates mrcp recognizer header */
static void* mrcp_recognizer_header_accessor_allocate(mrcp_header_base_t *header, apr_pool_t *pool)
{
	mrcp_recognizer_header_t *recognizer_header = apr_palloc(pool,sizeof(mrcp_recognizer_header_t));
	mrcp_recognizer_header_init(recognizer_header);
	header->data = recognizer_header;
	return header->data;
}

/* destroys mrcp recognizer header */
static void mrcp_recognizer_header_accessor_destroy(mrcp_header_base_t *header)
{
	if(header->data) {
		mrcp_recognizer_header_destroy(header->data);
		header->data = NULL;
	}
}

/* parses mrcp recognizer header */
static mrcp_status_t mrcp_recognizer_header_parse(mrcp_header_base_t *header, size_t id, char *value, apr_pool_t *pool)
{
	mrcp_status_t status;
	mrcp_recognizer_header_t *recognizer_header = header->data;
	if(!recognizer_header) {
		return MRCP_STATUS_FAILURE;
	}
	
	status = MRCP_STATUS_SUCCESS;
	switch(id)
	{
		case RECOGNIZER_HEADER_CONFIDENCE_THRESHOLD:
			recognizer_header->confidence_threshold = apt_float_value_parse(value);
			break;
		case RECOGNIZER_HEADER_SENSITIVITY_LEVEL:
			recognizer_header->sensitivity_level = apt_size_value_parse(value);
			break;
		case RECOGNIZER_HEADER_SPEED_VS_ACCURACY:
			recognizer_header->speed_vs_accuracy = apt_size_value_parse(value);
			break;
		case RECOGNIZER_HEADER_N_BEST_LIST_LENGTH:
			recognizer_header->n_best_list_length = apt_size_value_parse(value);
			break;
		case RECOGNIZER_HEADER_NO_INPUT_TIMEOUT:
			recognizer_header->no_input_timeout = apt_size_value_parse(value);
			break;
		case RECOGNIZER_HEADER_RECOGNITION_TIMEOUT:
			recognizer_header->recognition_timeout = apt_size_value_parse(value);
			break;
		case RECOGNIZER_HEADER_WAVEFORM_URI:
			recognizer_header->waveform_uri = apr_pstrdup(pool,value);
			break;
		case RECOGNIZER_HEADER_INPUT_WAVEFORM_URI:
			recognizer_header->input_waveform_uri = apr_pstrdup(pool,value);
			break;
		case RECOGNIZER_HEADER_COMPLETION_CAUSE:
			recognizer_header->completion_cause = apt_size_value_parse(value);
			break;
		case RECOGNIZER_HEADER_RECOGNIZER_CONTEXT_BLOCK:
			recognizer_header->recognizer_context_block = apr_pstrdup(pool,value);
			break;
		case RECOGNIZER_HEADER_START_INPUT_TIMERS:
			apt_boolean_value_parse(value,&recognizer_header->start_input_timers);
			break;
		case RECOGNIZER_HEADER_VENDOR_SPECIFIC:
			recognizer_header->vendor_specific = apr_pstrdup(pool,value);
			break;
		case RECOGNIZER_HEADER_SPEECH_COMPLETE_TIMEOUT:
			recognizer_header->speech_complete_timeout = apt_size_value_parse(value);
			break;
		case RECOGNIZER_HEADER_SPEECH_INCOMPLETE_TIMEOUT:
			recognizer_header->speech_incomplete_timeout = apt_size_value_parse(value);
			break;
		case RECOGNIZER_HEADER_DTMF_INTERDIGIT_TIMEOUT:
			recognizer_header->dtmf_interdigit_timeout = apt_size_value_parse(value);
			break;
		case RECOGNIZER_HEADER_DTMF_TERM_TIMEOUT:
			recognizer_header->dtmf_term_timeout = apt_size_value_parse(value);
			break;
		case RECOGNIZER_HEADER_DTMF_TERM_CHAR:
			if(value) {
				recognizer_header->dtmf_term_char = *value;
			}
			break;
		case RECOGNIZER_HEADER_FETCH_TIMEOUT:
			recognizer_header->fetch_timeout = apt_size_value_parse(value);
			break;
		case RECOGNIZER_HEADER_FAILED_URI:
			recognizer_header->failed_uri = apr_pstrdup(pool,value);
			break;
		case RECOGNIZER_HEADER_FAILED_URI_CAUSE:
			recognizer_header->failed_uri_cause = apr_pstrdup(pool,value);
			break;
		case RECOGNIZER_HEADER_SAVE_WAVEFORM:
			apt_boolean_value_parse(value,&recognizer_header->save_waveform);
			break;
		case RECOGNIZER_HEADER_NEW_AUDIO_CHANNEL:
			apt_boolean_value_parse(value,&recognizer_header->new_audio_channel);
			break;
		case RECOGNIZER_HEADER_SPEECH_LANGUAGE:
			recognizer_header->speech_language = apr_pstrdup(pool,value);
			break;
		case RECOGNIZER_HEADER_VER_BUFFER_UTTERANCE:
			apt_boolean_value_parse(value,&recognizer_header->ver_buffer_utterance);
			break;
		case RECOGNIZER_HEADER_RECOGNITION_MODE:
			recognizer_header->recognition_mode = apr_pstrdup(pool,value);
			break;
		case RECOGNIZER_HEADER_CANCEL_IF_QUEUE:
			apt_boolean_value_parse(value,&recognizer_header->cancel_if_queue);
			break;
		case RECOGNIZER_HEADER_HOTWORD_MAX_DURATION:
			recognizer_header->hotword_max_duration = apt_size_value_parse(value);
			break;
		case RECOGNIZER_HEADER_HOTWORD_MIN_DURATION:
			recognizer_header->hotword_min_duration = apt_size_value_parse(value);
			break;
		case RECOGNIZER_HEADER_DTMF_BUFFER_TIME:
			recognizer_header->dtmf_buffer_time = apt_size_value_parse(value);
			break;
		case RECOGNIZER_HEADER_CLEAR_DTMF_BUFFER:
			apt_boolean_value_parse(value,&recognizer_header->clear_dtmf_buffer);
			break;
		case RECOGNIZER_HEADER_EARLY_NO_MATCH:
			apt_boolean_value_parse(value,&recognizer_header->early_no_match);
			break;
		default:
			status = MRCP_STATUS_FAILURE;
	}
	return status;
}

/* parses mrcpv1 recognizer header */
static mrcp_status_t mrcp_v1_recognizer_header_parse(mrcp_header_base_t *header, size_t id, char *value, apr_pool_t *pool)
{
	if(id == RECOGNIZER_HEADER_CONFIDENCE_THRESHOLD) {
		mrcp_recognizer_header_t *recognizer_header = header->data;
		if(!recognizer_header) {
			return MRCP_STATUS_FAILURE;
		}
		recognizer_header->confidence_threshold = (float)apt_size_value_parse(value);
		recognizer_header->confidence_threshold /= 100;
		return MRCP_STATUS_SUCCESS;
	}
	return mrcp_recognizer_header_parse(header,id,value,pool);
}

/* generates mrcp recognizer header */
static size_t mrcp_recognizer_header_generate(mrcp_header_base_t *header, size_t id, char *value)
{
	size_t length = 0;
	mrcp_recognizer_header_t *recognizer_header = header->data;
	if(!recognizer_header) {
		return MRCP_STATUS_FAILURE;
	}

	switch(id)
	{
		case RECOGNIZER_HEADER_CONFIDENCE_THRESHOLD:
			length = apt_float_value_generate(recognizer_header->confidence_threshold,value);
			break;
		case RECOGNIZER_HEADER_SENSITIVITY_LEVEL:
			length = apt_size_value_generate(recognizer_header->sensitivity_level,value);
			break;
		case RECOGNIZER_HEADER_SPEED_VS_ACCURACY:
			length = apt_size_value_generate(recognizer_header->speed_vs_accuracy,value);
			break;
		case RECOGNIZER_HEADER_N_BEST_LIST_LENGTH:
			length = apt_size_value_generate(recognizer_header->n_best_list_length,value);
			break;
		case RECOGNIZER_HEADER_NO_INPUT_TIMEOUT:
			length = apt_size_value_generate(recognizer_header->no_input_timeout,value);
			break;
		case RECOGNIZER_HEADER_RECOGNITION_TIMEOUT:
			length = apt_size_value_generate(recognizer_header->recognition_timeout,value);
			break;
		case RECOGNIZER_HEADER_WAVEFORM_URI:
			if(recognizer_header->waveform_uri) {
				length = apt_string_value_generate(recognizer_header->waveform_uri,value);
			}
			break;
		case RECOGNIZER_HEADER_INPUT_WAVEFORM_URI:
			if(recognizer_header->input_waveform_uri) {
				length = apt_string_value_generate(recognizer_header->input_waveform_uri,value);
			}
			break;
		case RECOGNIZER_HEADER_COMPLETION_CAUSE:
			if(recognizer_header->completion_cause != RECOGNIZER_COMPLETION_CAUSE_COUNT) {
				length = mrcp_completion_cause_generate(recognizer_header->completion_cause,value);
			}
			break;
		case RECOGNIZER_HEADER_RECOGNIZER_CONTEXT_BLOCK:
			if(recognizer_header->recognizer_context_block) {
				length = apt_string_value_generate(recognizer_header->recognizer_context_block,value);
			}
			break;
		case RECOGNIZER_HEADER_START_INPUT_TIMERS:
			length = apt_boolean_value_generate(recognizer_header->start_input_timers,value);
			break;
		case RECOGNIZER_HEADER_VENDOR_SPECIFIC:
			if(recognizer_header->vendor_specific) {
				length = apt_string_value_generate(recognizer_header->vendor_specific,value);
			}
			break;
		case RECOGNIZER_HEADER_SPEECH_COMPLETE_TIMEOUT:
			length = apt_size_value_generate(recognizer_header->speech_complete_timeout,value);
			break;
		case RECOGNIZER_HEADER_SPEECH_INCOMPLETE_TIMEOUT:
			length = apt_size_value_generate(recognizer_header->speech_incomplete_timeout,value);
			break;
		case RECOGNIZER_HEADER_DTMF_INTERDIGIT_TIMEOUT:
			length = apt_size_value_generate(recognizer_header->dtmf_interdigit_timeout,value);
			break;
		case RECOGNIZER_HEADER_DTMF_TERM_TIMEOUT:
			length = apt_size_value_generate(recognizer_header->dtmf_term_timeout,value);
			break;
		case RECOGNIZER_HEADER_DTMF_TERM_CHAR:
			if(recognizer_header->dtmf_term_char) {
				*value = recognizer_header->dtmf_term_char;
				length++;
			}
			break;
		case RECOGNIZER_HEADER_FETCH_TIMEOUT:
			length = apt_size_value_generate(recognizer_header->fetch_timeout,value);
			break;
		case RECOGNIZER_HEADER_FAILED_URI:
			if(recognizer_header->failed_uri) {
				length = apt_string_value_generate(recognizer_header->failed_uri,value);
			}
			break;
		case RECOGNIZER_HEADER_FAILED_URI_CAUSE:
			if(recognizer_header->failed_uri_cause) {
				length = apt_string_value_generate(recognizer_header->failed_uri_cause,value);
			}
			break;
		case RECOGNIZER_HEADER_SAVE_WAVEFORM:
			length = apt_boolean_value_generate(recognizer_header->save_waveform,value);
			break;
		case RECOGNIZER_HEADER_NEW_AUDIO_CHANNEL:
			length = apt_boolean_value_generate(recognizer_header->new_audio_channel,value);
			break;
		case RECOGNIZER_HEADER_SPEECH_LANGUAGE:
			if(recognizer_header->speech_language) {
				length = apt_string_value_generate(recognizer_header->speech_language,value);
			}
			break;
		case RECOGNIZER_HEADER_VER_BUFFER_UTTERANCE:
			length = apt_boolean_value_generate(recognizer_header->ver_buffer_utterance,value);
			break;
		case RECOGNIZER_HEADER_RECOGNITION_MODE:
			if(recognizer_header->recognition_mode) {
				length = apt_string_value_generate(recognizer_header->recognition_mode,value);
			}
			break;
		case RECOGNIZER_HEADER_CANCEL_IF_QUEUE:
			length = apt_boolean_value_generate(recognizer_header->cancel_if_queue,value);
			break;
		case RECOGNIZER_HEADER_HOTWORD_MAX_DURATION:
			length = apt_size_value_generate(recognizer_header->hotword_max_duration,value);
			break;
		case RECOGNIZER_HEADER_HOTWORD_MIN_DURATION:
			length = apt_size_value_generate(recognizer_header->hotword_min_duration,value);
			break;
		case RECOGNIZER_HEADER_DTMF_BUFFER_TIME:
			length = apt_size_value_generate(recognizer_header->dtmf_buffer_time,value);
			break;
		case RECOGNIZER_HEADER_CLEAR_DTMF_BUFFER:
			length = apt_boolean_value_generate(recognizer_header->clear_dtmf_buffer,value);
			break;
		case RECOGNIZER_HEADER_EARLY_NO_MATCH:
			length = apt_boolean_value_generate(recognizer_header->early_no_match,value);
			break;
		default:
			length = 0;
	}
	return length;
}

/* generates mrcpv1 recognizer header */
static size_t mrcp_v1_recognizer_header_generate(mrcp_header_base_t *header, size_t id, char *value)
{
	if(id == RECOGNIZER_HEADER_CONFIDENCE_THRESHOLD) {
		mrcp_recognizer_header_t *recognizer_header = header->data;
		if(!recognizer_header) {
			return MRCP_STATUS_FAILURE;
		}
		return apt_size_value_generate((size_t)((recognizer_header->confidence_threshold+0.001f)*100),value);
	}
	return mrcp_recognizer_header_generate(header,id,value);
}

/* duplicates mrcp recognizer header */
static mrcp_status_t mrcp_recognizer_header_duplicate(mrcp_header_base_t *header, const mrcp_header_base_t *src, size_t id, apr_pool_t *pool)
{
	mrcp_status_t status;
	mrcp_recognizer_header_t *recognizer_header = header->data;
	const mrcp_recognizer_header_t *src_recognizer_header = src->data;
	if(!recognizer_header || !src_recognizer_header) {
		return MRCP_STATUS_FAILURE;
	}
	
	status = MRCP_STATUS_SUCCESS;
	switch(id)
	{
		case RECOGNIZER_HEADER_CONFIDENCE_THRESHOLD:
			recognizer_header->confidence_threshold = src_recognizer_header->confidence_threshold;
			break;
		case RECOGNIZER_HEADER_SENSITIVITY_LEVEL:
			recognizer_header->sensitivity_level = src_recognizer_header->sensitivity_level;
			break;
		case RECOGNIZER_HEADER_SPEED_VS_ACCURACY:
			recognizer_header->speed_vs_accuracy = src_recognizer_header->speed_vs_accuracy;
			break;
		case RECOGNIZER_HEADER_N_BEST_LIST_LENGTH:
			recognizer_header->n_best_list_length = src_recognizer_header->n_best_list_length;
			break;
		case RECOGNIZER_HEADER_NO_INPUT_TIMEOUT:
			recognizer_header->no_input_timeout = src_recognizer_header->no_input_timeout;
			break;
		case RECOGNIZER_HEADER_RECOGNITION_TIMEOUT:
			recognizer_header->recognition_timeout = src_recognizer_header->recognition_timeout;
			break;
		case RECOGNIZER_HEADER_WAVEFORM_URI:
			recognizer_header->waveform_uri = apr_pstrdup(pool,src_recognizer_header->waveform_uri);
			break;
		case RECOGNIZER_HEADER_INPUT_WAVEFORM_URI:
			recognizer_header->input_waveform_uri = apr_pstrdup(pool,src_recognizer_header->input_waveform_uri);
			break;
		case RECOGNIZER_HEADER_COMPLETION_CAUSE:
			recognizer_header->completion_cause = src_recognizer_header->completion_cause;
			break;
		case RECOGNIZER_HEADER_RECOGNIZER_CONTEXT_BLOCK:
			recognizer_header->recognizer_context_block = apr_pstrdup(pool,src_recognizer_header->recognizer_context_block);
			break;
		case RECOGNIZER_HEADER_START_INPUT_TIMERS:
			recognizer_header->start_input_timers = src_recognizer_header->start_input_timers;
			break;
		case RECOGNIZER_HEADER_VENDOR_SPECIFIC:
			recognizer_header->vendor_specific = apr_pstrdup(pool,src_recognizer_header->vendor_specific);
			break;
		case RECOGNIZER_HEADER_SPEECH_COMPLETE_TIMEOUT:
			recognizer_header->speech_complete_timeout = src_recognizer_header->speech_complete_timeout;
			break;
		case RECOGNIZER_HEADER_SPEECH_INCOMPLETE_TIMEOUT:
			recognizer_header->speech_incomplete_timeout = src_recognizer_header->speech_incomplete_timeout;
			break;
		case RECOGNIZER_HEADER_DTMF_INTERDIGIT_TIMEOUT:
			recognizer_header->dtmf_interdigit_timeout = src_recognizer_header->dtmf_interdigit_timeout;
			break;
		case RECOGNIZER_HEADER_DTMF_TERM_TIMEOUT:
			recognizer_header->dtmf_term_timeout = src_recognizer_header->dtmf_term_timeout;
			break;
		case RECOGNIZER_HEADER_DTMF_TERM_CHAR:
			recognizer_header->dtmf_term_char = src_recognizer_header->dtmf_term_char;
			break;
		case RECOGNIZER_HEADER_FETCH_TIMEOUT:
			recognizer_header->fetch_timeout = src_recognizer_header->fetch_timeout;
			break;
		case RECOGNIZER_HEADER_FAILED_URI:
			recognizer_header->failed_uri = apr_pstrdup(pool,src_recognizer_header->failed_uri);
			break;
		case RECOGNIZER_HEADER_FAILED_URI_CAUSE:
			recognizer_header->failed_uri_cause = apr_pstrdup(pool,src_recognizer_header->failed_uri_cause);
			break;
		case RECOGNIZER_HEADER_SAVE_WAVEFORM:
			recognizer_header->save_waveform = src_recognizer_header->save_waveform;
			break;
		case RECOGNIZER_HEADER_NEW_AUDIO_CHANNEL:
			recognizer_header->new_audio_channel = src_recognizer_header->new_audio_channel;
			break;
		case RECOGNIZER_HEADER_SPEECH_LANGUAGE:
			recognizer_header->speech_language = apr_pstrdup(pool,src_recognizer_header->speech_language);
			break;
		case RECOGNIZER_HEADER_VER_BUFFER_UTTERANCE:
			recognizer_header->ver_buffer_utterance = src_recognizer_header->ver_buffer_utterance;
			break;
		case RECOGNIZER_HEADER_RECOGNITION_MODE:
			recognizer_header->recognition_mode = apr_pstrdup(pool,src_recognizer_header->recognition_mode);
			break;
		case RECOGNIZER_HEADER_CANCEL_IF_QUEUE:
			recognizer_header->cancel_if_queue = src_recognizer_header->cancel_if_queue;
			break;
		case RECOGNIZER_HEADER_HOTWORD_MAX_DURATION:
			recognizer_header->hotword_max_duration = src_recognizer_header->hotword_max_duration;
			break;
		case RECOGNIZER_HEADER_HOTWORD_MIN_DURATION:
			recognizer_header->hotword_min_duration = src_recognizer_header->hotword_min_duration;
			break;
		case RECOGNIZER_HEADER_DTMF_BUFFER_TIME:
			recognizer_header->dtmf_buffer_time = src_recognizer_header->dtmf_buffer_time;
			break;
		case RECOGNIZER_HEADER_CLEAR_DTMF_BUFFER:
			recognizer_header->clear_dtmf_buffer = src_recognizer_header->clear_dtmf_buffer;
			break;
		case RECOGNIZER_HEADER_EARLY_NO_MATCH:
			recognizer_header->early_no_match = src_recognizer_header->early_no_match;
			break;
		default:
			status = MRCP_STATUS_FAILURE;
	}
	return status;
}

static APR_INLINE const apt_string_table_item_t* recognizer_header_string_table_get(mrcp_version_t version)
{
	if(version == MRCP_VERSION_1) {
		return v1_recognizer_header_string_table;
	}
	return v2_recognizer_header_string_table;
}

static APR_INLINE const apt_string_table_item_t* recognizer_method_string_table_get(mrcp_version_t version)
{
	if(version == MRCP_VERSION_1) {
		return v1_recognizer_method_string_table;
	}
	return v2_recognizer_method_string_table;
}

static APR_INLINE const apt_string_table_item_t* recognizer_event_string_table_get(mrcp_version_t version)
{
	if(version == MRCP_VERSION_1) {
		return v1_recognizer_event_string_table;
	}
	return v2_recognizer_event_string_table;
}

static APR_INLINE void mrcp_header_accessor_set(mrcp_header_accessor_t *header_accessor, mrcp_version_t version)
{
	header_accessor->allocator = mrcp_recognizer_header_accessor_allocate;
	header_accessor->destructor = mrcp_recognizer_header_accessor_destroy;
	header_accessor->field_parser = mrcp_recognizer_header_parse;
	header_accessor->field_generator = mrcp_recognizer_header_generate;
	header_accessor->field_duplicator = mrcp_recognizer_header_duplicate;
	header_accessor->field_table = recognizer_header_string_table_get(version);
	header_accessor->field_count = RECOGNIZER_HEADER_COUNT;

	if(version == MRCP_VERSION_1) {
		header_accessor->field_parser = mrcp_v1_recognizer_header_parse;
		header_accessor->field_generator = mrcp_v1_recognizer_header_generate;
	}
}


/* initializes mrcp recognizer resource */
mrcp_status_t mrcp_recognizer_init(mrcp_resource_t *resource, mrcp_version_t version)
{
	resource->method_table = recognizer_method_string_table_get(version);
	resource->method_count = RECOGNIZER_METHOD_COUNT;

	resource->event_table = recognizer_event_string_table_get(version);
	resource->event_count = RECOGNIZER_EVENT_COUNT;

	resource->audio_stream_type = MRCP_AUDIO_STREAM_SINK;

	mrcp_header_accessor_set(&resource->header_accessor,version);
	return MRCP_STATUS_SUCCESS;
}
