/*-*-linux-c-*-*/

/*
 *  gnewtellium - Newtella for Unix
 *  Copyright (C) 2001 Elias Athanasopoulos
 *
 *  01/07/2001 - patch to include subdirectories with mp3s
 *               when selecting a shared directory
 *               Flavio Catalani <f.catalani@libero.it>
 *
 *  02/07/2001 - POSIX handling of directories
 *               by Kervin Pierre <kpierre@fit.edu>  
 *
 *  This program is free software; you can redistribute 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.
 *
 *  This program 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 received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/* Not to be mistaken with "config.h" */
#include "../config.h"

#include <string.h>

#if HAVE_DIRENT_H
#	include <dirent.h>
#	define NAMLEN(dirent) strlen((dirent)->d_name)
#else
#	define dirent direct
#	define NAMLEN(dirent) (dirent)->d_namlen
#	if HAVE_SYS_NDIR_H
#		include <sys/ndir.h>
#	endif
#	if HAVE_SYS_DIR_H
#		include <sys/dir.h>
#	endif
#	if HAVE_NDIR_H
#		include <ndir.h>
#	endif
#endif


#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <ctype.h>

#include <gtk/gtk.h>

#include "file.h"
#include "global.h"

#include "memory.h"

#include "newtella.h"

guint32 file_hashpjw (void *s, int len)
{
	/* taken from gnubile */
	const char *p;
	unsigned long int h;
	unsigned long topnibble;

	h = 479001599; /* start things with a very large prime. */

	for (p = (char*) s; len; p++, len--)
	{
		h = (h << 4) + *p;
		topnibble = h & 0xf0000000;
		h = h ^ (topnibble >> 24) ^ topnibble;
	}
	return h;
}


gint file_is_mp3(gchar *filename)
{
        return (!strncasecmp(filename+strlen(filename)-4, ".mp3", 4));
}

gint file_has_ending(gchar *filename)
{
        return (!strncasecmp(filename+strlen(filename)-2, ".", 1)||!strncasecmp(filename+strlen(filename)-3, ".", 1)||!strncasecmp(filename+strlen(filename)-4, ".", 1)||!strncasecmp(filename+strlen(filename)-5, ".", 1)||!strncasecmp(filename+strlen(filename)-6, ".", 1));
}

guint32 file_get_size(gchar *file_name, gchar *path)
{
	gchar *s = newtella_malloc(1024);
	struct stat *fs = newtella_malloc(sizeof(struct stat));
	guint32 file_size = 0;

	strncpy(s, path, 1024);

	if (s[strlen(s)-1] != '/')
		s = strcat(s, "/");

	s = strcat(s, file_name);
	stat(s, fs);
	file_size = fs->st_size;

	newtella_free(fs);
	newtella_free(s);

	return file_size;
}

GList *file_extract_keywords(char *s)
{
	char *t, *key;
        GList *keywords = NULL;

        while((t = memchr(s, ' ', strlen(s)))) {
                *t++ = 0;
                key = newtella_malloc(255);
                strncpy(key, s, 255);

                /* valid keyword? */
                if (strlen(key) > 2)
                        keywords = g_list_append(keywords, (char *) key);
		else
			newtella_free(key);

		/* next keyword */
                strcpy(s, t);
        };

        /* last keyword */
        key = newtella_malloc(255);
        strncpy(key, s, 255);

        /* valid keyword? */
        if (strlen(key) > 2)
                keywords = g_list_append(keywords, (char *) key);
	else
		newtella_free(key);

	return keywords;
}

void file_name_to_low(char *s)
{
	char *t;

	t = s;

	do {
		if (isalpha(*t))
			*t = tolower(*t);
	} while (*t++ != '\0');
}

/* TODO: Handle circular links.*/
int file_build_db(char *path)
{
	struct dirent *de;
        DIR *share_dir;
        struct file_entry *fe;
        char pathcp[PATH_MAX];
	struct stat stat_struct;

        share_dir = opendir(path);

        if (!share_dir) {
                perror("opendir");
                return -1;
        }


        while ((de = readdir(share_dir))) {
                if (strcmp(de->d_name, ".") && strcmp(de->d_name, ".."))
                {
			memset(pathcp, 0, PATH_MAX);
        		strncpy(pathcp, path, PATH_MAX);
			strcat(pathcp, de->d_name);     /* to pathcp. */

                        /* include sub directories with mp3s
			   Flavio Catalani <f.catalani@libero.it> */
			if(stat(pathcp, &stat_struct)==-1) {
				perror("stat: ");
				g_print("number error %d on '%s'.", errno, pathcp);
				return -1;
			} /* Is what we found a dir? */
			else if (S_ISDIR(stat_struct.st_mode)) {
                                strcat(pathcp, "/");
                                if (!file_build_db(pathcp)) {
                                        perror("opendir");
                                        return -1;
                                }
                        }

			if (file_has_ending(de->d_name)) {
                                fe = newtella_malloc(sizeof(struct file_entry));
                                fe->name = newtella_malloc(PATH_MAX);
                                fe->path = newtella_malloc(PATH_MAX);
                                strncpy(fe->name, de->d_name, PATH_MAX);
                                strncpy(fe->path, path, PATH_MAX);
				// Igor: Wurde auskommentiert, da Dateien mit Großbuchstaben nicht korrekt behandelt wurden
				//file_name_to_low(fe->name);
                                fe->index = file_hashpjw(fe->name, 15);
                                fe->size = file_get_size(fe->name, fe->path);
                                gl_file_db = g_list_append(gl_file_db, fe);
				// Igor: Hier wird jetzt neu die Anzahl und Gesamtgröße der Dateien eingetragen
				gl_my_host_info->file_count = gl_my_host_info->file_count + 1;
				gl_my_host_info->files_total_size += fe->size;
                        }
                }
        }

	// Igor: Größe in KB
	gl_my_host_info->files_total_size = gl_my_host_info->files_total_size / 1024;

	closedir(share_dir);

	return 1;
}

int file_exclude_from_db(char *path)
{
	struct file_entry *fe;
	GList *iter;

	iter = g_list_first(gl_file_db);
	while (iter) {
		fe = iter->data;

		if (!strcmp(fe->path, path)) {
			gl_file_db = g_list_remove(gl_file_db, fe);
			newtella_free(fe);
			iter = g_list_first(gl_file_db);
		} else
			iter = g_list_next(iter);
	}

	return 1;
}

GList *file_scan_db(char *key)
{
	struct file_entry *fe;
	GList *iter, *found_hits = NULL;
	char *name;

	file_name_to_low(key);

	iter = g_list_first(gl_file_db);
	while (iter) {
		fe = iter->data;

		// Igor: Hier wird der Name in Kleinbuchstaben umgewandelt, damit er die keywords richtig erkennt
		name = malloc(strlen(fe->name) + 1);
		memcpy(name, fe->name, strlen(fe->name) + 1);
		file_name_to_low(name);

		//if (strstr(fe->name, key)) { (s.o.)
		if (strstr(name, key)) {
			found_hits = g_list_append(found_hits, fe);
		}

		free(name);
		iter = iter->next;
	}

	return found_hits;
}
