/*
 * GQmpeg
 * (C)1998, 1999 John Ellis
 *
 * Author: John Ellis
 *
 * This software is released under the GNU General Public License.
 * Please read the included file COPYING for more information.
 * This software comes with no warranty of any kind, use at you own risk!
 */

#include "gqmpeg.h"
#include <fcntl.h>
#include <errno.h>

/* note:
 * this is really cheesy right now, basically to send a command to a running
 * gqmpeg, place a command in ~/.gqmpeg/command
 * the best way would be:
 *   echo "play" > ~/.gqmpeg/commands
 * the file only exists when gqmpeg is accepting commands.
 * the file is checked every 1/10th second.
 */

#define GQMPEG_FILE_IPC_COMMAND ".gqmpeg/command"
#define GQMPEG_FILE_IPC_LOCK ".gqmpeg/command.pid"

static gint ipc_fd_id = -1;
static FILE *ipc_file_id = NULL;
static gint ipc_cb_id = -1;
static gchar *ipc_file = NULL;

static gint pid_lock_file_create()
{
	FILE *f;
	gchar *lock_file;

	lock_file = g_strconcat(homedir(), "/", GQMPEG_FILE_IPC_LOCK, NULL);

	f = fopen(lock_file, "w");
	if (!f)
		{
		printf("error opening file for write %s\n", lock_file);
		g_free(lock_file);
		return FALSE;
		}

	g_free(lock_file);

	fprintf(f, "%d\n", (int)getpid());
	fclose(f);

	return TRUE;
}

static void pid_lock_file_destroy()
{
	gchar *lock_file;

	lock_file = g_strconcat(homedir(), "/", GQMPEG_FILE_IPC_LOCK, NULL);
	if (isfile(lock_file))
		{
		unlink(lock_file);
		}

	g_free(lock_file);
}

static gint pid_lock_file_locked()
{
	FILE *f;
	gchar *lock_file;
	gchar buf[64];
        pid_t pid_v = -1;

	lock_file = g_strconcat(homedir(), "/", GQMPEG_FILE_IPC_LOCK, NULL);

        f = fopen(lock_file, "r");
	g_free(lock_file);
        if(!f) return FALSE;

	if (fgets(buf, sizeof(buf), f) == NULL)
		{
		fclose(f);
		return FALSE;
		}

        fclose(f);

	pid_v = (pid_t)strtol(buf, NULL, 10);
	if (pid_v < 1 || (kill (pid_v, 0) == -1 && errno != EPERM)) return FALSE;

	return TRUE;
}

void ipc_send(gchar *command)
{
	FILE *f;

	if (ipc_file)
		{
		f = fopen(ipc_file, "w");
		}
	else
		{
		gchar *path = g_strconcat(homedir(), "/.gqmpeg/command", NULL);
		f = fopen(path, "w"); /* blocking, huh ? */
		g_free(path);
		}

	if (!f)
		{
		printf("error opening command file for write %s\n", ipc_file);
		return;
		}

	fprintf(f, "%s\n", command);

	fclose(f);
}

static gint ipc_read_data()
{
	gchar i_buf[1025];
	i_buf[1024] = '\0'; /* paranoid safety */

	while (fgets(i_buf, 1024, ipc_file_id))
		{
		if (debug_mode) printf("data_read_from_ipc\n");
		if (!strncmp(i_buf, "play_file", 9) && strlen(i_buf) > 10)
			{
			gchar *buf = quoted_value(i_buf + 10);
			if (is_playlist(buf))
				{
				playlist_load_from_file(buf, FALSE, TRUE);
				}
			else
				{
				current_song_set_and_play(-1, buf);
				}
			g_free(buf);
			}
		else if (!strncmp(i_buf, "play", 4))
			{
			btn_play_pressed();
			}
		else if (!strncmp(i_buf, "stop", 4))
			{
			btn_stop_pressed();
			}
		else if (!strncmp(i_buf, "pause", 5))
			{
			btn_pause_pressed();
			}
		else if (!strncmp(i_buf, "next", 4))
			{
			btn_next_down();
			btn_next_pressed();
			}
		else if (!strncmp(i_buf, "prev", 4))
			{
			btn_prev_down();
			btn_prev_pressed();
			}
		else if (!strncmp(i_buf, "pladd_play", 10) && strlen(i_buf) > 11)
			{
			gchar *buf = quoted_value(i_buf + 11);
			playlist_add(buf);
			g_free(buf);

			current_song_set_and_play(playlist_get_count() - 1, NULL);
			}
		else if (!strncmp(i_buf, "pladd", 5) && strlen(i_buf) > 6)
			{
			gchar *buf = quoted_value(i_buf + 6);
			playlist_add(buf);
			g_free(buf);
			}
		else if (!strncmp(i_buf, "plrm", 4) && strlen(i_buf) > 5)
			{
			gchar *buf = quoted_value(i_buf + 5);
			playlist_remove(buf, -1, TRUE);
			g_free(buf);
			}
		else if (!strncmp(i_buf, "plclr", 4))
			{
			playlist_clear();
			}
		else if (!strncmp(i_buf, "plload", 6) && strlen(i_buf) > 7)
			{
			gchar *buf = quoted_value(i_buf + 7);
			playlist_load_from_file(buf, FALSE, FALSE);
			g_free(buf);
			}
		else if (!strncmp(i_buf, "plappend", 8) && strlen(i_buf) > 9)
			{
			gchar *buf = quoted_value(i_buf + 9);
			playlist_load_from_file(buf, TRUE, FALSE);
			g_free(buf);
			}
		else if (!strncmp(i_buf, "help", 4))
			{
			printf("available ipc commands:\n");
			printf("play, pause, stop, next, prev\n");
			printf("pladd {\"file\"|file}        add file to playlist\n");
			printf("pladd_play {\"file\"|file}   add file to playlist and play it\n");
			printf("plremove {\"file\"|file}     remove file from playlist\n");
			printf("plclr                      clear playlist\n");
			printf("plload {playlist}          load playlist\n");
			printf("plappend {playlist}        append playlist\n");
			printf("play_file {\"file\"|file}    play file, do not add to playlist\n");
			printf("                           or, if playlist, load playlist\n");
			printf("   file is a path or http://server:port\n");
			}
		else
			{
			printf("unknown ipc command: `%s'\n", i_buf);
			}
		}

	/* this appears to be needed for NetBSD */
	if (feof(ipc_file_id) != 0)
		rewind (ipc_file_id);

	return TRUE;
}

void ipc_on()
{
	if (ipc_file_id || ipc_cb_id > -1) return;

	if (pid_lock_file_locked())
		{
		printf("ipc command file already locked, ipc disabled\n");
		return;
		}

	if (!ipc_file)
		{
		ipc_file = g_strconcat(homedir(), "/", GQMPEG_FILE_IPC_COMMAND, NULL);
		}
	unlink(ipc_file);
	if (mkfifo(ipc_file, S_IRUSR | S_IWUSR) != 0)
		{
		printf("Failed to mkfifo for %s\n", ipc_file);
		return;
		}

	ipc_fd_id = open(ipc_file, O_RDONLY | O_NONBLOCK);

	if (ipc_fd_id == -1)
		{
		printf("unable to open %s\n", ipc_file);
		return;
		}
	ipc_file_id = fdopen (ipc_fd_id, "r");

	pid_lock_file_create();

	ipc_cb_id = gtk_timeout_add(100, ipc_read_data, NULL);

/* FIXME! this is better in theory, but keeps calling ipc_read_data
   even when no data is ready?
	ipc_cb_id = gdk_input_add(ipc_fd_id,
                           GDK_INPUT_READ,
                           (GdkInputFunction) ipc_read_data,
                           NULL);
*/

	if (debug_mode) printf("ipc_on\n");
}

void ipc_off()
{
	if (ipc_cb_id > -1)
		{
		gtk_timeout_remove(ipc_cb_id);
/*		gdk_input_remove(ipc_cb_id);*/
		ipc_cb_id = -1;
		}

	if (ipc_file_id != NULL) fclose(ipc_file_id);

	ipc_file_id = NULL;

	if (ipc_fd_id != -1) close (ipc_fd_id);

	ipc_fd_id = -1;

	if (ipc_file)
		{
		unlink(ipc_file);
		g_free(ipc_file);
		ipc_file = NULL;
		pid_lock_file_destroy();
		}

	if (debug_mode) printf("ipc_off\n");
}

gint ipc_another_process_active()
{
	return pid_lock_file_locked();
}

