/* play_list.c 
	vi:ts=3 sw=3:
 */

/* $Id: play_list.c,v 1.7 1995/09/16 15:33:25 espie Exp espie $
 * $Log: play_list.c,v $
 * Revision 1.7  1995/09/16 15:33:25  espie
 * Bug fix.
 *
 * Revision 1.6  1995/09/07 14:33:48  espie
 * *** empty log message ***
 *
 * Revision 1.5  1995/09/05 19:21:10  espie
 * *** empty log message ***
 *
 * Revision 1.4  1995/09/03 13:39:54  espie
 * *** empty log message ***
 *
 * Revision 1.3  1995/09/02 22:20:21  espie
 * Free play_list at end.
 *
 * Revision 1.2  1995/08/27 18:43:08  espie
 * *** empty log message ***
 *
 * Revision 1.2  1995/08/14  13:26:59  espie
 * More versatile build_play_list.
 *
 * Revision 1.1  1995/07/02 17:52:39  espie
 * Initial revision
 *
 */

#include <sys/types.h>
#include <sys/stat.h>
#ifdef OSK
#include <dir.h>
#define dirent direct
#else
#ifdef __NeXT__
#include <sys/dir.h>
#include <sys/dirent.h>
#else
#include <dirent.h>
#endif
#endif

#ifdef IS_POSIX
#include <time.h>
#else
#ifdef AMIGA
#include <time.h>
#else
#include <sys/time.h>
#endif
#endif

#ifndef S_ISDIR
#define S_ISDIR(p) ((p) & S_IFDIR)
#endif
#ifdef AMIGA
#include <proto/dos.h>
#endif
#include "defs.h"
#include "extern.h"
#include "play_list.h"


/* n = random_range(max): output a number in the range 0:max - 1.
 * For our purpose, we don't have to get a very random number,
 * so the standard generator is alright.
 */
LOCAL int random_range(max)
int max;
    {
    static init = 0;

        /* initialize the generator to an appropriate seed eventually */
    if (!init)
        {
        srand(time(0));
        init = 1;
        }
    return rand()%max;
    }

LOCAL struct play_entry *new_entry(dir, name)
char *dir;
char *name;
	{
	int i;
	struct play_entry *new;

	if (dir)
		{
		i = strlen(name) + strlen(dir)+1; /* note + 1 only since char name[1] */
		if ( (new = malloc(sizeof(struct play_entry) + sizeof(char) * i)) )
			{
#ifdef AMIGA
         strcpy(new->name, dir);
         if (!AddPart(new->name, name, i+1))
            return 0;
#else
			sprintf(new->name, "%s/%s", dir, name);
#endif
			new->filename = new->name;
			new->filetype = UNKNOWN;
			}
		}
	else if ( (new = malloc(sizeof(struct play_entry))) )
		{
		new->filename = name;
		new->filetype = UNKNOWN;
		}
	return new;
	}

LOCAL ENTRY *table;
LOCAL int idx, size;

LOCAL void free_play_list()
	{
	int i;

	for (i = 0; i < idx; i++)
		free(table[i]);
	free(table);
	size = idx = 0;
	}

#define CHUNK 500

LOCAL void check_bounds()
	{
	ENTRY *oldtable;
	if (idx >= size)
		{
		oldtable = table;
		size += CHUNK;
		table = malloc(sizeof(ENTRY) * size);
		if (table)
			memcpy(table, oldtable, sizeof(ENTRY) * (size - CHUNK));
		if (oldtable)
			free(oldtable);
		}
	}

LOCAL int is_dir(name)
char *name;
	{
	struct stat buf;

	if (stat(name, &buf))
		return 0;
	return S_ISDIR(buf.st_mode);
	}

LOCAL void expand_dir(name)
char *name;
	{
	DIR *dir;
	struct dirent *de;
	ENTRY new;
	
	if ( (dir = opendir(name)) )
		{
		while ( (de = readdir(dir)) )
			{
			if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
				continue;
			new = new_entry(name, de->d_name);
			if (new)
				{
				if (is_dir(new->filename))
					{
					expand_dir(new->filename);
					free(new);
					}
				else
					{
					check_bounds();
					table[idx++] = new;
					}
				}
			}
		closedir(dir);
		}
	}

ENTRY *obtain_play_list()
	{
	int i;

	at_end(free_play_list);

	check_bounds();
	table[idx] = 0;
	printf("Total files: %d\n", idx);
	return table;
	}

void add_play_list(name)
char *name;
	{
	check_bounds();
	if (is_dir(name))
		expand_dir(name);
	else
		table[idx++] = new_entry(0, name);
	}

int last_entry_index()
	{
	return idx - 1;
	}

void delete_entry(entry)
ENTRY *entry;
	{
	int n;
	ENTRY old;

	old = *entry;
	n = idx - (entry - table) - 1;

	memmove(entry, entry+1, n * sizeof(ENTRY));
	idx--;
	free(old);
	}

void randomize()
	{
	ENTRY e;
	int i, k;

	for (i = idx-1; i > 0; i--)
		{
		k = random_range(i+1);
		e = table[k];
		table[k] = table[i];
		table[i] = e;
		}
	}

