/***********************************************
 *  playlist.c                                 
 *                                            
 *  Copyright 2001 Eric Kratzer.              
 *  Includes Xaudio software Copyright (C)
 *           1996-2000 Xaudio Corporation
 *           All Rights Reserved.          
 *
 *  This file is part of imp3sh.
 *                                            
 *  imp3sh is free software; you can distribute
 *  it and/or modify it under the terms of the
 *  GNU General Public License as published by
 *  the Free Software Foundation; either version
 *  2 of the License, or (at your option) any
 *  later version.
 *
 *  imp3sh is distributed in the hope that
 *  it will be useful, but WITHOUT ANY WARRANTY;
 *  without even the implied warranty of 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR
 *  PURPOSE. See the GNU General Public License
 *  for more details.
 *
 *  You should have recieved a copy of the GNU
 *  General Public License along with imp3sh; if
 *  not, write to the Free Software Foundation,
 *  Inc., 59 Temple Place, Suite 330, Boston MA
 *  02111-1307 USA
 ************************************************/

/************************************
 *          Include Files           *
 ************************************/

#include "imp3sh.h"

/************************************
 *       External References        *
 ************************************/

extern ListDef *active_list, *edit_list;

extern DCharBuf *args;

extern ProcessState state;

extern char *PLAYMODES[], *SEARCHPRF[];

extern flag_t ignore_stream_weight, external_player, user_stream, inside_queue;

/************************************
 *         Local Variables          *
 ************************************/

static ListDef *list_list = NULL;

/************************************
 *         Module routines          *
 ************************************/

unsigned int g_playlist_bytec()
{
    ListDef *lst;
    unsigned int bytec;

    lst = list_list;
    bytec = 0;

    while (lst) {
	bytec += g_dbuf_bytec(lst->dcb);
	bytec += sizeof(ListDef);
	lst = lst->next;
    }

    return bytec;
}

/************************************
 *     List Manip (high-level)      *
 ************************************/

ListDef *g_list_base()
{
    return list_list;
}

ListDef *g_list(char *name)
{				/* get list */
    ListDef *lst;

    lst = list_list;

    if (name) {
	while (lst)
	    if (strcmp(lst->dcb->name, name) == 0)
		return lst;
	    else
		lst = lst->next;
    }

    return NULL;
}

int a_list(char *name)
{				/* add list */
    ListDef *curr, *prev;

    curr = list_list;
    prev = NULL;

    while (curr) {
	if (strcmp(curr->dcb->name, name) == 0)
	    return FALSE;
	prev = curr;
	curr = curr->next;
    }

    if (!prev) {
	list_list = malloc(sizeof(ListDef));
	prev = list_list;
    } else {
	prev->next = malloc(sizeof(ListDef));
	prev = prev->next;
    }

    prev->dcb = i_dbuf(name, LIST_SIZE, DCHAR_GROW);
    prev->next = NULL;
    prev->playmode = ONCE_MODE;
    prev->listview = TAG_FILE_PREF;
    prev->global_weight = 0;
    prev->play_weight = 1;
    prev->skip_weight = 1;

    return TRUE;
}

int r_list(char *name)
{				/* remove */
    ListDef *curr, *prev;

    curr = list_list;
    prev = NULL;

    while (curr) {
	if (strcmp(curr->dcb->name, name) == 0)
	    break;
	prev = curr;
	curr = curr->next;
    }

    if (curr) {
	if (prev)
	    prev->next = curr->next;
	else
	    list_list = curr->next;

	f_dbuf(curr->dcb);
	free(curr);
	return TRUE;
    }

    return FALSE;
}

void clear_all_lists()
{
    ListDef *lst, *tmp;

    lst = list_list;
    tmp = NULL;

    while (lst) {
	tmp = lst;
	lst = lst->next;

	f_dbuf(tmp->dcb);
	free(tmp);
    }

    list_list = NULL;
    edit_list = NULL;
    active_list = NULL;

    update_list_env();
}

void verify_lists()
{
    ListDef *lst;
    int i;

    lst = list_list;

    while (lst) {
	i = lst->play_weight;
	if (!i)
	    lst->play_weight = 1;
	else if (i < -128)
	    lst->play_weight = -128;
	else if (i > 127)
	    lst->play_weight = 127;

	i = lst->skip_weight;
	if (!i)
	    lst->skip_weight = 1;
	else if (i < -128)
	    lst->skip_weight = -128;
	else if (i > 127)
	    lst->skip_weight = 127;

	verify_dbuf(lst->dcb);

	lst->global_weight = 0;
	for (i = 0; i < lst->dcb->len; i++)
	    lst->global_weight += lst->dcb->buf[i].info;

	lst = lst->next;
    }
}

void check_stream_weight_state()
{
    /* don't weight current pos in new active list 
       on song switch                              */
    if (!user_stream && !in_queue() && !inside_queue &&
	(state == PLAY || (state == EXTERNAL && external_player)))
	ignore_stream_weight = TRUE;
}

void /* user */ use_list()
{
    ListDef *tmpl;
    char *name;

    name = g_dbuf(args, 1);

    if (!name)
	print_cmnd_help(USE_LIST);
    else if (!list_list)
	show_user(DEBUG_MSG " No lists currently defined");
    else {
	tmpl = g_list(name);

	if (tmpl) {
	    if (active_list != tmpl)
		check_stream_weight_state();

	    active_list = edit_list = tmpl;
	    update_list_env();
	    show_user(STATUS_MSG " Active & edit lists set to \"%s\"",
		      name);
	} else
	    show_user(DEBUG_MSG " \"%s\" list not found", name);
    }
}

void /* user */ use_next_list()
{
    ListDef *new_list;

    if (!active_list) {
	if (list_list)
	    active_list = list_list;
	else {
	    show_user(DEBUG_MSG " No lists currently defined");
	    return;
	}
    }

    if (active_list->next)
	new_list = active_list->next;
    else if (list_list)
	new_list = list_list;
    else {
	show_user(ERROR_MSG " Bad list pointer");
	return;
    }

    if (active_list != new_list)
	check_stream_weight_state();

    active_list = new_list;
    update_list_env();
    show_user(STATUS_MSG " Active list set to \"%s\"", 
	      active_list->dcb->name);
}

void /* user */ edit_list_comm()
{
    ListDef *tmpl;
    char *name;

    name = g_dbuf(args, 1);

    if (!name)
	print_cmnd_help(EDIT_LIST);
    else if (!list_list)
	show_user(DEBUG_MSG " No lists currently defined");
    else {
	tmpl = g_list(name);

	if (tmpl) {
	    edit_list = tmpl;
	    update_list_env();
	    show_user(STATUS_MSG " Edit list set to \"%s\"", name);
	} else
	    show_user(DEBUG_MSG " \"%s\" list not found", name);
    }
}

void /* user */ add_list()
{
    ListDef *lst;
    char *name;

    name = g_dbuf(args, 1);

    if (!name)
	print_cmnd_help(ADD_LIST);
    else {
	if (a_list(name) && (lst = g_list(name))) {
	    edit_list = lst;
	    if (!active_list)
		active_list = lst;
	    update_list_env();
	    show_user(STATUS_MSG " \"%s\" list created successfully",
		      name);
	} else
	    show_user(DEBUG_MSG " \"%s\" list already exists", name);
    }
}

void /* user */ reset_list()
{
    ListDef *lst;
    char *name;

    name = g_dbuf(args, 1);

    if (!name) {
	print_cmnd_help(RESET_LIST);
	return;
    }

    if (strcmp(name, "*") == 0) {
	clear_all_played();
	show_user(STATUS_MSG " All lists were reset");
    } else if (!(lst = g_list(name)))
	show_user(DEBUG_MSG " \"%s\" list not found", name);
    else {
	clear_played(lst);
	show_user(STATUS_MSG " \"%s\" was reset", name);
    }
}

void /* user */ rename_list()
{
    ListDef *lst;
    char *name, *repl;

    name = g_dbuf(args, 1);
    repl = g_dbuf(args, 2);

    if (!name || !repl)
	print_cmnd_help(RENAME_LIST);
    else if (!(lst = g_list(name)))
	show_user(DEBUG_MSG " \"%s\" list not found", name);
    else {
	free(lst->dcb->name);
	lst->dcb->name = strdup(repl);
	if (lst == active_list || lst == edit_list)
	    update_list_env();
	show_user(STATUS_MSG " \"%s\" list renamed to \"%s\"", name, repl);
    }
}

void /* user */ remove_list()
{
    ListDef *lst;
    char *name;
    flag_t curr, edit;

    name = g_dbuf(args, 1);
    curr = edit = FALSE;

    if (!name)
	print_cmnd_help(REMOVE_LIST);
    else if (strcmp(name, "*") == 0) {
	clear_all_lists();
	show_user(STATUS_MSG " Removed all lists");
    } else if (!(lst = g_list(name)))
	show_user(DEBUG_MSG " \"%s\" list not found", name);
    else {
	if (lst == active_list)
	    curr = TRUE;
	if (lst == edit_list)
	    edit = TRUE;

	r_list(name);
	show_user(STATUS_MSG " Removed \"%s\" list", name);

	if (curr) {
	    active_list = list_list;
	    if (active_list)
		show_user(STATUS_MSG " Active list is now \"%s\"",
			  active_list->dcb->name);
	    else
		show_user(STATUS_MSG
			  " No lists available: Active list undefined");
	}

	if (edit) {
	    edit_list = list_list;
	    if (edit_list)
		show_user(STATUS_MSG " Edit list is now \"%s\"",
			  edit_list->dcb->name);
	    else
		show_user(STATUS_MSG
			  " No lists available: Edit list undefined");
	}

	if (curr || edit)
	    update_list_env();
    }
}

/************************************
 *       Environment updating       *
 ************************************/

void update_list_env()
{
    char tmp[32];

    if (active_list) {
	mysetenv(CURR_ACTIVE_SOURCE, active_list->dcb->name);
	mysetenv(CURR_ACTIVE_MODE, PLAYMODES[active_list->playmode]);
	mysetenv(CURR_ACTIVE_VIEW, SEARCHPRF[active_list->listview]);
	sprintf(tmp, "%d", active_list->dcb->len);
	mysetenv(CURR_ACTIVE_LEN, tmp);
	sprintf(tmp, "%d", active_list->dcb->pos);
	mysetenv(CURR_ACTIVE_INDEX, tmp);
    } else {
	mysetenv(CURR_ACTIVE_SOURCE, NULL);
	mysetenv(CURR_ACTIVE_MODE, NULL);
	mysetenv(CURR_ACTIVE_VIEW, NULL);
	mysetenv(CURR_ACTIVE_LEN, NULL);
	mysetenv(CURR_ACTIVE_INDEX, NULL);
    }

    if (edit_list) {
	mysetenv(CURR_EDIT_SOURCE, edit_list->dcb->name);
	mysetenv(CURR_EDIT_MODE, PLAYMODES[edit_list->playmode]);
	mysetenv(CURR_EDIT_VIEW, SEARCHPRF[edit_list->listview]);
	sprintf(tmp, "%d", edit_list->dcb->len);
	mysetenv(CURR_EDIT_LEN, tmp);
    } else {
	mysetenv(CURR_EDIT_SOURCE, NULL);
	mysetenv(CURR_EDIT_MODE, NULL);
	mysetenv(CURR_EDIT_VIEW, NULL);
	mysetenv(CURR_EDIT_LEN, NULL);
    }
}

void update_active_env(ListDef * lst)
{
    char tmp[32];

    if (lst) {
	sprintf(tmp, "%d", lst->dcb->pos);
	mysetenv(CURR_ACTIVE_INDEX, tmp);
	sprintf(tmp, "%d", lst->dcb->len);
	mysetenv(CURR_ACTIVE_LEN, tmp);
	mysetenv(CURR_ACTIVE_SOURCE, lst->dcb->name);
	mysetenv(CURR_ACTIVE_MODE, PLAYMODES[lst->playmode]);
	mysetenv(CURR_ACTIVE_VIEW, SEARCHPRF[lst->listview]);
    }
}
