/*
 * 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):
 *
 */

#ifndef __MRCP_MESSAGE_H__
#define __MRCP_MESSAGE_H__

/**
 * @file mrcp_message.h
 * @brief MRCP Message Definition
 */ 

#include "mrcp_types.h"
#include "mrcp_header_base.h"

MRCP_BEGIN_EXTERN_C

/** Request-states used in MRCP response message */
typedef enum {
	/** The request was processed to completion and there will be no	more events from that resource to the client with that request-id */
	MRCP_REQUEST_STATE_COMPLETE,
	/** The job has been placed on a queue and will be processed in first-in-first-out order */
	MRCP_REQUEST_STATE_INPROGRESS,
	/** Indicate that further event messages will be delivered with that request-id */
	MRCP_REQUEST_STATE_PENDING,
	
	/** Number of request states */
	MRCP_REQUEST_STATE_COUNT,
	/** Unknown request state */
	MRCP_REQUEST_STATE_UNKNOWN = MRCP_REQUEST_STATE_COUNT
} mrcp_request_state_t;

/* Status codes */
typedef enum {
	MRCP_STATUS_CODE_UNKNOWN                   = 0,
	/* success codes (2xx) */
	MRCP_STATUS_CODE_SUCCESS                   = 200,
	MRCP_STATUS_CODE_SUCCESS_WITH_IGNORE       = 201,
	/* failure codec (4xx) */
	MRCP_STATUS_CODE_METHOD_NOT_ALLOWED        = 401,
	MRCP_STATUS_CODE_METHOD_NOT_VALID          = 402,
	MRCP_STATUS_CODE_UNSUPPORTED_PARAM         = 403,
	MRCP_STATUS_CODE_ILLEGAL_PARAM_VALUE       = 404,
	MRCP_STATUS_CODE_NOT_FOUND                 = 405,
	MRCP_STATUS_CODE_MISSING_PARAM             = 406,
	MRCP_STATUS_CODE_METHOD_FAILED             = 407,
	MRCP_STATUS_CODE_UNRECOGNIZED_MESSAGE      = 408,
	MRCP_STATUS_CODE_UNSUPPORTED_PARAM_VALUE   = 409,
	MRCP_STATUS_CODE_RESOURCE_SPECIFIC_FAILURE = 421
} mrcp_status_code_t;

/* MRCP message types */
typedef enum {
	MRCP_MESSAGE_TYPE_UNKNOWN,
	MRCP_MESSAGE_TYPE_REQUEST,
	MRCP_MESSAGE_TYPE_RESPONSE,
	MRCP_MESSAGE_TYPE_EVENT
} mrcp_message_type;


typedef struct mrcp_start_line_t mrcp_start_line_t;

/** Start-line of MRCP message */
struct mrcp_start_line_t {
	/** MRCP message type */
	mrcp_message_type    message_type;
	/** Version of protocol in use */
	mrcp_version_t       version;
	/** Specify the length of the message, including the start-line (v2) */
	size_t               length;
	/** Unique identifier among client and server */
	mrcp_request_id      request_id;
	/** MRCP method name */
	const char          *method_name;
	/** MRCP method id (associated with method name) */
	mrcp_method_id       method_id;
	/** Success or failure or other status of the request */
	mrcp_status_code_t   status_code;
	/* The state of the job initiated by the request */
	mrcp_request_state_t request_state;
};

/** Initialize MRCP start-line */
void mrcp_start_line_init(mrcp_start_line_t *start_line);

/** Parse MRCP start-line */
mrcp_status_t mrcp_start_line_parse(mrcp_start_line_t *start_line, apt_text_stream_t *text_stream, apr_pool_t *pool);
/** Generate MRCP start-line */
mrcp_status_t mrcp_start_line_generate(mrcp_start_line_t *start_line, apt_text_stream_t *text_stream);
/** Finalize MRCP start-line generation */
mrcp_status_t mrcp_start_line_finalize(mrcp_start_line_t *start_line, apt_text_stream_t *text_stream);


typedef struct mrcp_channel_id mrcp_channel_id;
/** MRCP channel-identifier */
struct mrcp_channel_id {
	/** Unambiguous string identifying the MRCP session */
	mrcp_session_id  session_id;
	/** MRCP resource name */
	const char      *resource_name;
	/** MRCP resource id (associated with resource name) */
	mrcp_resource_id resource_id;
};

/** Initialize MRCP channel-identifier */
void mrcp_channel_id_init(mrcp_channel_id *channel_id);

/** Parse MRCP channel-identifier */
mrcp_status_t mrcp_channel_id_parse(mrcp_channel_id *channel_id, apt_text_stream_t *text_stream, apr_pool_t *pool);

/** Generate MRCP channel-identifier */
mrcp_status_t mrcp_channel_id_generate(mrcp_channel_id *channel_id, apt_text_stream_t *text_stream);


typedef struct mrcp_message_header_t mrcp_message_header_t;

/** MRCP message-header */
struct mrcp_message_header_t {
	/** Common MRCP generic-header */
	mrcp_header_base_t generic_header;
	/** MRCP resource specific header */
	mrcp_header_base_t resource_header;
};

/** Initialize MRCP message-header */
static APR_INLINE void mrcp_message_header_init(mrcp_message_header_t *message_header)
{
	mrcp_header_base_init(&message_header->generic_header);
	mrcp_header_base_init(&message_header->resource_header);
}

/** Destroy MRCP message-header */
static APR_INLINE void mrcp_message_header_destroy(mrcp_message_header_t *message_header)
{
	mrcp_header_base_destroy(&message_header->generic_header);
	mrcp_header_base_destroy(&message_header->resource_header);
}


/** Parse MRCP message-header */
mrcp_status_t mrcp_header_parse(mrcp_message_header_t *message_header, apt_text_stream_t *text_stream, apr_pool_t *pool);

/** Generate MRCP message-header */
mrcp_status_t mrcp_header_generate(mrcp_message_header_t *message_header, apt_text_stream_t *text_stream);

/** Set MRCP message-header */
mrcp_status_t mrcp_header_set(mrcp_message_header_t *message_header, const mrcp_message_header_t *src, apr_pool_t *pool);

/** Get MRCP message-header */
mrcp_status_t mrcp_header_get(mrcp_message_header_t *message_header, const mrcp_message_header_t *src, apr_pool_t *pool);

/** Inherit MRCP message-header */
mrcp_status_t mrcp_header_inherit(mrcp_message_header_t *message_header, const mrcp_message_header_t *parent, apr_pool_t *pool);


typedef struct mrcp_message_t mrcp_message_t;

/** MRCP message */
struct mrcp_message_t {
	/** Start-line of MRCP message */
	mrcp_start_line_t      start_line;
	/** Channel-identifier of MRCP message */
	mrcp_channel_id        channel_id;
	/** Header of MRCP message */
	mrcp_message_header_t  header;
	/** Body of MRCP message */
	char                  *body;

	/** Memory pool MRCP message is allocated from */
	apr_pool_t            *pool;
};

/** Create MRCP message */
mrcp_message_t* mrcp_message_create(apr_pool_t *pool);

/** Initialize MRCP message */
void mrcp_message_init(mrcp_message_t *message, apr_pool_t *pool);

/** Initialize MRCP response/event message by request message */
void mrcp_message_init_by_request(mrcp_message_t *message, const mrcp_message_t *request_message);

/** Create MRCP request message */
mrcp_message_t* mrcp_request_create(mrcp_method_id method_id, apr_pool_t *pool);
/** Create MRCP response message */
mrcp_message_t* mrcp_response_create(const mrcp_message_t *request_message, apr_pool_t *pool);
/** Create MRCP event message */
mrcp_message_t* mrcp_event_create(const mrcp_message_t *request_message, mrcp_method_id event_id, apr_pool_t *pool);

/** Destroy MRCP message */
void mrcp_message_destroy(mrcp_message_t *message);


/** Parse MRCP message-body */
mrcp_status_t mrcp_body_parse(mrcp_message_t *message, apt_text_stream_t *text_stream, apr_pool_t *pool);
/** Generate MRCP message-body */
mrcp_status_t mrcp_body_generate(mrcp_message_t *message, apt_text_stream_t *text_stream);


/** Prepare MRCP generic-header */
static APR_INLINE void* mrcp_generic_header_prepare(mrcp_message_t *mrcp_message)
{
	return mrcp_header_base_allocate(&mrcp_message->header.generic_header,mrcp_message->pool);
}

/** Add MRCP generic-header proprerty */
static APR_INLINE void mrcp_generic_header_property_add(mrcp_message_t *mrcp_message, size_t id)
{
	mrcp_header_property_add(&mrcp_message->header.generic_header.property_set,id);
}

/** Check MRCP generic-header proprerty */
static APR_INLINE mrcp_status_t mrcp_generic_header_property_check(mrcp_message_t *mrcp_message, size_t id)
{
	return mrcp_header_property_check(&mrcp_message->header.generic_header.property_set,id);
}


/** Prepare MRCP resource-header */
static APR_INLINE void* mrcp_resource_header_prepare(mrcp_message_t *mrcp_message)
{
	return mrcp_header_base_allocate(&mrcp_message->header.resource_header,mrcp_message->pool);
}

/** Add MRCP resource-header proprerty */
static APR_INLINE void mrcp_resource_header_property_add(mrcp_message_t *mrcp_message, size_t id)
{
	mrcp_header_property_add(&mrcp_message->header.resource_header.property_set,id);
}

/** Check MRCP resource-header proprerty */
static APR_INLINE mrcp_status_t mrcp_resource_header_property_check(mrcp_message_t *mrcp_message, size_t id)
{
	return mrcp_header_property_check(&mrcp_message->header.resource_header.property_set,id);
}

MRCP_END_EXTERN_C

#endif /*__MRCP_MESSAGE_H__*/
