/*
 * 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_client_context.h"
#include "mrcp_client_defs.h"
#include "mrcp_client_session.h"
#include "mrcp_resource.h"
#include "mrcp_parser.h"
#include "mrcp_resource_set.h"

static APR_INLINE apt_task_msg_t* context_msg_prepare(mrcp_client_context_t *context, mrcp_client_context_msg_id msg_id, mrcp_client_context_msg_t **context_msg)
{
	apt_task_msg_t *task_msg = apt_task_msg_acquire(context->msg_pool);
	if(!task_msg) {
		return NULL;
	}
	*context_msg = (mrcp_client_context_msg_t*) task_msg->data;
	(*context_msg)->msg_id = msg_id;
	return task_msg;
}


mrcp_client_context_t* mrcp_client_context_create(void *object, mrcp_client_event_handler_t *event_handler)
{
	mrcp_client_context_t *context = malloc(sizeof(mrcp_client_context_t));
	context->msg_pool = NULL;
	context->object = object;
	context->event_handler = event_handler;

	mrcp_module_init(&context->module,NULL);
	return context;
}

mrcp_status_t mrcp_client_context_destroy(mrcp_client_context_t *context)
{
	free(context);
	return MRCP_STATUS_SUCCESS;
}


mrcp_session_t* mrcp_client_context_session_create(mrcp_client_context_t *context, void *object)
{
	mrcp_session_t *session = mrcp_client_session_create();
	session->handle = object;
	return session;
}

mrcp_status_t mrcp_client_context_session_destroy(mrcp_client_context_t *context, mrcp_session_t *session)
{
	mrcp_client_context_msg_t *context_msg;
	apt_task_msg_t *task_msg = context_msg_prepare(context,MRCP_CLIENT_SESSION_DESTROY,&context_msg);
	if(!task_msg) {
		return MRCP_STATUS_FAILURE;
	}
	context_msg->session = session;
	return context->module.signal(&context->module,task_msg);
}

mrcp_status_t mrcp_client_context_session_initiate(mrcp_client_context_t *context, mrcp_session_t *session)
{
	mrcp_client_context_msg_t *context_msg;
	apt_task_msg_t *task_msg = context_msg_prepare(context,MRCP_CLIENT_SESSION_INITIATE,&context_msg);
	if(!task_msg) {
		return MRCP_STATUS_FAILURE;
	}
	context_msg->session = session;
	return context->module.signal(&context->module,task_msg);
}

mrcp_status_t mrcp_client_context_session_terminate(mrcp_client_context_t *context, mrcp_session_t *session)
{
	mrcp_client_context_msg_t *context_msg;
	apt_task_msg_t *task_msg = context_msg_prepare(context,MRCP_CLIENT_SESSION_TERMINATE,&context_msg);
	if(!task_msg) {
		return MRCP_STATUS_FAILURE;
	}
	context_msg->session = session;
	return context->module.signal(&context->module,task_msg);
}

mrcp_media_audio_t* mrcp_client_audio_media_create(mrcp_client_context_t *context, mrcp_session_t *session, const char *ip, unsigned short port)
{
	mrcp_media_audio_t *audio_media = mrcp_audio_media_create(session->pool);
	audio_media->base.ip = ip;
	audio_media->base.port = port;
	audio_media->base.state = MRCP_MEDIA_ENABLED;
	return audio_media;
}

mrcp_audio_channel_t* mrcp_client_audio_channel_create(mrcp_client_context_t *context, mrcp_session_t *session, mrcp_media_audio_t *local_media, mrcp_audio_channel_mode_t mode)
{
	return mrcp_audio_channel_create(mode,local_media,NULL,session->pool);
}

mrcp_client_channel_t* mrcp_client_synthesizer_channel_create(mrcp_client_context_t *context, mrcp_session_t *session, audio_sink_t *sink)
{
	mrcp_resource_t *resource;
	mrcp_client_channel_t *channel;
	mrcp_client_t *mrcp_client = (mrcp_client_t*) context->module.engine;
	resource = mrcp_client->resource_container->resource_array[MRCP_RESOURCE_SYNTHESIZER];
	if(!resource) {
		return NULL;
	}
	
	channel = mrcp_client_channel_create(session,resource,NULL,sink);
	return channel;
}

mrcp_client_channel_t* mrcp_client_recognizer_channel_create(mrcp_client_context_t *context, mrcp_session_t *session, audio_source_t *source)
{
	mrcp_resource_t *resource;
	mrcp_client_channel_t *channel;
	mrcp_client_t *mrcp_client = (mrcp_client_t*) context->module.engine;
	resource = mrcp_client->resource_container->resource_array[MRCP_RESOURCE_RECOGNIZER];
	if(!resource) {
		return NULL;
	}
	
	channel = mrcp_client_channel_create(session,resource,source,NULL);
	return channel;
}

mrcp_status_t mrcp_client_context_channel_destroy(mrcp_client_context_t *context, mrcp_session_t *session, mrcp_client_channel_t *channel)
{
	/* nothing to do, channel is allocated from the pool */
	return MRCP_STATUS_SUCCESS;
}

mrcp_status_t mrcp_client_context_channel_add(mrcp_client_context_t *context, mrcp_session_t* session, mrcp_client_channel_t *control_channel, mrcp_audio_channel_t *audio_channel)
{
	mrcp_client_context_msg_t *context_msg;
	apt_task_msg_t *task_msg = context_msg_prepare(context,MRCP_CLIENT_CHANNEL_ADD,&context_msg);
	if(!task_msg) {
		return MRCP_STATUS_FAILURE;
	}
	context_msg->session = session;
	context_msg->control_channel = control_channel;
	context_msg->audio_channel = audio_channel;
	return context->module.signal(&context->module,task_msg);
}

mrcp_status_t mrcp_client_context_channel_remove(mrcp_client_context_t *context, mrcp_session_t* session, mrcp_client_channel_t *control_channel)
{
	mrcp_client_context_msg_t *context_msg;
	apt_task_msg_t *task_msg = context_msg_prepare(context,MRCP_CLIENT_CHANNEL_REMOVE,&context_msg);
	if(!task_msg) {
		return MRCP_STATUS_FAILURE;
	}
	context_msg->session = session;
	context_msg->control_channel = control_channel;
	return context->module.signal(&context->module,task_msg);
}

audio_sink_t* mrcp_client_audio_sink_get(mrcp_audio_channel_t *channel)
{
	if(!channel || channel->mode != MRCP_AUDIO_CHANNEL_ACTIVE) {
		return NULL;
	}
	return channel->audio_sink;
}

audio_source_t* mrcp_client_audio_source_get(mrcp_audio_channel_t *channel)
{
	if(!channel || channel->mode != MRCP_AUDIO_CHANNEL_ACTIVE) {
		return NULL;
	}
	return channel->audio_source;
}

mrcp_status_t mrcp_client_context_channel_modify(mrcp_client_context_t *context, mrcp_session_t *session, mrcp_message_t *mrcp_message)
{
	mrcp_client_context_msg_t *context_msg;
	apt_task_msg_t *task_msg = context_msg_prepare(context,MRCP_CLIENT_CHANNEL_MODIFY,&context_msg);
	if(!task_msg) {
		return MRCP_STATUS_FAILURE;
	}
	context_msg->session = session;
	context_msg->mrcp_message = mrcp_message;
	mrcp_message->start_line.request_id = ++session->last_request_id;
	return context->module.signal(&context->module,task_msg);
}

mrcp_message_t* mrcp_client_context_message_get(mrcp_client_context_t *context, mrcp_session_t *session, mrcp_client_channel_t* channel, mrcp_method_id method_id)
{
	mrcp_client_t *mrcp_client = (mrcp_client_t*) context->module.engine;
	mrcp_message_t *mrcp_message;
	if(!session || !channel) {
		return NULL;
	}
	
	mrcp_message = mrcp_request_create(method_id,mrcp_client->pool);
	mrcp_message->channel_id.resource_id = channel->resource->id;
	if(mrcp_message_associate_resource_by_id(mrcp_client->resource_container,mrcp_message) != MRCP_STATUS_SUCCESS) {
		apt_log(APT_PRIO_WARNING,"Failed to Associate MRCP Resource\n");
		return NULL;
	}

	return mrcp_message;
}

mrcp_status_t mrcp_client_context_resource_discover(mrcp_client_context_t *context)
{
	mrcp_client_context_msg_t *context_msg;
	apt_task_msg_t *task_msg = context_msg_prepare(context,MRCP_CLIENT_RESOURCE_DISCOVER,&context_msg);
	if(!task_msg) {
		return MRCP_STATUS_FAILURE;
	}
	return context->module.signal(&context->module,task_msg);
}

void* mrcp_client_context_object_get(mrcp_client_context_t *context)
{
	return context->object;
}

void* mrcp_client_context_session_object_get(mrcp_session_t *session)
{
	return session->handle;
}

mrcp_resource_id mrcp_client_context_resource_id_get(mrcp_client_channel_t *channel)
{
	return channel->resource->id;
}
