#include <stdlib.h>
#include <time.h>
#include <signal.h>
#include <gtk/gtk.h>

#include "../../include/prochandle.h"

#include "../guiutils.h"
#include "sysinfowin.h"
#include "config.h"


static void SysInfoSignalCB(int s);
static gint SysInfoTimeOutCB(gpointer data);


#define ATOI(s)         (((s) != NULL) ? atoi(s) : 0)
#define ATOL(s)         (((s) != NULL) ? atol(s) : 0)
#define ATOF(s)         (((s) != NULL) ? atof(s) : 0.0f)
#define STRDUP(s)       (((s) != NULL) ? g_strdup(s) : NULL)

#define MAX(a,b)        (((a) > (b)) ? (a) : (b))
#define MIN(a,b)        (((a) < (b)) ? (a) : (b))
#define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))
#define STRLEN(s)       (((s) != NULL) ? strlen(s) : 0)
#define STRISEMPTY(s)   (((s) != NULL) ? (*(s) == '\0') : TRUE)


/*
 *      UNIX signal callback.
 */
static void SysInfoSignalCB(int s)
{
	switch(s)
	{
#ifdef SIGINT
	  case SIGINT:
	    exit(0);
	    break;
#endif
#ifdef SIGTERM
	  case SIGTERM:
	    exit(0);
	    break;
#endif
#ifdef SIGQUIT
	  case SIGQUIT:
	    exit(0);
	    break;
#endif
#ifdef SIGSEGV
	  case SIGSEGV:
	    exit(1);
	    break;
#endif
	}
}

/*
 *	Timeout callback.
 */
static gint SysInfoTimeOutCB(gpointer data)
{
	sysinfo_win_struct *si = SYSINFO_WIN(data);
	if(!SysInfoIsMapped(si))
	{
	    gtk_main_quit();
	    return(FALSE);
	}

	SysInfoUpdate(si);

	return(TRUE);
}


int main(int argc, char *argv[])
{
	gboolean initialized_gtk = FALSE;
	gint i;
	const gchar *arg;
	guint id;
	sysinfo_display_flags display = SYSINFO_DISPLAY_CPU_LOAD |
	    SYSINFO_DISPLAY_CPU_LOADAVG | SYSINFO_DISPLAY_MEMORY |
	    SYSINFO_DISPLAY_APM_POWER;
	sysinfo_bar_style bar_style = SYSINFO_BAR_STYLE_CONTINUOUS;
	sysinfo_bar_orientation bar_orientation = SYSINFO_BAR_ORIENTATION_HORIZONTAL;
	gulong poll_interval = 250l;
	sysinfo_win_struct *si;

#define DO_FREE_LOCALS	{		\
}

	/* Set up signal callbacks */
#ifdef SIGINT
	signal(SIGINT, SysInfoSignalCB);
#endif
#ifdef SIGTERM
	signal(SIGTERM, SysInfoSignalCB);
#endif
#ifdef SIGQUIT
	signal(SIGQUIT, SysInfoSignalCB);
#endif
#ifdef SIGKILL
	signal(SIGKILL, SysInfoSignalCB);
#endif
#ifdef SIGSEGV
	signal(SIGSEGV, SysInfoSignalCB);
#endif
#ifdef SIGPIPE
	signal(SIGPIPE, SysInfoSignalCB);
#endif


	/* Parse arguments */
	for(i = 1; i < argc; i++)
	{
	    arg = argv[i];
	    if(arg == NULL)
		continue;

	    /* Help */
	    if(!g_strcasecmp(arg, "--help") ||
	       !g_strcasecmp(arg, "-help") ||
	       !g_strcasecmp(arg, "--h") ||
	       !g_strcasecmp(arg, "-h") ||
	       !g_strcasecmp(arg, "-?")
	    )
	    {
		g_print("%s", PROG_HELP_MESG);
		DO_FREE_LOCALS
		return(0);
	    }
	    /* Version */
	    else if(!g_strcasecmp(arg, "--version") ||
		    !g_strcasecmp(arg, "-version")
	    )
	    {
		g_print(
		    "%s",
		    PROG_NAME " Version " PROG_VERSION "\n"
		    PROG_COPYRIGHT
		);
		DO_FREE_LOCALS
		return(0);
	    }
	    /* Display */
	    else if(!g_strcasecmp(arg, "-d"))
	    {
		display = 0;		/* Reset display flags */
		i++;
		arg = (i < argc) ? argv[i] : NULL;
		while((arg != NULL) ? (*arg != '-') : FALSE)
		{
		    if(!g_strcasecmp(arg, "load"))
			display |= SYSINFO_DISPLAY_CPU_LOAD;
		    else if(!g_strcasecmp(arg, "loadavg") ||
			    !g_strcasecmp(arg, "avg") ||
			    !g_strcasecmp(arg, "average")
		    )
			display |= SYSINFO_DISPLAY_CPU_LOADAVG;
		    else if(!g_strcasecmp(arg, "memory") ||
			    !g_strcasecmp(arg, "mem")
		    )
			display |= SYSINFO_DISPLAY_MEMORY;
		    else if(!g_strcasecmp(arg, "apmpower") ||
			    !g_strcasecmp(arg, "apm")
		    )
			display |= SYSINFO_DISPLAY_APM_POWER;
		    else if(!g_strcasecmp(arg, "details"))
			display |= SYSINFO_DISPLAY_CPU_DETAILS;
		    else
			g_printerr(
"-d: Warning: Unsupported display flag \"%s\".\n",
			    arg
			);

		    i++;
		    arg = (i < argc) ? argv[i] : NULL;
		}
		i--;
	    }
	    /* Bar Style */
	    else if(!g_strcasecmp(arg, "--style") ||
		    !g_strcasecmp(arg, "-style") ||
		    !g_strcasecmp(arg, "-s")
	    )
	    {
		i++;
		arg = (i < argc) ? argv[i] : NULL;
		if(!STRISEMPTY(arg))
		{
		    if(*arg == 'c')
			bar_style = SYSINFO_BAR_STYLE_CONTINUOUS;
		    else if(*arg == 'd')
			bar_style = SYSINFO_BAR_STYLE_DISCRETE;
		    else if(*arg == 'l')
			bar_style = SYSINFO_BAR_STYLE_LED;
		    else
			g_printerr(
"%s: Warning: Unsupported argument \"%s\".\n",
			    argv[i - 1], arg
			);
		}
	    }
	    /* Bar Orientation */
	    else if(!g_strcasecmp(arg, "--orientation") ||
		    !g_strcasecmp(arg, "-orientation") ||
		    !g_strcasecmp(arg, "-o")
	    )
	    {
		i++;
		arg = (i < argc) ? argv[i] : NULL;
		if(!STRISEMPTY(arg))
		{
		    if(*arg == 'h')
			bar_orientation = SYSINFO_BAR_ORIENTATION_HORIZONTAL;
		    else if(*arg == 'v')
			bar_orientation = SYSINFO_BAR_ORIENTATION_VERTICAL;
		    else
			g_printerr(
"%s: Warning: Unsupported argument \"%s\".\n",
			    argv[i - 1], arg
			);
		}
	    }
	    /* Poll Interval */
	    else if(!g_strcasecmp(arg, "--interval") ||
		    !g_strcasecmp(arg, "-interval") ||
		    !g_strcasecmp(arg, "-i")
	    )
	    {
		i++;
		arg = (i < argc) ? argv[i] : NULL;
		if(!STRISEMPTY(arg))    
		{
		    poll_interval = ATOL(arg);
		}
	    }
	    /* Skip these arguments so that gtk_window_apply_args()
	     * handles them
	     */
	    else if(gtk_is_window_arg(arg))
	    {
		i++;
	    }
	    /* Single character argument? */
	    else if((*arg == '-') ? (arg[1] != '-') : FALSE)
	    {
		const gchar *v = arg + 1;
/*              gchar c; */

		while(*v != '\0')
		{
#if 0
		    c = *v;
		    if(c == 's')
		    {
			auto_start = TRUE;
		    }
		    else
		    {
			g_printerr(
"-%c: Unsupported argument.\n",
			    c
			);
			DO_FREE_LOCALS
			return(2);
		    }
#endif
		    v++;
		}
	    }
	    else
	    {
		g_printerr(
"%s: Unsupported argument.\n",
		    arg
		);
		DO_FREE_LOCALS
		return(2);
	    }
	}


	/* Set GTK locale */
	gtk_set_locale();

	/* Initialize GTK as needed */
	if(!initialized_gtk)
	{
	    if(!gtk_init_check(&argc, &argv))
	    {
		g_printerr("Unable to initialize GTK.\n");
		DO_FREE_LOCALS
		return(1);
	    }
	    initialized_gtk = TRUE;
	}

	/* Initialize GDK RGB buffers system */
	gdk_rgb_init();


	/* Create new SysInfo Window */
	si = SysInfoNew(
	    NULL,
	    display,
	    bar_style,
	    bar_orientation
	);
	gtk_window_apply_args(GTK_WINDOW(si->toplevel), argc, argv);
	SysInfoMap(si);

	id = gtk_timeout_add(
	    MAX(poll_interval, 10l),
	    SysInfoTimeOutCB, si
	);

	gtk_main();


	/* Begin deleting */

	SysInfoDelete(si);

	/* Reset the DND Icon */
	GUIDNDSetDragIcon(NULL, NULL, 0, 0);

	DO_FREE_LOCALS

	return(0);
#undef DO_FREE_LOCALS
}
