/*
 * 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 <apr_thread_proc.h>
#include <apr_thread_cond.h>
#include "mrcp_server_plugin.h"
#include "mrcp_synthesizer.h"
#include "mrcp_audio_channel.h"
#include "audio_buffer.h"

typedef struct synthesizer_emul_channel_t synthesizer_emul_channel_t;

struct synthesizer_emul_channel_t {
	apr_pool_t      *pool;

	int              running;
	apr_thread_t    *thread_handle;
	audio_buffer_t  *audio_buffer;
	FILE            *audio_file;
	mrcp_message_t  *message;
};

static apr_status_t synthesizer_read_frame(audio_source_t *source, media_frame_t *frame);

static const audio_source_method_set_t audio_source_method_set = {
	NULL,
	NULL,
	NULL,
	synthesizer_read_frame
};

static void* APR_THREAD_FUNC speak_emul_proc(apr_thread_t *thread_handle, void *data)
{
	char audio_data[4096];
	size_t size;
	mrcp_server_channel_t *channel = data;
	synthesizer_emul_channel_t *synth_channel = mrcp_server_channel_handle_get(channel);
	if(!synth_channel || !synth_channel->message) {
		return NULL;
	}
	
	while(synth_channel->running) {
		if(synth_channel->audio_file) {
			size = fread(audio_data,1,sizeof(audio_data),synth_channel->audio_file);
			if(size == 0) {
				break;
			}
		}
		else {
			size = sizeof(audio_data);
			memset(audio_data,0,size);
		}
		audio_buffer_write(synth_channel->audio_buffer,audio_data,size);
	}
	
	if(synth_channel->running) {
		mrcp_message_t *message = mrcp_event_create(synth_channel->message,SYNTHESIZER_SPEAK_COMPLETE,synth_channel->pool);

		audio_buffer_wait_for_read_complete(synth_channel->audio_buffer);

		printf("Synthesizer Plugin: Speak Complete\n");
		mrcp_server_channel_signal(channel,message);
		synth_channel->running = 0;
	}

	return NULL;
}

static apr_status_t synthesizer_read_frame(audio_source_t *source, media_frame_t *frame)
{
	synthesizer_emul_channel_t *synth_channel = source->object;

	frame->type = MEDIA_FRAME_TYPE_AUDIO;
	audio_buffer_read(synth_channel->audio_buffer,frame->codec_frame.buffer,frame->codec_frame.size);
	return APR_SUCCESS;
}

static mrcp_status_t synthesizer_on_channel_open(mrcp_server_plugin_t *server_plugin, mrcp_server_channel_t *channel, apr_pool_t *pool)
{
	audio_source_t *audio_source;
	synthesizer_emul_channel_t *synth_channel = apr_palloc(pool,sizeof(synthesizer_emul_channel_t));
	synth_channel->pool = pool;
	mrcp_server_channel_handle_set(channel,synth_channel);

	audio_source = apr_palloc(pool,sizeof(audio_source_t));
	audio_source->object = synth_channel;
	audio_source->method_set = &audio_source_method_set;
	mrcp_server_channel_audio_source_set(channel,audio_source);

	synth_channel->audio_buffer = audio_buffer_create(1600,pool);

	printf("Synthesizer Plugin: Open Channel\n");
	return MRCP_STATUS_SUCCESS;
}

static mrcp_status_t synthesizer_on_channel_close(mrcp_server_plugin_t *server_plugin, mrcp_server_channel_t *channel)
{
	printf("Synthesizer Plugin: Close Channel\n");
	return MRCP_STATUS_SUCCESS;
}

static mrcp_status_t synthesizer_on_speak(mrcp_server_channel_t *channel, mrcp_message_t *request_message, mrcp_message_t *response_message)
{
	synthesizer_emul_channel_t *synth_channel = mrcp_server_channel_handle_get(channel);
	mrcp_synthesizer_header_t *synth_header = request_message->header.resource_header.data;

	printf("Synthesizer Plugin: %s\n",request_message->start_line.method_name);
	if(synth_header) {
		if(mrcp_resource_header_property_check(request_message,SYNTHESIZER_HEADER_VOICE_GENDER) == MRCP_STATUS_SUCCESS) {
			switch(synth_header->voice_param.gender) {
				case VOICE_GENDER_MALE:
					printf("Lang Pack: Jenniffer\n");
					break;
				case VOICE_GENDER_FEMALE:
					printf("Lang Pack: John\n");
					break;
				default:
					printf("Lang Pack: Neutral\n");
					break;
			}
		}
	}
	if(request_message->body) {
		printf(request_message->body);
	}

	synth_channel->audio_file = fopen("demo.pcm","rb");
	synth_channel->message = request_message;
	synth_channel->running = 1;
	audio_buffer_open(synth_channel->audio_buffer);
	apr_thread_create(&synth_channel->thread_handle, NULL, speak_emul_proc, channel, synth_channel->pool);
	return MRCP_STATUS_SUCCESS;
}

static mrcp_status_t synthesizer_on_stop(mrcp_server_channel_t *channel, mrcp_message_t *request_message, mrcp_message_t *response_message)
{
	synthesizer_emul_channel_t *synth_channel = mrcp_server_channel_handle_get(channel);
	if(!synth_channel->running) {
		return MRCP_STATUS_FAILURE;
	}
	if(request_message) {
		printf("Synthesizer Plugin: %s\n",request_message->start_line.method_name);
	}

	synth_channel->running = 0;
	audio_buffer_close(synth_channel->audio_buffer);
	if(synth_channel->message) {
		mrcp_message_t *message = mrcp_response_create(synth_channel->message,synth_channel->pool);
		printf("Synthesizer Plugin: STOP Complete\n");
		mrcp_server_channel_signal(channel,message);
	}
	synth_channel->message = NULL;
	synth_channel->thread_handle = NULL;
	if(synth_channel->audio_file) {
		fclose(synth_channel->audio_file);
	}
	return MRCP_STATUS_SUCCESS;
}

static mrcp_status_t synthesizer_on_pause(mrcp_server_channel_t *channel, mrcp_message_t *request_message, mrcp_message_t *response_message)
{
	synthesizer_emul_channel_t *synth_channel = mrcp_server_channel_handle_get(channel);
	if(!synth_channel->running) {
		return MRCP_STATUS_FAILURE;
	}
	printf("Synthesizer Plugin: %s\n",request_message->start_line.method_name);
	audio_buffer_pause(synth_channel->audio_buffer);
	return MRCP_STATUS_SUCCESS;
}

static mrcp_status_t synthesizer_on_resume(mrcp_server_channel_t *channel, mrcp_message_t *request_message, mrcp_message_t *response_message)
{
	synthesizer_emul_channel_t *synth_channel = mrcp_server_channel_handle_get(channel);
	if(!synth_channel->running) {
		return MRCP_STATUS_FAILURE;
	}
	printf("Synthesizer Plugin: %s\n",request_message->start_line.method_name);
	audio_buffer_resume(synth_channel->audio_buffer);
	return MRCP_STATUS_SUCCESS;
}

static mrcp_status_t synthesizer_on_barge_in_occurred(mrcp_server_channel_t *channel, mrcp_message_t *request_message, mrcp_message_t *response_message)
{
	synthesizer_on_stop(channel,request_message,response_message);
	return MRCP_STATUS_SUCCESS;
}

static mrcp_status_t synthesizer_on_control(mrcp_server_channel_t *channel, mrcp_message_t *request_message, mrcp_message_t *response_message)
{
	printf("Synthesizer Plugin: %s\n",request_message->start_line.method_name);
	return MRCP_STATUS_SUCCESS;
}

static mrcp_status_t synthesizer_on_define_lexicon(mrcp_server_channel_t *channel, mrcp_message_t *request_message, mrcp_message_t *response_message)
{
	printf("Synthesizer Plugin: %s\n",request_message->start_line.method_name);
	return MRCP_STATUS_SUCCESS;
}

static mrcp_status_t synthesizer_on_setparams(mrcp_server_channel_t *channel, mrcp_message_t *request_message, mrcp_message_t *response_message)
{
	printf("Synthesizer Plugin: %s\n",request_message->start_line.method_name);
	return MRCP_STATUS_SUCCESS;
}

static mrcp_status_t synthesizer_on_getparams(mrcp_server_channel_t *channel, mrcp_message_t *request_message, mrcp_message_t *response_message)
{
	printf("Synthesizer Plugin: %s\n",request_message->start_line.method_name);
	return MRCP_STATUS_SUCCESS;
}

static mrcp_server_method_plugin_t synthesizer_method_plugin_array[] = {
	synthesizer_on_setparams,
	synthesizer_on_getparams,
	synthesizer_on_speak,
	synthesizer_on_stop,
	synthesizer_on_pause,
	synthesizer_on_resume,
	synthesizer_on_barge_in_occurred,
	synthesizer_on_control,
	synthesizer_on_define_lexicon
};


static mrcp_status_t synthesizer_destroy(mrcp_module_t *module)
{
	return MRCP_STATUS_SUCCESS;
}

static mrcp_module_state_t synthesizer_open(mrcp_module_t *module)
{
	return MODULE_STATE_OPENED;
}

static mrcp_module_state_t synthesizer_close(mrcp_module_t *module)
{
	return MODULE_STATE_CLOSED;
}

static mrcp_module_method_set_t module_method_set = {
	synthesizer_destroy,
	synthesizer_open,
	synthesizer_close,
	NULL /*process*/
};

MRCP_PLUGIN_DECLARE(mrcp_server_plugin_t*) mrcp_synthesizer_plugin_create(apr_pool_t *pool)
{
	mrcp_server_plugin_t *synthesizer_plugin = apr_palloc(pool,sizeof(mrcp_server_plugin_t));

	mrcp_module_init(&synthesizer_plugin->module,&module_method_set);

	synthesizer_plugin->channel_open = synthesizer_on_channel_open;
	synthesizer_plugin->channel_close = synthesizer_on_channel_close;
	synthesizer_plugin->method_plugin_array = synthesizer_method_plugin_array;
	synthesizer_plugin->method_count = SYNTHESIZER_METHOD_COUNT;

	return synthesizer_plugin;
}
