/*
    This file is part of audtty, copyright 2008-2010 Chris Taylor.

    audtty 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.

    audtty 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 audtty; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*/

#include <audacious/audctrl.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <ncursesw/curses.h>
#include <sys/stat.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <unistd.h>
#include "main.h"
#include "dbus.h"
#include "settings.h"
#include "kbd_constants.h"
#include "curses_printf.h"
#include "browse.h"

win browser;
controller cont;
extern struct timespec interval;

int sort_abc(const void *x, const void *y) {
  return (g_strcmp0(*(const char **)x, *(const char **)y));
}


void get_contents( void );
void swap(gchar** tmp1, gchar** tmp2);
void browser_paint(controller *display);
gboolean check_dir( void );
void add_file(gboolean dir);
void remove_win( void );
void display_error(gchar *message, gchar *name, gboolean type);
void open_directory( void );


void file_browser(gint height)
{
	cont.height=height;
	gint c;
        cont.files=(files*)malloc(sizeof(files)*2000);
	cont.location=g_get_current_dir();
        g_chdir(cont.location);
        cont.selector=0;
	cont.length = 1;
	cont.first=0;
	cont.pos_height=0;
	clear();
	refresh();

	browser.location = newwin(1, 0, 0, 0);
	browser.title = newwin(1, 0, 1, 0);
	browser.list = newwin(cont.height, 0, 3, 0);


	wcolor_set(browser.location, 1, NULL);
	wcolor_set(browser.title, 1, NULL);
	wcolor_set(browser.list, 1, NULL);

	mvwtitledhline(browser.title, 0, "File Browser");
	wnoutrefresh(browser.title);
	wnoutrefresh(browser.list);

	doupdate();


	get_contents();
	browser_paint(&cont);

	while((c=getch()))
	{
		switch(c)
		{
			case 'q':
			case 'k':
			case ESCAPE:
				remove_win();
				return;
			case KEY_DOWN:
				if( cont.selector < (cont.length - 1) )
				{
					++(cont.selector);
					browser_paint(&cont);
				}
				break;
			case KEY_UP:
				if ( cont.selector > 0 )
				{
					--(cont.selector);
					browser_paint(&cont);
				}
				break;
			case KEY_NPAGE:
				cont.selector+=cont.height;
				cont.pos_height=0;
				if(cont.selector>=cont.length)
					cont.selector = cont.length-1;
				cont.first=cont.selector;
				browser_paint(&cont);
				break;
			case KEY_PPAGE:
				cont.selector-=cont.height;
				cont.pos_height=0;
				if(cont.selector<0)
					cont.selector = 0;
				cont.first=cont.selector;
				browser_paint(&cont);
				break;
			case KEY_HOME:
				cont.pos_height=0;
				cont.selector=0;
				cont.first=0;
				browser_paint(&cont);
				break;
			case KEY_END:
				cont.pos_height=0;
				cont.selector=cont.length-1;
				cont.first=cont.selector;
				browser_paint(&cont);
				break;
                        case 'o':
                        case 'O':
                                open_directory();
                                break;
                        case 'a':
			case 'A':
				add_file(TRUE);
				break;
			case ENTER:
				add_file(FALSE);
				get_contents();
				break;
			default:
				break;
		}
	}
	return;
}

void get_contents( void )
{
        gint count=2;
        gint i=0;
        gchar *name;
        GDir *dir;
	GError *open_error=NULL;
        

        cont.first=0;
	cont.pos_height=0;

	werase(browser.location);
	doupdate();
	waddstr(browser.location, "Current Directory: ");
	waddstr(browser.location, g_get_current_dir());
	wnoutrefresh(browser.location);

        for(i=0;i<=cont.length+1;i++)
        {
            cont.files[i].file=NULL;
        }

	dir = g_dir_open(cont.location,0,&open_error);
        if(!dir)
        {
            display_error(open_error->message, cont.location, true);
            g_error_free(open_error);
            return;
        }
        else
        {
            cont.files[0].file=".";
            cont.files[1].file="..";
            while((name=(gchar*)g_dir_read_name(dir)))
            {
                    GError *convert_error=NULL;
                    cont.files[count].file=g_filename_to_utf8(name,-1,NULL,NULL,&convert_error);
                    if(convert_error)
                    {
                        cont.files[count].file=name;
                        display_error(convert_error->message, name, false);
                    }
                    if(convert_error!=NULL)
                        g_error_free(convert_error);
                    count++;
            }
            cont.length=count;
            qsort(cont.files, cont.length, sizeof(files), &sort_abc);
            g_dir_close(dir);
        }
        browser_paint(&cont);
        g_free(name);
}

gboolean check_dir( void )
{
	struct stat statbuf;
	gchar *temp;

	temp = g_strjoin("/",cont.location,cont.files[cont.selector].file,NULL);
	stat(temp,&statbuf);

	if(S_ISDIR(statbuf.st_mode)) {
		g_free(temp);
		return TRUE;
	}
	else {
		g_free(temp);
		return FALSE;
	}
}

void add_file(gboolean dir)
{
	if(dir)
	{
		if(g_strcmp0(cont.files[cont.selector].file,".")==0)
			flash();
		else
		{
			gchar *temp;
			gchar *uri = NULL;

			temp = g_strjoin("/",cont.location,cont.files[cont.selector].file,NULL);

			uri = g_filename_to_uri(temp, NULL, NULL);
			audacious_remote_playlist_add_url_string(dbus_proxy,uri);
			g_free(temp);
                        g_free(uri);
                        return;
		}
	}
	else
	{
		if(g_strcmp0(cont.files[cont.selector].file,".")==0)
			flash();
                else if(g_strcmp0(cont.files[cont.selector].file,"..")==0)
		{
			g_chdir("..");
                        cont.location=g_strdup(g_get_current_dir());
                        cont.selector=1;
			get_contents();
		}
		else if(check_dir())
		{
			cont.location = g_strdup(g_strjoin("/",cont.location,cont.files[cont.selector].file,NULL));

			g_chdir(cont.location);
			cont.selector=1;
			get_contents();
		}
		else
		{
			gchar *temp;
			gchar *uri = NULL;

			temp = g_strjoin("/",cont.location,cont.files[cont.selector].file,NULL);

			uri = g_filename_to_uri(temp, NULL, NULL);
			audacious_remote_playlist_add_url_string(dbus_proxy,uri);
			g_free(temp);
                        g_free(uri);
		}
	}
}

void remove_win( void )
{
        g_free(cont.files);
	delwin(browser.title);
	delwin(browser.list);
	delwin(browser.location);
	doupdate();
	mainwin_repaint();
}

void browser_paint(controller *display)
{
	gint i,last;
	last=display->first+(display->height-1);

	if(display->selector<display->prev_pos)
	{
		--display->pos_height;
		if(display->selector<display->first)
		{
			display->pos_height=0;
			--display->first;
			if(display->first<0)
				display->first=0;
                }
	}
        else if(display->selector>display->prev_pos)
	{
		++display->pos_height;
		if(display->selector>last)
		{
			++display->first;
			display->pos_height=display->height;
		}
	}
	for(i=0;i<display->height;i++)
	{
                gint show_file=display->first+i;
		if(display->files[show_file].file!=NULL)
		{
                    mvwaddstr(browser.list,i,0,display->files[show_file].file);
                    wclrtoeol(browser.list);

                    if(i==0)
                        wclrtobot(browser.list);

                    if (show_file == display->selector)
                        mvwchgat(browser.list, i, 0, -1, A_REVERSE, 2, NULL);
                    else
			mvwchgat(browser.list, i, 0, -1, A_NORMAL, 1, NULL);
		}
	}
	display->prev_pos=display->selector;
	wnoutrefresh(browser.list);
	doupdate();
}

void display_error(gchar *message, gchar *name, gboolean type)
{
    gint c,i;
    werase(browser.list);
    for(i=0;i<(cont.height/2)-3;i++)
        waddstr(browser.list,"\n");
    waddstr(browser.list,message);
    waddstr(browser.list,"\n");
    waddstr(browser.list,"\n");
    if(type)
    {
        waddstr(browser.list,"Failed to open directory: ");
        waddstr(browser.list,name);
    }
    else
    {
        waddstr(browser.list,"Failed to convert filename: ");
        waddstr(browser.list,name);
    }
    waddstr(browser.list,"\n");
    waddstr(browser.list,"\n");
    if(type)
            waddstr(browser.list,"Hit enter twice to move up one directory.");
    else
            waddstr(browser.list,"Hit enter twice to continue.");
    wnoutrefresh(browser.list);
    doupdate();
    while((c=getch()))
    {
        switch(c)
        {
                    case ENTER:
                           if(type)
                            {
                                g_chdir("..");
                                cont.location=g_strdup(g_get_current_dir());
                            }
                            werase(browser.list);
                            wnoutrefresh(browser.list);
                            doupdate();
                            return;
        }
    }
    return;
}

void open_directory( void )
{
        gint len = 0;
	gchar buffer[1024];
	buffer[0] = '\0';
	while (true) {
		gint c;

		while((c = getch()) != ERR) {
			switch (c) {
				case ESCAPE:
                                        get_contents();
                                        return;
				case ENTER:
                                        cont.location=g_strdup(buffer);
                                        g_chdir(buffer);
                                        get_contents();
                                        return;
				case KEY_BACKSPACE:
					if (len == 0) break;
					buffer[--len] = '\0';
					break;
				default:
					if (len == 1025) break;
					if (c < 32) break;
					buffer[len] = c;
					buffer[++len] = '\0';
					break;
			}
		}

		gint x, y;
		mvwaddnstrf(browser.location, 0, 0, "Open Directory: %s", -1, buffer);
		getyx(browser.location, y, x);
		wclrtoeol(browser.location);
		mvwchgat(browser.location, 0, 0, -1, A_BOLD, 1, NULL);
		wnoutrefresh(browser.location);

		doupdate();
    }
    return;
}