/*
 * 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_HEADER_BASE_H__
#define __MRCP_HEADER_BASE_H__

/**
 * @file mrcp_header_base.h
 * @brief The Base of MRCP Header
 */ 

#include "apt_string_table.h"
#include "apt_text_stream.h"
#include "mrcp_types.h"

MRCP_BEGIN_EXTERN_C

/** Bit field masks are used to define property set */
typedef int mrcp_header_property_set_t;

/** Add property to property set */
static APR_INLINE void mrcp_header_property_add(mrcp_header_property_set_t *property_set, size_t id)
{
	int mask = 1 << id;
	*property_set |= mask;
}

/** Remove property from property set */
static APR_INLINE void mrcp_header_property_remove(mrcp_header_property_set_t *property_set, size_t id)
{
	int mask = 1 << id;
	*property_set &= ~mask;
}

/** Check the property in property set */
static APR_INLINE mrcp_status_t mrcp_header_property_check(mrcp_header_property_set_t *property_set, size_t id)
{
	int mask = 1 << id;
	return ((*property_set & mask) == mask) ? MRCP_STATUS_SUCCESS : MRCP_STATUS_FAILURE;
}


typedef struct mrcp_header_base_t mrcp_header_base_t;

typedef struct mrcp_header_accessor_t mrcp_header_accessor_t;
/** MRCP header accessor interface */
struct mrcp_header_accessor_t {
	/** Allocate actual header data */
	void* (*allocator)(mrcp_header_base_t *header, apr_pool_t *pool);
	/** Destroy header data */
	void (*destructor)(mrcp_header_base_t *header);

	/** Parse header field */
	mrcp_status_t (*field_parser)(mrcp_header_base_t *header, size_t id, char *value, apr_pool_t *pool);
	/** Generate header field */
	size_t (*field_generator)(mrcp_header_base_t *header, size_t id, char *value);
	/** Duplicate header field */
	mrcp_status_t (*field_duplicator)(mrcp_header_base_t *header, const mrcp_header_base_t *src, size_t id, apr_pool_t *pool);

	/** Table of fields  */
	const apt_string_table_item_t *field_table;
	/** Number of fields  */
	size_t                         field_count;
};

/** Initialize header accessor */
static APR_INLINE void mrcp_header_accessor_init(mrcp_header_accessor_t *header_accessor)
{
	header_accessor->allocator = NULL;
	header_accessor->destructor = NULL;
	header_accessor->field_parser = NULL;
	header_accessor->field_generator = NULL;
	header_accessor->field_duplicator = NULL;
	header_accessor->field_table = NULL;
	header_accessor->field_count = 0;
}

/** Validate header accessor */
static APR_INLINE mrcp_status_t mrcp_header_accessor_validate(mrcp_header_accessor_t *header_accessor)
{
	return (header_accessor->allocator && header_accessor->destructor && 
		header_accessor->field_parser && header_accessor->field_generator &&
		header_accessor->field_duplicator && header_accessor->field_table && 
		header_accessor->field_count) ?	MRCP_STATUS_SUCCESS : MRCP_STATUS_FAILURE;
}


/** MRCP header base */
struct mrcp_header_base_t {
	/** Actual header data allocated by accessor */
	void                         *data;
	/** Property set explicitly shows which fields are present(set) in entire header */
	mrcp_header_property_set_t    property_set;
	
	/** Header accessor interface */
	const mrcp_header_accessor_t *accessor;
};

/** Initialize header base */
static APR_INLINE void mrcp_header_base_init(mrcp_header_base_t *header)
{
	header->data = NULL;
	header->property_set = 0;
	header->accessor = NULL;
}

/** Allocate header data */
static APR_INLINE void* mrcp_header_base_allocate(mrcp_header_base_t *header, apr_pool_t *pool)
{
	if(header->data) {
		return header->data;
	}
	if(!header->accessor || !header->accessor->allocator) {
		return NULL;
	}
	return header->accessor->allocator(header,pool);
}

/** Destroy header base */
static APR_INLINE void mrcp_header_base_destroy(mrcp_header_base_t *header)
{
	if(!header->accessor || !header->accessor->destructor) {
		return;
	}
	header->accessor->destructor(header);
}


/** Parse header base */
mrcp_status_t mrcp_header_base_parse(mrcp_header_base_t *header, apt_name_value_pair_t *name_value_pair, apr_pool_t *pool);

/** Generates header base */
mrcp_status_t mrcp_header_base_generate(mrcp_header_base_t *header, apt_text_stream_t *text_stream);

/** Set header base */
mrcp_status_t mrcp_header_base_set(mrcp_header_base_t *header, const mrcp_header_base_t *src, mrcp_header_property_set_t mask, apr_pool_t *pool);

/** Inherit header base */
mrcp_status_t mrcp_header_base_inherit(mrcp_header_base_t *header, const mrcp_header_base_t *parent, apr_pool_t *pool);

MRCP_END_EXTERN_C

#endif /*__MRCP_HEADER_BASE_H__*/
