/*
 * 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 "openmrcp_server.h"
#include "mrcp_resource_manager.h"
#include "mrcp_resource_set.h"

#define DEFAULT_MRCP_SERVER_VERSION MRCP_VERSION_2

mrcp_server_plugin_t* mrcp_synthesizer_plugin_create(apr_pool_t *pool);
mrcp_server_plugin_t* mrcp_recognizer_plugin_create(apr_pool_t *pool);

mrcp_signaling_agent_t* mrcp_server_sofia_agent_create(const char *ip, unsigned short sip_port, unsigned short mrcp_port, 
													   const char *resource_location, apr_pool_t *pool);
mrcp_proto_agent_t* mrcp_server_v2_agent_create(const char *listen_ip, unsigned short listen_port, apr_pool_t *pool);

mrcp_signaling_agent_t* mrcp_server_rtsp_agent_create(const char *ip, unsigned short rtsp_port, 
													  const char *resource_location, apr_pool_t *pool);
mrcp_proto_agent_t* mrcp_server_rtsp_proto_agent_create(mrcp_signaling_agent_t *signaling_agent);

mrcp_media_agent_t* mrcp_live_media_agent_create(const char *ip, unsigned short rtp_port_min, unsigned short rtp_port_max, apr_pool_t *pool);


static mrcp_signaling_agent_t* module_signaling_agent_create(mrcp_server_module_loader_t *module_loader, apr_pool_t *pool)
{
	openmrcp_server_options_t *options = (openmrcp_server_options_t *)module_loader;
	mrcp_signaling_agent_t *signaling_agent = NULL;
	switch(options->proto_version) {
		case MRCP_VERSION_1:
			signaling_agent = mrcp_server_rtsp_agent_create(
									options->local_ip,options->local_port,
									options->resource_location,pool);
			break;
		case MRCP_VERSION_2:
			signaling_agent = mrcp_server_sofia_agent_create(
									options->local_ip,options->local_port,options->mrcp_port,
									options->resource_location,pool);
			break;
		default:
			break;
	}
	return signaling_agent;
}

static mrcp_proto_agent_t* module_proto_agent_create(mrcp_server_module_loader_t *module_loader, mrcp_signaling_agent_t *signaling_agent, apr_pool_t *pool)
{
	openmrcp_server_options_t *options = (openmrcp_server_options_t *)module_loader;
	mrcp_proto_agent_t *proto_agent = NULL;
	switch(options->proto_version) {
		case MRCP_VERSION_1:
			proto_agent = mrcp_server_rtsp_proto_agent_create(signaling_agent);
			break;
		case MRCP_VERSION_2:
			proto_agent = mrcp_server_v2_agent_create(options->local_ip,options->mrcp_port,pool);
			break;
		default:
			break;
	}
	return proto_agent;
}

static mrcp_media_agent_t* module_media_agent_create(mrcp_server_module_loader_t *module_loader, apr_pool_t *pool)
{
	openmrcp_server_options_t *options = (openmrcp_server_options_t *)module_loader;

	return mrcp_live_media_agent_create(options->local_ip,options->rtp_port_min,options->rtp_port_max,pool);
}

static mrcp_server_plugin_t* mrcp_resource_plugin_load(
								apr_dso_handle_t *dso_handle, 
								const char *symname, 
								mrcp_plugin_creator default_plugin_creator, 
								apr_pool_t *pool)
{
	mrcp_plugin_creator plugin_creator = NULL;
	if(dso_handle) {
		apr_dso_handle_sym_t func_handle = NULL;
		if(apr_dso_sym(&func_handle,dso_handle,symname) != APR_SUCCESS) {
			char derr[512] = "";
			apr_dso_error(dso_handle,derr,sizeof(derr));
			printf("%s\n",derr);
		}
		if(func_handle) {
			plugin_creator = (mrcp_plugin_creator)(intptr_t)func_handle;
		}
		else {
			printf("No such symbol '%s'\n",symname);
		}
	}
	if(plugin_creator == NULL) {
		plugin_creator = default_plugin_creator;
	}
	return plugin_creator(pool);
}

static mrcp_server_resource_t* mrcp_server_resource_get(mrcp_resource_container_t *resource_container, mrcp_resource_id resource_id)
{
	if(resource_id < resource_container->resource_count) {
		return (mrcp_server_resource_t*)resource_container->resource_array[resource_id];
	}
	return NULL;
}

static mrcp_resource_container_t* module_resource_container_create(mrcp_server_module_loader_t *module_loader, apr_pool_t *pool)
{
	openmrcp_server_options_t *options = (openmrcp_server_options_t *)module_loader;
	mrcp_server_resource_t *resource;
	mrcp_resource_container_t *resource_container = mrcp_server_resource_container_create(options->proto_version,options->resource_string_table,pool);
	if(!resource_container) {
		return NULL;
	}

	/* synthesizer plugin initialization */
	resource = mrcp_server_resource_get(resource_container,MRCP_RESOURCE_SYNTHESIZER);
	if(resource) {
		resource->plugin = mrcp_resource_plugin_load(
								options->synth_plugin,
								"mrcp_synthesizer_plugin_create",
								mrcp_synthesizer_plugin_create,
								pool);
	}

	/* recognizer plugin initialization */
	resource = mrcp_server_resource_get(resource_container,MRCP_RESOURCE_RECOGNIZER);
	if(resource) {
		resource->plugin = mrcp_resource_plugin_load(
								options->recog_plugin,
								"mrcp_recognizer_plugin_create",
								mrcp_recognizer_plugin_create,
								pool);
	}
	
	return resource_container;
}

static mrcp_status_t openmrcp_server_options_validate(openmrcp_server_options_t *options)
{
	if(!options) {
		return MRCP_STATUS_FAILURE;
	}

	if(options->proto_version != MRCP_VERSION_1 && options->proto_version != MRCP_VERSION_2) {
		options->proto_version = DEFAULT_MRCP_SERVER_VERSION;
	}

	if(options->local_ip == NULL) {
		options->local_ip = "127.0.0.1";
	}
	if(options->local_port == 0) {
		switch(options->proto_version) {
			case MRCP_VERSION_1:
				options->local_port = 1554; /*554*/
				break;
			case MRCP_VERSION_2:
				options->local_port = 8060; /*5060*/
				break;
			default:
				break;
		}
	}
	if(options->mrcp_port == 0) {
		options->mrcp_port = 1544;
	}
	if(options->rtp_port_min == 0) {
		options->rtp_port_min = 6000;
	}
	if(options->rtp_port_max == 0) {
		options->rtp_port_max = 8000;
	}

	if(!options->resource_location) {
		switch(options->proto_version) {
			case MRCP_VERSION_1:
				options->resource_location = "media";
				break;
			case MRCP_VERSION_2:
				options->resource_location = "";
				break;
			default:
				break;
		}
	}

	options->module_loader.signaling_agent_create = module_signaling_agent_create;
	options->module_loader.proto_agent_create = module_proto_agent_create;
	options->module_loader.media_agent_create = module_media_agent_create;
	options->module_loader.resource_container_create = module_resource_container_create;
	return MRCP_STATUS_SUCCESS;
}

openmrcp_server_options_t* openmrcp_server_options_create(apr_pool_t *pool)
{
	openmrcp_server_options_t *options = apr_palloc(pool,sizeof(openmrcp_server_options_t));
	options->proto_version = DEFAULT_MRCP_SERVER_VERSION;
	options->local_ip = NULL;
	options->local_port = 0;
	options->mrcp_port = 0;
	options->rtp_port_min = 0;
	options->rtp_port_max = 0;
	options->synth_plugin = NULL;
	options->recog_plugin = NULL;
	options->resource_location = NULL;
	options->resource_string_table = NULL;
	return options;
}


mrcp_server_t* openmrcp_server_start(openmrcp_server_options_t *options)
{
	if(!options) {
		return NULL;
	}

	openmrcp_server_options_validate(options);
	
	return mrcp_server_start(&options->module_loader);
}

mrcp_status_t openmrcp_server_shutdown(mrcp_server_t *mrcp_server)
{
	return mrcp_server_shutdown(mrcp_server);
}
