/*
    This file is part of xmms-curses, copyright 2003-2005 Knut Auvor Grythe,
    2007-2010 Chris Taylor.

    xmms-curses 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.

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

#include <audacious/audctrl.h>
#include <stdlib.h>
#include <time.h>
#include <ncursesw/curses.h>
#include <string.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <locale.h>
#include "kbd_constants.h"
#include "browse.h"
#include "connect.h"
#include "curses_printf.h"
#include "dbus.h"
#include "main.h"
#include "playlist.h"
#include "playlist_jump.h"
#include "playlist_addurl.h"
#include "settings.h"
#include "playlist_create.h"

static gchar* playing_status(void);
void mainwin_repaint(void);
static void controls(gint c);
static gchar* chans(gint nch);
void finish(void);
void window_changed(gint sig);

struct timespec interval = {0, SLEEP_TIME};
prefs settings;
windows wins;
playlist list;

DBusGProxy *dbus_proxy = NULL;
static DBusGConnection *connection = NULL;

gint main(gint argc, gchar *argv[])
{
        setlocale(LC_ALL, "");
	g_type_init();
	set_defaults();
	read_conffiles();
	arguments(argc, argv);
	check_env();
	GError *error = NULL;
	connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
	if(connection==NULL){
		printf("DBUS-Error: %s \n", error->message);
		exit(EXIT_SUCCESS);
	}
	dbus_proxy = dbus_g_proxy_new_for_name(connection, AUDACIOUS_DBUS_SERVICE,
						AUDACIOUS_DBUS_PATH,
						AUDACIOUS_DBUS_INTERFACE);
	list.pos = -1;
	list.length = -1;
	list.scrolledto = -1;
	list.song = (song*)malloc(sizeof(song));
	list.song_mask = NULL;

	(void) atexit(finish);
	(void) initscr();      // initialize the curses library
	(void) nonl();         // tell curses not to do NL->CR/NL on output
	keypad(stdscr, true);  // enable keyboard mapping
	(void) cbreak();       // take input chars one at a time, no wait for \n
	(void) noecho();       // don't echo input - in color
	(void) nodelay(stdscr, 1);
	curs_set(0);           // turn off cursor
	signal(SIGWINCH, window_changed);

	if (has_colors()) {
		start_color();
		use_default_colors();
		init_pair(1, COLOR_CYAN, COLOR_DEFAULT);
		init_pair(2, COLOR_WHITE, COLOR_BLACK);
	}

	wins.status = newwin(2, 0, 0, 0);
	wins.title = newwin(1, 0, 2, 0);
	wins.list = newwin(0, 0, 3, 0);
	wins.term_resized = false;

	wcolor_set(wins.status, 1, NULL);
	wcolor_set(wins.title, 1, NULL);
	wcolor_set(wins.list, 1, NULL);

	gint repaint = true;

	while (true) {
		gint length, prev_length, c;

		if (wins.term_resized == true) {
			wins.term_resized = false; // Unset trigger
			repaint = true;
			resize_windows();
		}

		if (!audacious_remote_is_running(dbus_proxy)) {
			while((c = getch()) != ERR) {
				if (c == 'q' || c == ESCAPE)
					exit (EXIT_SUCCESS);
			}
			werase(wins.list);
			werase(wins.status);
			werase(wins.title);
			doupdate();
			mvwtitledhline(wins.status, 0, "Audacious NOT RUNNING");
			wnoutrefresh(wins.status);
			doupdate();
			usleep(500000);
			continue;
		}


		list.prev_pos = list.pos;
		list.pos = audacious_remote_get_playlist_pos(dbus_proxy);
		prev_length = list.length;
		//prev_selector = list.selector;

		length = audacious_remote_get_playlist_length(dbus_proxy);
		if(length != list.length) {
			playlist_read(length);
		}
		if (length == 0)
			list.pos = -1;

		/* input */
		while((c = getch()) != ERR)
			controls(c);

		paint_playback();
		paint_songinfo();

		if (list.pos != list.prev_pos || list.length != prev_length) {
			list.selector = list.pos;
			playlist_paint(&list);
		}

		wnoutrefresh(wins.status);

		if (repaint) {
			repaint = false;
			mainwin_repaint();
		}

		doupdate();

		usleep(25000);
    }
    exit(EXIT_SUCCESS);               /* we're done */
}

static void controls(gint c)
{
	gint height, width;
	getmaxyx(wins.list, height, width);

	// process the command keystroke
	switch (c) {
		case 'a':
			file_browser(height);
			break;
		case 'L':
			playlist_addurl();
			break;
		case 'z':
			audacious_remote_playlist_prev(dbus_proxy);
			break;
		case 'x':
			audacious_remote_play(dbus_proxy);
			break;
		case 'c':
			audacious_remote_pause(dbus_proxy);
			break;
		case 'v':
			audacious_remote_stop(dbus_proxy);
			break;
		case 'b':
			audacious_remote_playlist_next(dbus_proxy);
			break;
		case 's':
			audacious_remote_toggle_shuffle(dbus_proxy);
			break;
		case 'r':
			audacious_remote_toggle_repeat(dbus_proxy);
			break;
		case 'j':
			playlist_jump(list);
			mainwin_repaint();
			break;
		case 'h':
			audacious_remote_main_win_toggle(dbus_proxy, false);
			break;
		case 'H':
			audacious_remote_main_win_toggle(dbus_proxy, true);
			break;
		case 'k':
			audacious_remote_quit(dbus_proxy);
			exit(EXIT_SUCCESS);
			break;
		case '+':
		case '0':
			audacious_remote_set_main_volume(dbus_proxy, audacious_remote_get_main_volume(dbus_proxy)+5);
			break;
		case '-':
		case '9':
			audacious_remote_set_main_volume(dbus_proxy, audacious_remote_get_main_volume(dbus_proxy)-5);
			break;
		case 'C':
			audacious_remote_playlist_clear(dbus_proxy);
			break;
		case KEY_LEFT:
			audacious_remote_jump_to_time(dbus_proxy, audacious_remote_get_output_time(dbus_proxy)-5000);
			break;
		case KEY_RIGHT:
			audacious_remote_jump_to_time(dbus_proxy, audacious_remote_get_output_time(dbus_proxy)+5000);
			break;
		case KEY_DOWN:
			if( list.selector < (list.length - 1) ) {
				++(list.selector);
				playlist_paint(&list);
			}
			break;
		case KEY_HOME:
			list.selector=0;
			playlist_paint(&list);
			break;
		case KEY_END:
			list.selector=list.length-1;
			playlist_paint(&list);
			break;
		case KEY_UP:
			if ( list.selector > 0 ) {
				--(list.selector);
				playlist_paint(&list);
			}
			break;
		case KEY_NPAGE:
			list.selector+=height;
			if(list.selector>=list.length)
				list.selector = list.length-1;
			playlist_paint(&list);
			break;
		case KEY_PPAGE:
			list.selector-=height;
			if(list.selector<0)
				list.selector = 0;
			playlist_paint(&list);
			break;
		case ENTER:
			audacious_remote_set_playlist_pos(dbus_proxy, list.selector);
			audacious_remote_play(dbus_proxy);
			break;
		case 'q':
		case ESCAPE:
			exit(EXIT_SUCCESS);
			break;
		case 'R':
			playlist_read(audacious_remote_get_playlist_length(dbus_proxy));
			playlist_paint(&list);
			break;
		case 'd':
			if(audacious_remote_get_playlist_length(dbus_proxy) == 0) break;
			if( (list.selector >= 0) && (audacious_remote_get_playlist_length(dbus_proxy) > 0))
                        {
                            audacious_remote_playlist_delete(dbus_proxy, list.selector);
                        }
			list.selector--;
			if(list.selector<0)
				list.selector = 0;
			playlist_read(audacious_remote_get_playlist_length(dbus_proxy));
			playlist_paint(&list);
			break;
                case 'u':
                case 'U':
                        playlist_create();
                        break;
	}
}

void paint_playback(void)
{
	gint time;
	time = audacious_remote_get_output_time(dbus_proxy)/1000;
	if(audacious_remote_get_playlist_length(dbus_proxy) > 0)
	{
		mvwaddnstrf(wins.status, 0, 0, "%s [%02i:%02i] %s", -1,
				playing_status(), time/60, time%60,
				song_title(list.pos));
	}
	else
	{
                mvwaddnstrf(wins.status, 0, 0, "%s", -1, song_title(list.pos));
	}
	wclrtoeol(wins.status);
	mvwchgat(wins.status, 0, 0, -1, A_BOLD, 1, NULL);
}

void paint_songinfo(void)
{
	if(audacious_remote_get_playlist_length(dbus_proxy) == 0)
	{
                mvwaddnstrf(wins.status, 1, 0, "%s - %s - vol: %3d%%", -1,
                        audacious_remote_is_shuffle(dbus_proxy) ? "shuffle" : "!shuffle",
                        audacious_remote_is_repeat(dbus_proxy) ? "repeat" : "!repeat",
                        audacious_remote_get_main_volume(dbus_proxy));
        }
	else
	{
		gint rate, freq, nch;
		audacious_remote_get_info(dbus_proxy, &rate, &freq, &nch);
		mvwaddnstrf(wins.status, 1, 0, "Tot %02i:%02i, %i kbps, %i KHz, %s - %s - %s - vol: %3d%%", -1,
			song_length(list.pos)/60,
			song_length(list.pos)%60,
			rate/1000, freq/1000, chans(nch),
			audacious_remote_is_shuffle(dbus_proxy) ? "shuffle" : "!shuffle",
			audacious_remote_is_repeat(dbus_proxy) ? "repeat" : "!repeat",
			audacious_remote_get_main_volume(dbus_proxy));
	}
	wclrtoeol(wins.status);
	wchgat(wins.status, -1, A_NORMAL, 1, NULL);
}

gchar* chans (gint nch)
{
	switch (nch) {
		case 1:
			return "mono";
		case 2:
			return "stereo";
		case 7:
			return "surround";
		default:
			return "stereo";
	}
	return NULL;
}

void mvwtitledhline(WINDOW *win, gint y, gchar *label)
{
	gint height, width;

	getmaxyx(win, height, width);

	mvwhline(win, y, 0, 0, width);
	mvwaddch(win, y, width/2-strlen(label)/2-1, ' ');
	waddstr(win, label);
	waddch(win, ' ');
}

static gchar* playing_status()
{
	if (audacious_remote_is_playing(dbus_proxy)) {
		if (!audacious_remote_is_paused(dbus_proxy)) {
			return("|>");
		} else {
			return("||");
		}
	} else {
		return("[]");
	}
}

void resize_windows(void)
{
	struct winsize size;
	ioctl(1, TIOCGWINSZ, &size);
	endwin();
	resizeterm(size.ws_col, size.ws_row);
	wresize(wins.status, 2, size.ws_col);
	wresize(wins.title, 1, size.ws_col);
	wresize(wins.list, size.ws_row-3, size.ws_col);
}

void mainwin_repaint(void)
{
	playlist_paint(&list);
	mvwtitledhline(wins.title, 0, "Playlist");
	wnoutrefresh(wins.title);
}

void finish()
{
    endwin();
}

void window_changed(gint sig)
{
	wins.term_resized = true;
}
