/*
 *  lxmms2.c - A program to control XMMS2 with a 
 *  LIRC compatible IR remote control.
 *
 *  Copyright (c) 2005-2010 Johannes Heimansberg
 *  http://wejp.k.vu/
 *
 *  Released under the GNU General Public License v2
 *  (See COPYING file for details.)
 */
#define VERSION "0.1.3"
#define DEBUG

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <errno.h>
#include <unistd.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <lirc/lirc_client.h>
#include <xmmsclient/xmmsclient.h>

#define TRUE 1
#define FALSE 0
#define SUCCESS 1
#define FAILURE 2

static int connected = FALSE;

void xmms2_disconnect_cb(void *userdata)
{
	connected = FALSE;
	printf("Connection to xmms2d lost.\n");
}

static int xmms2_connect(xmmsc_connection_t **connection)
{
	char *path = NULL;
	int   result = FALSE;

	path = getenv("XMMS_PATH");

	/* Initialize connection to XMMS2 daemon */
	if (!xmmsc_connect(*connection, path)) {
		printf("ERROR: %s\n", xmmsc_get_last_error(*connection));
		printf("XMMS_PATH: %s\n", path);
	} else {
		printf("SUCCESS: Connected to xmms2d.\n");
		xmmsc_disconnect_callback_set(*connection, xmms2_disconnect_cb, NULL);
		result = SUCCESS;
		connected = TRUE;
	}
	return result;
}

static int xmms2_do_reljump(xmmsc_connection_t *conn, int where)
{
	xmmsc_result_t *res;
	int             result = SUCCESS;

	if (connected) {
		res = xmmsc_playlist_set_next_rel(conn, where);
		xmmsc_result_wait(res);

		if (xmmsc_result_iserror(res)) {
			char *err = xmmsc_get_last_error(conn);
			fprintf(stderr, "ERROR: Couldn't advance in playlist: %s\n", err);
			if (strcmp(err, "Disconnected") == 0) result = FAILURE;
		} else {
			xmmsc_result_unref(res);
			res = xmmsc_playback_tickle(conn);
			xmmsc_result_wait(res);
			xmmsc_result_unref(res);
		}
	} else {
		result = FAILURE;
	}
	return result;
}

static int xmms2_play(xmmsc_connection_t *connection)
{
	xmmsc_result_t *res;
	int             result = SUCCESS;

	if (connected) {
		res = xmmsc_playback_start(connection);
		xmmsc_result_wait(res);
		if (xmmsc_result_iserror(res)) {
			char *err = xmmsc_get_last_error(connection);
			fprintf(stderr, "ERROR: Couldn't start playback: %s\n", err);
			if (err && strcmp(err, "Disconnected") == 0) result = FAILURE;
		} else {
			xmmsc_result_unref(res);
		}
	} else {
		result = FAILURE;
	}
	return result;
}

static int xmms2_stop(xmmsc_connection_t *connection)
{
	xmmsc_result_t *res;
	int             result = SUCCESS;

	if (connected) {
		res = xmmsc_playback_stop(connection);
		xmmsc_result_wait(res);
		if (xmmsc_result_iserror(res)) {
			char *err = xmmsc_get_last_error(connection);
			fprintf(stderr, "ERROR: Couldn't stop playback: %s\n", err);
			if (err && strcmp(err, "Disconnected") == 0) result = FAILURE;
		} else {
			xmmsc_result_unref(res);
		}
	} else {
		result = FAILURE;
	}
	return result;
}

static int xmms2_pause(xmmsc_connection_t *connection)
{
	xmmsc_result_t *res;
	int             result = SUCCESS;

	if (connected) {
		res = xmmsc_playback_pause(connection);
		xmmsc_result_wait(res);
		if (xmmsc_result_iserror(res)) {
			char *err = xmmsc_get_last_error(connection);
			fprintf(stderr, "ERROR: Couldn't pause playback: %s\n", err);
			if (err && strcmp(err, "Disconnected") == 0) result = FAILURE;
		} else {
			xmmsc_result_unref(res);
		}
	} else {
		result = FAILURE;
	}
	return result;
}

static int xmms2_toggle_pause(xmmsc_connection_t *connection, int start_playback)
{
	xmmsc_result_t *res;
	int             status = -1;
	int             result = SUCCESS;
	xmmsv_t        *val;

	if (connected) {
		res = xmmsc_playback_status(connection);
		xmmsc_result_wait(res);
		val = xmmsc_result_get_value(res);
		xmmsv_get_int(val, &status);
		xmmsc_result_unref(res);
		if (status == XMMS_PLAYBACK_STATUS_PLAY)
			result = xmms2_pause(connection);
		else if (status == XMMS_PLAYBACK_STATUS_PAUSE || start_playback == TRUE)
			result = xmms2_play(connection);
	} else {
		result = FAILURE;
	}
	return result;
}

static int xmms2_volume_get(xmmsc_connection_t *connection,
                            int *volume_l, 
                            int *volume_r)
{
	xmmsc_result_t *res;
	int             result = -1;
	xmmsv_t        *val;

	if (connected) {
		res = xmmsc_playback_volume_get(connection);
		xmmsc_result_wait(res);
		val = xmmsc_result_get_value(res);

		if (xmmsc_result_iserror(res)) {
			fprintf(stderr, "ERROR: Couldn't get config value.\n");
		} else if (!xmmsv_is_error(val)) {
			xmmsv_dict_entry_get_int(val, "left", volume_l);
			xmmsv_dict_entry_get_int(val, "left", volume_r);
			result = SUCCESS;
		}
		xmmsc_result_unref(res);
	} else {
		result = FAILURE;
	}
	return result;
}

static int xmms2_volume_set(xmmsc_connection_t *connection,
                            int volume_l, int volume_r)
{
	xmmsc_result_t *res;
	int             result = SUCCESS;

	if (connected) {
		res = xmmsc_playback_volume_set(connection, "left",  volume_l);
		xmmsc_result_wait(res);
		xmmsc_result_unref(res);
		res = xmmsc_playback_volume_set(connection, "right", volume_r);
		xmmsc_result_wait(res);
		xmmsc_result_unref(res);
	} else {
		result = FAILURE;
	}

	return result;
}

static int xmms2_volume_up(xmmsc_connection_t *connection)
{
	int volume_l, volume_r, result = SUCCESS;

	if (xmms2_volume_get(connection, &volume_l, &volume_r) == SUCCESS) {
		volume_l += 4;
		volume_r += 4;
		if (volume_l <= 100 && volume_r <= 100)
			result = xmms2_volume_set(connection, volume_l, volume_r);
	} else {
		result = FAILURE;
	}

	return result;
}

static int xmms2_volume_down(xmmsc_connection_t *connection)
{
	int volume_l, volume_r, result = SUCCESS;

	if (xmms2_volume_get(connection, &volume_l, &volume_r) == SUCCESS) {
		volume_l -= 4;
		volume_r -= 4;
		if (volume_l >= 0 && volume_r >= 0)
			result = xmms2_volume_set(connection, volume_l, volume_r);
	} else {
		result = FAILURE;
	}

	return result;
}

int main(int argc, char *argv[])
{
	xmmsc_connection_t *connection = NULL;
	struct lirc_config *config;

	printf("lxmms2 v%s Copyright (c) 2005-2010 Johannes Heimansberg " \
	       "( http://wejp.k.vu/ )\n", VERSION);

	connection = xmmsc_init("lxmms2");

	if (lirc_init("lxmms2", 1) == -1)
		exit(EXIT_FAILURE);

	if (xmms2_connect(&connection) == FALSE)
		exit(EXIT_FAILURE);

	if (lirc_readconfig(argc == 2 ? argv[1] : NULL, &config, NULL) == 0) {
		char *code, *c;
		int  ret, result = SUCCESS;

		while (lirc_nextcode(&code) == 0 && result == SUCCESS) {
			if (code == NULL) continue;
			if ((ret = lirc_code2char(config, code, &c)) == 0 && c != NULL) {
				if (strcmp(c, "play") == 0)
					result = xmms2_play(connection);					
				else if (strcmp(c, "pause") == 0)
					result = xmms2_pause(connection);
				else if (strcmp(c, "stop") == 0)
					result = xmms2_stop(connection);
				else if (strcmp(c, "toggle_pause") == 0)
					result = xmms2_toggle_pause(connection, FALSE);
				else if (strcmp(c, "toggle_play_pause") == 0)
					result = xmms2_toggle_pause(connection, TRUE);
				else if (strcmp(c, "next") == 0)
					result = xmms2_do_reljump(connection, 1);				
				else if (strcmp(c, "prev") == 0)
					result = xmms2_do_reljump(connection, -1);
				else if (strcmp(c, "volume_up") == 0)
					result = xmms2_volume_up(connection);
				else if (strcmp(c, "volume_down") == 0)
					result = xmms2_volume_down(connection);
				else
					printf("Unknown command: %s\n", c);
				usleep(500);
				c = NULL;
			}
			free(code);
			if (ret == -1) break;
		}
		lirc_freeconfig(config);
	}
	lirc_deinit();
	exit(EXIT_SUCCESS);
}
