/***********************************************
 *  stream.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"

#define LIST_COMM_SIZE  (COMM_SIZE*2)

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

extern CommandDef com[];

extern ListDef *edit_list;

extern DCharBuf *args;

extern char *c_path;

extern flag_t ignore_stream_weight, sort_mode, read_file_tags;

/************************************
 *        Local variables           *
 ************************************/

static char tmpstr_st[LIST_COMM_SIZE], tmpstr2_st[LIST_COMM_SIZE];
static char search_dir[PATH_MAX];

/************************************
 *       Stream weight manip        *
 ************************************/

void clear_all_played()
{
    ListDef *lst;

    lst = g_list_base();

    while (lst) {
	clear_played(lst);
	lst = lst->next;
    }
}

void clear_played(ListDef * lst)
{
    DCBNode *buf;
    int i, len;

    if (lst) {
	buf = lst->dcb->buf;
	len = lst->dcb->len;

	for (i = 0; i < len; i++)
	    buf[i].info = 0;

	lst->global_weight = 0;
    }
}

void clear_good_played(ListDef * lst, int weight)
{
    DCBNode *buf;
    int i, len;

    if (lst) {
	buf = lst->dcb->buf;
	len = lst->dcb->len;

	for (i = 0; i < len; i++)
	    if (buf[i].info >= weight) {
		lst->global_weight -= buf[i].info;
		buf[i].info = 0;
	    }
    }
}

void set_stream_weight(ListDef *lst, int val)
{
    DCharBuf *dcb;
    int nfo, pos, inc;
    
    dcb = lst->dcb;
    pos = dcb->pos;
    nfo = g_dbuf_info(dcb, pos);
    inc = nfo + val;

    if (inc > 127) {
	sp_dbuf(dcb, pos, 127);
	inc = 127 - nfo;
    } else if (inc < -128) {
	sp_dbuf(dcb, pos, -128);
	inc = -128 - nfo;
    } else {
	sp_dbuf(dcb, pos, inc);
	inc = val;
    }

    lst->global_weight += inc;
}

void add_stream_weight(ListDef * lst)
{
    if (ignore_stream_weight)
	ignore_stream_weight = FALSE;
    else if (lst)
	set_stream_weight(lst, lst->play_weight);
}

void remove_stream_weight(ListDef * lst)
{
    if (ignore_stream_weight)
	ignore_stream_weight = FALSE;
    else if (lst)
	set_stream_weight(lst, -(lst->skip_weight));
}

/************************************
 *          Stream manip            *
 ************************************/

int add_stream(char *file, DCharBuf * dcb, int tag_present, int check_info)
{
    if (check_info && !tag_present && get_stream_info(file, tmpstr2_st)) {
	strcat(tmpstr2_st, TAG_CODE);
	strcat(tmpstr2_st, file);
	return a_dbuf(dcb, skip_space(tmpstr2_st));
    } else
	return a_dbuf(dcb, file);
}

char *get_stream(DCharBuf * lst, int index, int what)
{
    char *tag, *fn;

    tag = g_dbuf(lst, index);

    if (!tag)
	return NULL;

    fn = grep_str(TAG_CODE, tag);
    if (!fn) {
	fn = tag;
	tag = NULL;
    }

    if (what == STR_FILE)
	return fn;
    else
	return tag;
}

void get_stream_id(ListDef * lst, int ndx, char *out)
{
    char *file, *tag;
    int pos;

    *out = ZCHAR;
    file = get_stream(lst->dcb, ndx, STR_FILE);

    if (!file)
	return;

    switch (lst->listview) {
    case TAG_FILE_PREF:
    case TAG_PATH_PREF:
	tag = get_stream(lst->dcb, ndx, STR_TAG);

	if (tag) {
	    pos = (file - tag) - TAG_CODE_LEN;

	    if (pos < LIST_COMM_SIZE) {
		strncpy(out, tag, pos + 1);
		out[pos] = ZCHAR;
	    }
	} else {
	    if (lst->listview == TAG_FILE_PREF)
		strcpy(out, file_from_path(file));
	    else
		strcpy(out, file);
	}
	break;

    case FILE_ONLY_PREF:
	strcpy(out, file_from_path(file));
	break;

    case PATH_FILE_PREF:
    default:
	strcpy(out, file);
	break;
    }
}

void get_sort_id(char *in, char *out)
{
    char *file, *tag;
    int pos;

    if (!in)
	return;

    tag = NULL;
    *out = ZCHAR;
    file = grep_str(TAG_CODE, in);

    if (!file)
	file = in;
    else
	tag = in;

    switch (sort_mode) {
    case TAG_FILE_PREF:
    case TAG_PATH_PREF:
	if (tag) {
	    pos = (file - tag) - TAG_CODE_LEN;
	    
	    if (pos < LIST_COMM_SIZE) {
		strncpy(out, in, pos + 1);
		out[pos] = ZCHAR;
	    }
	} else {
	    if (sort_mode == TAG_FILE_PREF)
		strcpy(out, file_from_path(in));
	    else
		strcpy(out, in);
	}
	break;

    case FILE_ONLY_PREF:
	strcpy(out, file_from_path(file));
	break;

    case PATH_FILE_PREF:
    default:
	strcpy(out, file);
	break;
    }
}

void /* user */ add_file_to_list()
{
    char *file, tmpfl[COMM_SIZE];
    struct stat sstat;
    int ndx;

    ndx = 1;
    file = g_dbuf(args, ndx++);

    if (!file) {
	print_cmnd_help(ADD_FILE_TO_LIST);
	return;
    }

    if (!edit_list) {
	show_user(DEBUG_MSG " Edit list undefined");
	return;
    }

    while (file) {
	if (is_url(file))
	    add_stream(file, edit_list->dcb, FALSE, read_file_tags);
	else {
	    if (*file != '/') {
		sprintf(tmpfl, "%s/%s", c_path, file);
		file = tmpfl;
	    }

	    if (stat(file, &sstat))
		show_user(ERROR_MSG " Error reading file \"%s\" : %s",
			  file, strerror(errno));
	    else if (sstat.st_mode & S_IFDIR)
		show_user(DEBUG_MSG " \"%s\" is a directory", file);
	    else {
		if (check_format(file))
		    add_stream(file, edit_list->dcb, FALSE, read_file_tags);
		else
		    show_user(DEBUG_MSG
			      " No suitable player defined for \"%s\"", file);
	    }
	}
	file = g_dbuf(args, ndx++);
    }

    update_list_env();
}

int d_chck(mode_t mode)
{
    if ((mode & S_IFDIR) && !(mode & S_IFLNK))
	return TRUE;
    else
	return FALSE;
}

void add_dir(int add_d, DCharBuf * pplist, DCharBuf * lst)
{
    struct dirent *dirent;
    struct stat sstat;
    DIR *dirstr;
    char *dir, *fname;

    dir = g_dbuf(pplist, 0);

    if (!dir)
	return;

    if (chdir(dir))
	show_user(ERROR_MSG " Failed to read \"%s\" : %s", dir,
		  strerror(errno));
    else {
	dirstr = opendir(".");

	if (!dirstr) 
	    show_user(ERROR_MSG " Failed to open \"%s\" : %s", dir,
		      strerror(errno));
	else {
	    getcwd(search_dir, PATH_MAX);
	    dirent = readdir(dirstr);

	    while (dirent) {
		fname = dirent->d_name;
		if (strcmp(fname, ".") != 0 && strcmp(fname, "..") != 0) {
		    lstat(fname, &sstat);
		    if (d_chck(sstat.st_mode)) {
			if (add_d) {
			    sprintf(tmpstr_st, "%s/%s", search_dir, fname);
			    a_dbuf(pplist, tmpstr_st);
			}
		    } else if (check_format(fname)) {
			sprintf(tmpstr_st, "%s/%s", search_dir, fname);
			add_stream(tmpstr_st, lst, FALSE, read_file_tags);
		    }
		}
		dirent = readdir(dirstr);
	    }
	    closedir(dirstr);
	}   
    }

    r_dbuf(pplist, 0);
}

void /* user */ add_dir_comm()
{
    DCharBuf *plist, *files, *dcb;
    int i, len, rec;
    char *dir;

    if (!edit_list) {
	show_user(DEBUG_MSG " Edit list undefined");
	return;
    }

    rec = FALSE;
    dir = g_dbuf(args, 1);

    if (!dir)
	dir = c_path;

    if (strcmp(com[ADD_DIR_RECURSE].name, g_dbuf(args, 0)) == 0)
	rec = TRUE;

    plist = i_dbuf("temp", 256, DCHAR_GROW);
    files = i_dbuf("files", LIST_SIZE, DCHAR_GROW);

    a_dbuf(plist, dir);

    if (rec)
	show_user(STATUS_MSG
		  " Recursively adding playable files in \"%s\" ...", dir);
    else
	show_user(STATUS_MSG " Adding playable files in \"%s\" ...", dir);

    while (plist->len > 0)
	add_dir(rec, plist, files);

    chdir(c_path);

    if (files->len) {
	dcb = edit_list->dcb;
	len = files->len;

	if (len > 1) {
	    sort_mode = edit_list->listview;
	    qsort((void *) files->buf, len, sizeof(DCBNode), compare_list);
	}

	for (i = 0; i < len; i++)
	    a_dbuf(dcb, g_dbuf(files, i));

	update_list_env();
	show_user(STATUS_MSG " Added %d file(s) to \"%s\" list", len,
		  dcb->name);
    } else
	show_user(DEBUG_MSG " No playable file(s) found in \"%s\"", dir);

    f_dbuf(files);
    f_dbuf(plist);
}
