/*
 *  file.c - Handles directory browsing.
 *
 *  (C) 1994 Mikael Nordqvist (d91mn@efd.lth.se, mech@df.lth.se)
 */

#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include "mod.h"

extern struct options opt;
extern int nr_songs;

struct mod_file *files=0;   /* Array of files */
char *file_names=0;         /* Space to store filenames in */

int nr_files; /* Includes directories */
int nr_dirs;  /* Directories only     */

static char *tmp_workdir;   /* The dir we are reading */

/* Alpha-sort + directories at the top (with '../' last) */

int my_alphasort(const struct dirent * const *a,
		 const struct dirent * const *b)
{
    struct stat sa, sb;

    if(!stat((*a)->d_name, &sa) &&
       !stat((*b)->d_name, &sb)) {
	if((S_ISDIR(sa.st_mode) && S_ISDIR(sb.st_mode)) ||
	   (!S_ISDIR(sa.st_mode) && !S_ISDIR(sb.st_mode))) {
	    /* Make sure .. is last of the directories */
	    if(!strcmp("..", (*a)->d_name))
		return 1;
	    else if(!strcmp("..", (*b)->d_name))
		return -1;
	    else
		return alphasort((void *)a, (void *)b);
	}
	else {
	    if(S_ISDIR(sa.st_mode))
		return -1;
	    else
		return 1;
	}
    }
    else {
	debug("Stat failed\n");
	return alphasort((void *)a, (void *)b);
    }
}


int choose_file(const struct dirent *de)
{
    if(!strcmp("/", tmp_workdir) && !strcmp("..", de->d_name))
	return 0;
    
    if(!strcmp(".", de->d_name))
	return 0;
    else
	return 1;
}


/* Read directory (workdir mus*/

void init_dir(char *dirname)
{
    int i, tmp;
    struct stat s;
    struct dirent **tmp_files;
    char *name;

    tmp_workdir=dirname;

    if(files)
	free(files);
    if(file_names)
	free(file_names);

    /* Should always be at least 1 file (..) */
    if((nr_files=scandir(dirname, &tmp_files, choose_file, my_alphasort)) < 1)
	error("scandir() failed.\n");
    
    files=(struct mod_file *)malloc(sizeof(struct mod_file)*nr_files);
    
    for(tmp=i=0; i < nr_files; ++i)
	tmp+=1+strlen(tmp_files[i]->d_name);
    
    file_names=name=(char *)malloc(tmp);
    
    nr_dirs=0;
    for(i=0; i < nr_files; ++i) {
	strcpy(name, tmp_files[i]->d_name);
	free(tmp_files[i]);
	files[i].name=name;
	files[i].options=-1; /* No options */
	if(stat(name, &s)) {
	    files[i].size=-1;  /* Invalid file */
	    files[i].dir=0;
	}
	else {
	    if(S_ISDIR(s.st_mode)) {
		files[i].dir=1;
		nr_dirs++;
	    }
	    else
		files[i].dir=0;
	    
	    files[i].size=s.st_size;
	}
	name+=1+strlen(name);
    }
    free(tmp_files);
}


/* Convert a play-list to a file-list */

void list_to_files(void)
{
    struct stat s;
    int i;

    nr_files=nr_songs;
    nr_dirs=0;
    files=(struct mod_file *)malloc(sizeof(struct mod_file)*nr_files);
    for(i=0; i < nr_files; ++i) {
	files[i].name=get_fullmodulename_ptr(i);
	files[i].dir=0;
	files[i].options=1;

	if(stat(files[i].name, &s) < 0)
	    files[i].size=-1;  /* Invalid file */
	else {
	    if(!S_ISDIR(s.st_mode))
		files[i].size=s.st_size;
	    else
		files[i].size=-1;
	}
    }
}


char *get_filestring(int nr)
{
    static char buf[81];

    if(files[nr].size >= 0) {
	if(!files[nr].dir)
	    sprintf(buf, "%7d  ", files[nr].size);
	else
	    strcpy(buf, "         ");
	
	strncat(buf, files[nr].name, 69);
	
	if(files[nr].dir)
	    strcat(buf, "/");
    }
    else {
	strcpy(buf, "      -  ");
	strncat(buf, files[nr].name, 69);
    }
    
    return buf;
}

/* Returns the filenumber of the specified directory name if it exists,
 * otherwise zero.
 */

int name_to_filenr(char *name)
{
    int i;
    for(i=0; i < nr_files; ++i)
	if(!strcmp(name, files[i].name) && files[i].dir)
	    return i;
    return 0;
}


char *get_dirnamestring(int nr)
{
    return files[nr].name;
}

/* For functions in other files */

int is_dir(int nr)
{
    return files[nr].dir;
}
