/*
 * GQmpeg
 * (C)1998, 1999 John Ellis
 *
 * Author: John Ellis
 *
 * This software is released under the GNU General Public License.
 * Please read the included file COPYING for more information.
 * This software comes with no warranty of any kind, use at you own risk!
 */

#include "gqmpeg.h"
#include "players.h"

static GList *io_list = NULL;
static IO_ModuleData *current_imd = NULL;

/*
 *-----------------------------------------------------------------------------
 * player module functions (public)
 *-----------------------------------------------------------------------------
 */

void player_modules_init()
{
	mpg123_init();
}

void player_modules_config_load(FILE *f, gchar *option, gchar *value, gchar *value_all)
{
	GList *work = io_list;
	while(work)
		{
		IO_ModuleData *imd = work->data;
		if (imd->config_load_func) imd->config_load_func(f, option, value, value_all);
		work = work->next;
		}
}

void player_modules_config_save(FILE *f)
{
	GList *work = io_list;
	while(work)
		{
		IO_ModuleData *imd = work->data;
		if (imd->config_save_func) imd->config_save_func(f);
		work = work->next;
		}
}

GList *player_modules_config_init()
{
	GList *list = NULL;
	GList *work = io_list;
	while(work)
		{
		GtkWidget *widget = NULL;
		IO_ModuleData *imd = work->data;
		if (imd->config_init_func)
			{
			widget = imd->config_init_func();
			}
		if (widget)
			{
			gtk_object_set_user_data(GTK_OBJECT(widget), imd->title);
			list = g_list_append(list, widget);
			}
		work = work->next;
		}

	return list;
}

void player_modules_config_apply()
{
	GList *work = io_list;
	while(work)
		{
		IO_ModuleData *imd = work->data;
		if (imd->config_apply_func) imd->config_apply_func();
		work = work->next;
		}
}

void player_modules_config_close()
{
	GList *work = io_list;
	while(work)
		{
		IO_ModuleData *imd = work->data;
		if (imd->config_close_func) imd->config_close_func();
		work = work->next;
		}
}

/*
 *-----------------------------------------------------------------------------
 * player module functions (private)
 *-----------------------------------------------------------------------------
 */

static gint player_module_get_type_id(IO_ModuleData *imd)
{
	gint ret = 0;
	GList *work = io_list;

	while(work)
		{
		if (imd == work->data) return ret;
		ret++;
		work = work->next;
		}

	return -1;
}

static IO_ModuleData *player_module_by_type_id(gint type)
{
	gint c = 0;
	GList *work = io_list;

	while(work)
		{
		if (c == type) return work->data;
		c++;
		work = work->next;
		}

	return NULL;
}

static gint player_module_get_id_by_type(gchar *path)
{
	gint ret;
	
	ret = typelist_determine_module_id(path);

	if (ret == -1)
		{
		ret = filter_determine_module_id(path);
		}

	return ret;
}

static void player_module_get_types(gchar *path, gint *type, gint *custom, gint *custom_type, gint *live)
{
	typelist_determine_ids(path, type, custom, custom_type, live);

	if (*type == -1)
		{
		*type = filter_determine_module_id(path);
		}
}

/*
 *-----------------------------------------------------------------------------
 * player module songdata functions (public)
 *-----------------------------------------------------------------------------
 */

SongData *player_module_songdata_init(gchar *path)
{
	IO_ModuleData *imd = NULL;
	SongData *sd;

	sd = g_new0(SongData, 1);
	sd->path = g_strdup(path);
	sd->generic_info_loaded = FALSE;
	sd->format_info_loaded = FALSE;
	player_module_get_types(path, &sd->type, &sd->custom, &sd->custom_type, &sd->live);

	imd = player_module_by_type_id(sd->type);

	if (imd && imd->songdata_init_func)
		{
		imd->songdata_init_func(sd);
		}

	if (!imd)
		{
		printf("No registered player types match: %s\n", path);
		}

	return sd;
}

gint player_module_songdata_update(SongData *sd, gint generic_info, gint format_info)
{
	IO_ModuleData *imd = NULL;

	if (!sd || !sd->path) return FALSE;

	imd = player_module_by_type_id(sd->type);

	if (imd && imd->songdata_info_func)
		{
		return imd->songdata_info_func(sd, generic_info, format_info);
		}

	return FALSE;
}

GtkWidget *player_module_songdata_detail_info(gchar *path)
{
	IO_ModuleData *imd;
	gint id = player_module_get_id_by_type(path);
	imd = player_module_by_type_id(id);

	if (imd && imd->info_func)
		{
		return imd->info_func(path);
		}

	return NULL;
}

/*
 *-----------------------------------------------------------------------------
 * player module start/stop/pause/seek functions (public)
 *-----------------------------------------------------------------------------
 */

gint playback_start(SongData *sd, gint seconds)
{
	gint ret = FALSE;

	if (!sd) return FALSE;

	if (status == STATUS_PLAY) return FALSE;
	if (status == STATUS_STOP || status == STATUS_NEXT) current_imd = player_module_by_type_id(sd->type);

	if (!current_imd || !current_imd->start_func)
		{
		printf("No registered player types claim playback for: %s\n", sd->path);
		return FALSE;
		}

	ret = current_imd->start_func(sd, seconds);

	if (ret)
		{
		status = STATUS_PLAY;
		}
	if (ret == -1)
		{
		current_imd = NULL;
		}

	return ret;
}

gint playback_stop(SongData *sd)
{
	gint ret = FALSE;

	if (!current_imd || !current_imd->stop_func || status == STATUS_STOP) return FALSE;

	ret = current_imd->stop_func(sd);

	if (ret == TRUE || ret == -1)
		{
		status = STATUS_STOP;
		current_imd = NULL;
		}

	return ret;
}

gint playback_pause(SongData *sd)
{
	gint ret = FALSE;

	if (!current_imd || !current_imd->pause_func || status == STATUS_STOP) return FALSE;
	if (status == STATUS_PAUSE) return playback_continue(sd);

	ret = current_imd->pause_func(sd);

	if (ret)
		{
		status = STATUS_PAUSE;
		}
	if (ret == -1)
		{
		status = STATUS_STOP;
		current_imd = NULL;
		}

	return ret;
}

gint playback_continue(SongData *sd)
{
	gint ret = FALSE;

	if (!current_imd || !current_imd->continue_func || status != STATUS_PAUSE) return FALSE;

	ret = current_imd->continue_func(sd);

	if (ret)
		{
		status = STATUS_PLAY;
		}
	if (ret == -1)
		{
		status = STATUS_STOP;
		current_imd = NULL;
		}

	return ret;
}

gint playback_seek(SongData *sd, gint seconds)
{
	gint ret = FALSE;

	if (!current_imd || !current_imd->seek_func) return FALSE;
	if (status != STATUS_PLAY && status != STATUS_PAUSE) return FALSE;

	ret = current_imd->seek_func(sd, seconds);

	if (ret == -1)
		{
		status = STATUS_STOP;
		current_imd = NULL;
		}

	return ret;
}

/*
 *-----------------------------------------------------------------------------
 * player module interface functions (public)
 * modules can call these functions to register types, update status, etc. ??
 *-----------------------------------------------------------------------------
 */

gint player_module_register(IO_ModuleData *imd)
{
	io_list = g_list_append(io_list, imd);
	return player_module_get_type_id(imd);
}

void module_register_file_suffix_type(gchar *extension, gchar *description, gint module_id)
{
	add_to_filter(extension, description, module_id);
}

void module_register_misc_type(gchar *format, gchar *description, gint module_id, gint live,
			       gint (*is_type_func)(gchar *),
			       GtkWidget *(*entry_setup_func)(gchar *),
			       GtkWidget *(*edit_func)(SongData *),
			       gchar *(*get_path_func)(GtkWidget *))
{
	add_to_typelist(format, description, module_id, live,
			is_type_func, entry_setup_func, edit_func, get_path_func);
}

void module_playback_end()
{
	status = STATUS_NEXT;
}

void module_playback_error()
{
	status = STATUS_STOP;
}

