/* GKrellM
|  Copyright (C) 1999-2000 Bill Wilson
|
|  Author:  Bill Wilson    bill@gkrellm.net
|  Latest versions might be found at:  http://gkrellm.net
|
|  This program is free software which I release under the GNU General Public
|  License. You may redistribute and/or modify this program under the terms
|  of that license as published by the Free Software Foundation; either
|  version 2 of the License, or (at your option) any later version.
|
|  This program 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.
|
|  To get a copy of the GNU General Puplic License,  write to the
|  Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/* Seti@home plugin for GKrellM
|
|  Copyright (C) 2000  Henry Palonen
|
|  Author:  Henry Palonen		h yty dot net
|
|  Version: for gkrellm version 0.10.4 and up
*/

/* Simple seti@home client monitor. See www.setiathome.com for details about
|  seti@home effort. Basicaly we are trying to find extraterrestial
|  intelligence ;)
|  
|  You can start & stop seti@home client by pressing left-mouse button over
|  seti-monitor.
|
|  Plugin is based to Bill Wilson's great work, GKrellM & meminfo.c & template.c files.
|
|  Latest versions might be found from http://www.yty.net/h/gkrellm
*/

/* If this file is compiled as a shared object file and installed in
|  in your ~/.gkrellm/plugins directory, then it will be loaded when
|  gkrellm starts up.
|
|     gcc -fPIC `gtk-config --cflags` `imlib-config --cflags-gdk` -c seti.c
|     gcc -shared -Wl -o seti.so seti.o
|     cp seti.so ~/.gkrellm/plugins
*/ 

/*
|  Starting code, finally ;)
*/

#include <gkrellm/gkrellm.h>
#include <utime.h>
#include <dirent.h>


#define PIPE_SIZE	4

static Panel	*seti;	
static gchar 	*seti_file_path;
static gint	seti_pipe[PIPE_SIZE];

typedef struct
        {
        gchar   *command;
        FILE    *pipe;
        gint    timeout;
        gint    messages;
        gint    new;
        gint    seen;
        }
        Setiproc;

static Decal    *seti_label_decal;
static Decal    *seti_icon_decal;
static Setiproc         seti_user_agent;
static gint             seti_prog_state;
static Decal	*seti_decal;
static gchar	*seti_label;
static gint	seti_label_is_data,x_seti;
static Krell	*seti_krell;
static gint	seti_first_create=1;


/*
 *	Updating krell
 */

static void
update_seti()
	{
	FILE	*f;
	gchar	buf[160];
	gdouble lprogress;

	gchar 	hjuu[10];
	gfloat 	daa;

	Krell	*krell;

	krell = KRELL(seti);

/* It's enough to update once every ten seconds. It's actually too
|  often. Should be minute or so. But then there should be a call which 
|  updates krell with "force" at startup so seti@home status is readable
|  right away. I worst case there would be one minute delay. Now delay is 10 secs max.
|
|  UPDATE since 0.10.0: 
|  Now there is "seti_first_create" which launces drawing of monitor right
|  from the start.
|  
*/
	
	if (GK.ten_second_tick || seti_first_create)
		{
		
		/* This was the first time to draw */
		seti_first_create = 0;

		/* File format is something with
		|
	  	|  prog=0.2355233
		|
		|  line on it.
	 	*/

		if ((f = fopen(seti_file_path, "r")) != NULL)
			{
			while ((fgets(buf, sizeof(buf), f)) != NULL)
				{
				if (strncmp(buf, "prog", 4) == 0)
					{
					sscanf(buf,"prog=%lg",
						 &lprogress);
					if (GK.debug) 
						printf("setiprogress %g \n", lprogress);
	
					lprogress = lprogress * 100;
					krell->full_scale = 100;
					krell->previous = 0;
					gkrellm_update_krell(seti, krell, lprogress);
					gkrellm_draw_layers(seti);
					}
				}
			fclose(f);
			}
		}


	}	


static void
pipe_command(Setiproc *mp)
        {
        gchar   buf[128];

        if (mp->command == NULL || *(mp->command) == '\0')
                return;
        snprintf(buf, sizeof(buf), "%s 1>ls.txt", mp->command);
        if (GK.debug)
                printf("pipe_command: %s\n", buf);
        if ((mp->pipe = popen(buf, "r")) == NULL)
                return;
        fcntl(fileno(mp->pipe), F_SETFL, O_NONBLOCK);
        }


/* User has clicked panel. We should try to start/stop seti@home software */

static gint
seti_panel_click(GtkWidget *widget, GdkEventButton *ev)
        {

        if (ev->button == 1)
                {
                if (GK.debug)
			printf("Right click on seti@home. Will try to start/stop software\n");
		
		if (seti_prog_state)
			{
			seti_user_agent.command = g_strdup("killall -STOP setiathome");
			seti_prog_state=0;
			}
		else
			{
			seti_user_agent.command = g_strdup("killall -CONT setiathome");
			seti_prog_state=1;
			}

		pipe_command(&seti_user_agent);
		}
	}

static gint
seti_expose_event (GtkWidget *widget, GdkEventExpose *event)
	{
	if (widget == seti->drawing_area)
		{
		gdk_draw_pixmap(widget->window,
				widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
				seti->pixmap,
				event->area.x, event->area.y,
				event->area.x, event->area.y,
				event->area.width, event->area.height);
		}
	return FALSE;
	}


/*
 *	Creating seti-monitor
 */

void
create_seti(GtkWidget *vbox, gint first_create)
        {
        Style           *style;
        GdkImlibImage   *bg_image;
	TextStyle       *ts;
	gint		w;
	static	Style		seti_style;


	#ifdef USE_FS_STYLE_WHICH_MAY_SHOW_A_DIFF_ONLY_IN_THE_DEFAULT_THEME
	#define MY_STYLE        FS_STYLE
	#else
	#define MY_STYLE        DEFAULT_STYLE
	#endif  
        
        /* Allocate a panel structure.  plug->label and plug->textstyle
        |  structures will also be allocated...
 	*/

        if (first_create)
                {
                seti = gkrellm_panel_new0();
                seti_label = ("Seti");
                seti_decal = gkrellm_decal_new0();
                }
        else
                {
                gkrellm_destroy_decal_list(seti);
                gkrellm_destroy_krell_list(seti);
                }
	
	style = gkrellm_style_new0();
	seti_style = *gkrellm_meter_style(gkrellm_lookup_meter_style_id(UPTIME_STYLE_NAME));
	 
       	seti_krell = gkrellm_create_krell(seti, gkrellm_krell_meter_image(MY_STYLE), style);
	
	/* Measure the lenght of string "Seti" in pixels and move decal to there
	| 
	*/
	seti->textstyle = gkrellm_meter_textstyle(gkrellm_lookup_meter_style_id(UPTIME_STYLE_NAME));
	
	ts = seti->textstyle;

        w = gdk_string_width(ts->font, "Seti") + 2;
        if (w > UC.chart_width - 2 * seti_style.margin)
                w = UC.chart_width - 2 * seti_style.margin;

        seti_decal = gkrellm_create_text_decal(seti, "Seti", ts, &seti_style, -1, -1, w);
        seti_decal->x = (UC.chart_width - seti_decal->w) / 2;



	/* 
	|  Configure panel sets panel height etc.
	*/

	gkrellm_configure_panel(seti, NULL, style);

	/* Add margin to panel height for clearer appearance. */

	seti->label->h_panel += seti_style.margin; 

	bg_image = gkrellm_bg_meter_image(MY_STYLE);
	gkrellm_create_panel(vbox, seti, bg_image);
	gkrellm_monitor_height_adjust(seti->h);

	/* Actual text-drawing is done here */

        gkrellm_draw_decal_text(seti, seti_decal, seti_label, 10);
	gkrellm_draw_layers(seti);

	if (first_create)
		{
	        gtk_signal_connect(GTK_OBJECT (seti->drawing_area), "expose_event", 
		 	(GtkSignalFunc) seti_expose_event, NULL);

        	gtk_signal_connect(GTK_OBJECT(seti->drawing_area),"button_release_event", 
		 	(GtkSignalFunc) seti_panel_click, NULL);
		}

	/* Read the functions first time... */
	
	update_seti();
	
	}


/*
 *	Configuration page
 *	Configuration contains path to 'state.sah'
 */

static GtkWidget                *seti_path_entry;
static gchar			*seti_info_text =
"Seti@home progress meter shows current progress in \n"
"seti-workunit.\n\n"
"Progress value is read every ten seconds from \n"
"'state.sah' file. User can change the filename\n"
"using 'File location' tab.\n\n"
"File is parsed for line 'prog=0.nnnnnnn' and\n"
"that value is simply converted to krell movement.\n\n"
"Seti@home client can be started & stopped by pressing\n"
"left mouse button over seti-monitor.\n\n"
"Version 0.10.0 \n\nCopyright 2000, Henry Palonen <h yty dot net>\n"
"http://www.yty.net/h/gkrellm";

static void
create_seti_tab(GtkWidget *tab_vbox)
        {
        GtkWidget               *hbox;
        GtkWidget               *label;
	GtkWidget		*vbox;
	GtkWidget		*tabs;
        GtkWidget               *text;
        GtkWidget               *scrolled;

        tabs = gtk_notebook_new();
        gtk_notebook_set_tab_pos(GTK_NOTEBOOK(tabs), GTK_POS_TOP);
        gtk_box_pack_start(GTK_BOX(tab_vbox), tabs, TRUE, TRUE, 0);

/* File location tab */

        vbox = create_tab(tabs, "File location");
        seti_path_entry = gtk_entry_new_with_max_length(255);
        gtk_box_pack_start(GTK_BOX(vbox), seti_path_entry, FALSE, FALSE, 2);
        gtk_entry_set_text(GTK_ENTRY(seti_path_entry), seti_file_path);

/* Info tab */

        vbox = create_tab(tabs, "Info");
        scrolled = gtk_scrolled_window_new(NULL, NULL);
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
                        GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
        gtk_box_pack_start(GTK_BOX(vbox), scrolled, TRUE, TRUE, 0);
        text = gtk_text_new(NULL, NULL);
        gtk_text_insert(GTK_TEXT(text), NULL, NULL, NULL, seti_info_text, -1);
        gtk_text_set_editable(GTK_TEXT(text), FALSE);
        gtk_container_add(GTK_CONTAINER(scrolled), text);

        }

/*
 *	Saving config
 */

static void
save_seti_config(FILE *f)
        {
        fprintf(f, "seti filename %s\n", seti_file_path);
        }

/*
 *  Loading config
 */

static void
load_seti_config(gchar *arg)
        {
        gchar   seti_config[64], item[256];
        gint    n;

        n = sscanf(arg, "%s %[^\n]", seti_config, item);

        if (n == 2)
                {
                if (GK.debug)
                        printf("seti_config=%s item=<%s>\n", seti_config, item);
                if (strcmp(seti_config, "filename") == 0)
                        seti_file_path = g_strdup(item);
                }
        }

/*
 *	Applying config.
 *	This includes only updating seti_file_path variable.
 */

static void
apply_seti_config()
	{
        gchar                  *s;

       	s = gtk_entry_get_text(GTK_ENTRY(seti_path_entry));

        if (strcmp(s, seti_file_path))
                {
                seti_file_path = g_strdup(s);
                }
	}


static Monitor  plugin_mon      =
        {
        "Seti",               		/* Name, for config tab.    */
        0,                              /* Id,  0 if a plugin       */
        create_seti,          		/* The create function      */
        update_seti,          		/* The update function      */
        create_seti_tab,                /* The config tab create function   */
        apply_seti_config,              /* Apply the config function        */
        save_seti_config,               /* Save user config */
        load_seti_config,               /* Load user config */
        "seti",                         /* config keyword */
        NULL,                           /* Undefined 2  */
        NULL,                           /* Undefined 1  */
        NULL,                           /* Undefined 0  */
        MON_APM,                        /* Insert plugin before this monitor */
        NULL,                           /* Handle if a plugin, filled in by GKrellM     */
        NULL                            /* path if a plugin, filled in by GKrellM       */
        };


Monitor *
init_plugin()
        {
	seti_file_path = "/home/luser/setiathome/state.sah";
        return &plugin_mon;
        }
