/*
 *
 * gkrellm-bfm.c
 * Pigeon(pigeon@pigeond.net)
 *
 * http://pigeond.net/bfm/
 *
 * This program 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.
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 *     02111-1307, USA.
 *
 */

#ifdef GKRELLM2
#include <gkrellm2/gkrellm.h>
#else
#include <gkrellm/gkrellm.h>
#endif
#include <libgen.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <time.h>

#define PLUGIN_VERSION	"0.6.4"

#define PLUGIN_NAME	"gkrellm-bfm"
#define PLUGIN_DESC	"bubblefishymon gkrellm port"
#define PLUGIN_URL	"http://www.jnrowe.ukfsn.org/projects/bfm/"
#define PLUGIN_STYLE	PLUGIN_NAME
#define PLUGIN_KEYWORD	PLUGIN_NAME

#define DEBUG 0


#define CHART_W 56
#define CHART_H 56

#ifdef GKRELLM2
# define Monitor     GkrellmMonitor
# define Chart       GkrellmChart
# define ChartConfig GkrellmChartconfig

# define gkrellm_create_tab        gkrellm_gtk_notebook_page
# define gkrellm_create_framed_tab gkrellm_gtk_framed_notebook_page
# define gkrellm_scrolled_text     gkrellm_gtk_scrolled_text_view
# define gkrellm_add_info_text     gkrellm_gtk_text_view_append_strings

# define init_plugin gkrellm_init_plugin
#endif

static gint style_id;
static char *prog = NULL;

static Monitor *mon = NULL;
static Chart *chart = NULL;
static ChartConfig *chart_config = NULL;

static gint	timeout_id,
			update_interval;


/* From the actual bfm */
int bfm_main();
void gkrellm_update(GtkWidget *widget, GdkDrawable *drawable, int start_x, int proximity);
void prepare_sprites(void);
extern int cpu_enabled;
extern int duck_enabled;
extern int fish_enabled;
extern int fish_traffic;
extern int time_enabled;
extern int memscreen_enabled;

int proximity = 0;

/* Options stuffs */
GtkWidget *prog_entry = NULL;
GtkWidget *cpu_check = NULL;
GtkWidget *mem_check = NULL;
GtkWidget *duck_check = NULL;
GtkWidget *fish_check = NULL;
GtkWidget *clock_check = NULL;
GtkWidget *fish_traffic_check = NULL;

static gboolean
update_plugin(void)
{
	GdkEventExpose event;
	gint ret_val;
	gtk_signal_emit_by_name(GTK_OBJECT(chart->drawing_area), "expose_event", &event, &ret_val);
	return TRUE;	/* restart timer */
}


static gint
chart_expose_event(GtkWidget *widget, GdkEventExpose *ev)
{
	int x;
	x = (gkrellm_chart_width() - CHART_W) / 2;
	gkrellm_update(widget, chart->pixmap, x, proximity);
	gkrellm_draw_chart_to_screen(chart);
	return TRUE;
}


static gint
button_release_event(GtkWidget *widget, GdkEventButton *ev, gpointer data)
{
	switch(ev->button)
	{
		case 1:
		case 2:
			if(prog)
			{
				gchar *cmd;
				cmd = g_strdup_printf("%s &", prog);
				system(cmd);
				g_free(cmd);
			}
			break;

		case 3:
			gkrellm_open_config_window(mon);
			break;

		default:
			break;
	}

	return TRUE;
}

static gint
enter_notify_event(GtkWidget *widget, GdkEventMotion *ev, gpointer data)
{
	proximity = 1;
	return TRUE;
}

static gint
leave_notify_event(GtkWidget *widget, GdkEventMotion *ev, gpointer data)
{
	proximity = 0;
	return TRUE;
}


static void
disable_plugin(void)
	{
	if (timeout_id)
		gtk_timeout_remove(timeout_id);
	timeout_id = 0;
	}

static void
create_plugin(GtkWidget *vbox, gint first_create)
{
	if(first_create)
	{
		chart = gkrellm_chart_new0();
	}

	gkrellm_set_chart_height_default(chart, CHART_H);
	gkrellm_chart_create(vbox, mon, chart, &chart_config);

	if(first_create)
	{
		bfm_main();
		gtk_signal_connect(GTK_OBJECT(chart->drawing_area),
				"expose_event",
				(GtkSignalFunc) chart_expose_event,
				NULL);
		gtk_signal_connect(GTK_OBJECT(chart->drawing_area),
				"button_release_event", GTK_SIGNAL_FUNC(button_release_event),
				NULL);
		gtk_signal_connect(GTK_OBJECT(chart->drawing_area),
				"enter_notify_event", GTK_SIGNAL_FUNC(enter_notify_event),
				NULL);
		gtk_signal_connect(GTK_OBJECT(chart->drawing_area),
				"leave_notify_event", GTK_SIGNAL_FUNC(leave_notify_event),
				NULL);
	}
	if (!timeout_id)
		timeout_id = gtk_timeout_add(1000 / update_interval,
					(GtkFunction) update_plugin, NULL);
	gkrellm_disable_plugin_connect(mon, disable_plugin);
}


static void
option_toggled_cb(GtkToggleButton *button, gpointer user_data)
{
	gboolean active = gtk_toggle_button_get_active(button);
	GtkWidget *togglebutton = GTK_WIDGET(button);

	if(togglebutton == cpu_check)
	{
		cpu_enabled = active;
	}
	else if(togglebutton == mem_check)
	{
		memscreen_enabled = active;
	}
	else if(togglebutton == duck_check)
	{
		duck_enabled = active;
	}
	else if(togglebutton == fish_check)
	{
		fish_enabled = active;
		if(fish_enabled)
		{
			gtk_widget_set_sensitive(fish_traffic_check, TRUE);
		}
		else
		{
			gtk_widget_set_sensitive(fish_traffic_check, FALSE);
		}
	}
	else if(togglebutton == clock_check)
	{
		time_enabled = active;
	}
	else if(togglebutton == fish_traffic_check)
	{
	    fish_traffic = active;
		/* Call this to reinitialize the fishes */
	    prepare_sprites();
	}

}

void
setup_toggle_buttons(void)
{
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cpu_check), cpu_enabled);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mem_check), memscreen_enabled);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(duck_check), duck_enabled);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fish_check), fish_enabled);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(clock_check), time_enabled);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fish_traffic_check), fish_traffic);
}


static void
cb_interval_modified(GtkWidget *widget, GtkSpinButton *spin)
	{
	update_interval = gtk_spin_button_get_value_as_int(spin);
	if (timeout_id)
		gtk_timeout_remove(timeout_id);
	timeout_id = gtk_timeout_add(1000 / update_interval,
					(GtkFunction) update_plugin, NULL);
	}

static gchar	*pending_prog;

static void
cb_prog_entry(GtkWidget *widget, gpointer data)
{
	gboolean	activate_sig = GPOINTER_TO_INT(data);
	gchar		*s           = gkrellm_gtk_entry_get_text(&prog_entry);

	if (activate_sig)
		{
		gkrellm_dup_string(&prog, s);
		g_free(pending_prog);
		pending_prog = NULL;
		}
	else	/* "changed" sig, entry is pending on "activate" or config close */
		gkrellm_dup_string(&pending_prog, s);
}

static void
config_destroyed(void)
	{
	if (pending_prog)
		gkrellm_dup_string(&prog, pending_prog);
	g_free(pending_prog);
	pending_prog = NULL;
	}

static void
create_plugin_tab(GtkWidget *tab_vbox)
{
	GtkWidget *tabs = NULL;

	GtkWidget *options_tab = NULL;

	GtkWidget *info_tab = NULL;
	GtkWidget *info = NULL;

	GtkWidget *about_tab = NULL;
	GtkWidget *about = NULL;

	GtkWidget *main_box;
	GtkWidget *prog_box;
	GtkWidget *prog_label;
	GtkWidget *row1;
	GtkWidget *cpu_box;
	GtkWidget *mem_box;
	GtkWidget *row2;
	GtkWidget *duck_box;
	GtkWidget *fish_box;
	GtkWidget *row3;
	GtkWidget *clock_box;
	GtkWidget *fish_traffic_box;

	static gchar *info_text[] =
	{
		"<b>" PLUGIN_NAME " " PLUGIN_VERSION "\n\n",
		"bubblefishymon gkrellm port\n",
		"Pigeon(pigeon@pigeond.net)\n",
		PLUGIN_URL "\n\n",
		"Original bubblemon by Johan\n",
		"http://www.student.nada.kth.se/~d92-jwa/code/\n\n",
		"More hacks by Timecop\n",
		"http://www.ne.jp/asahi/linux/timecop/\n\n",
		"And more hacks by James Rowe\n\n",
		"<i>Usage\n\n",
		"Nice monitor with:\n",
		"- Water level representing the memory usage...\n",
		"- Water color representing swap status...\n",
		"- Bubbles representing CPU usage...\n",
		"- Fish representing network traffic...\n",
		"  (Fish swiming from left to right represents outgoing traffic,\n",
		"   fish swiming from right to left represents incoming traffic)\n",
		"- Cute little duck swimming...\n",
		"- Clock hands representing time (obviously)...\n",
		"- Click and it will run a command for you (requested by Nick =)\n",
		"\n\n",
	};

	static gchar *about_text =
	_(
	  "BubbleFishyMon " PLUGIN_VERSION "\n"
	  PLUGIN_NAME " - " PLUGIN_DESC "\n\n"
	  "Copyright (C) 2001 Pigeon\n"
	  "pigeon@pigeond.net\n"
	  PLUGIN_URL "\n\n"
	  "Released under the GNU Public Licence"
	);

	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);
	g_signal_connect(G_OBJECT(tabs),"destroy",
			 G_CALLBACK(config_destroyed), NULL);

	/* Options tab */
	options_tab = gkrellm_create_tab(tabs, _("Options"));

	main_box = gtk_vbox_new (FALSE, 0);
	gtk_widget_set_name (main_box, "main_box");
	gtk_widget_ref (main_box);
	gtk_object_set_data_full (GTK_OBJECT (options_tab), "main_box", main_box,
							(GtkDestroyNotify) gtk_widget_unref);
	gtk_widget_show (main_box);
	gtk_container_add (GTK_CONTAINER (options_tab), main_box);

	prog_box = gtk_hbox_new (FALSE, 0);
	gtk_widget_set_name (prog_box, "prog_box");
	gtk_widget_ref (prog_box);
	gtk_object_set_data_full (GTK_OBJECT (options_tab), "prog_box", prog_box,
							(GtkDestroyNotify) gtk_widget_unref);
	gtk_widget_show (prog_box);
	gtk_box_pack_start (GTK_BOX (main_box), prog_box, TRUE, TRUE, 0);

	prog_label = gtk_label_new (_("Program to execute when clicked: "));
	gtk_widget_set_name (prog_label, "prog_label");
	gtk_widget_ref (prog_label);
	gtk_object_set_data_full (GTK_OBJECT (options_tab), "prog_label", prog_label,
							(GtkDestroyNotify) gtk_widget_unref);
	gtk_widget_show (prog_label);
	gtk_box_pack_start (GTK_BOX (prog_box), prog_label, FALSE, FALSE, 0);

	prog_entry = gtk_entry_new ();
	if(prog)
	{
		gtk_entry_set_text(GTK_ENTRY(prog_entry), prog);
	}
	gtk_widget_set_name (prog_entry, "prog_entry");
	gtk_widget_ref (prog_entry);
	gtk_object_set_data_full (GTK_OBJECT (options_tab), "prog_entry", prog_entry,
							(GtkDestroyNotify) gtk_widget_unref);
	gtk_widget_show (prog_entry);
	gtk_box_pack_start (GTK_BOX (prog_box), prog_entry, TRUE, TRUE, 0);
	g_signal_connect(G_OBJECT(prog_entry), "activate",
				G_CALLBACK(cb_prog_entry), GINT_TO_POINTER(1));
	g_signal_connect(G_OBJECT(prog_entry), "changed",
				G_CALLBACK(cb_prog_entry), GINT_TO_POINTER(0));

	row1 = gtk_hbox_new (FALSE, 0);
	gtk_widget_set_name (row1, "row1");
	gtk_widget_ref (row1);
	gtk_object_set_data_full (GTK_OBJECT (options_tab), "row1", row1,
							(GtkDestroyNotify) gtk_widget_unref);
	gtk_widget_show (row1);
	gtk_box_pack_start (GTK_BOX (main_box), row1, TRUE, TRUE, 0);

	cpu_box = gtk_hbox_new (FALSE, 0);
	gtk_widget_set_name (cpu_box, "cpu_box");
	gtk_widget_ref (cpu_box);
	gtk_object_set_data_full (GTK_OBJECT (options_tab), "cpu_box", cpu_box,
							(GtkDestroyNotify) gtk_widget_unref);
	gtk_widget_show (cpu_box);
	gtk_box_pack_start (GTK_BOX (row1), cpu_box, FALSE, TRUE, 0);

	cpu_check = gtk_check_button_new_with_label (_("CPU"));
	gtk_widget_set_name (cpu_check, "cpu_check");
	gtk_widget_ref (cpu_check);
	gtk_object_set_data_full (GTK_OBJECT (options_tab), "cpu_check", cpu_check,
							(GtkDestroyNotify) gtk_widget_unref);
	gtk_widget_show (cpu_check);
	gtk_box_pack_start (GTK_BOX (cpu_box), cpu_check, FALSE, TRUE, 0);
	gtk_widget_set_usize (cpu_check, 220, -2);

	mem_box = gtk_hbox_new (FALSE, 0);
	gtk_widget_set_name (mem_box, "mem_box");
	gtk_widget_ref (mem_box);
	gtk_object_set_data_full (GTK_OBJECT (options_tab), "mem_box", mem_box,
							(GtkDestroyNotify) gtk_widget_unref);
	gtk_widget_show (mem_box);
	gtk_box_pack_start (GTK_BOX (row1), mem_box, TRUE, TRUE, 0);

	mem_check = gtk_check_button_new_with_label (_("Memory"));
	gtk_widget_set_name (mem_check, "mem_check");
	gtk_widget_ref (mem_check);
	gtk_object_set_data_full (GTK_OBJECT (options_tab), "mem_check", mem_check,
							(GtkDestroyNotify) gtk_widget_unref);
	gtk_widget_show (mem_check);
	gtk_box_pack_start (GTK_BOX (mem_box), mem_check, TRUE, TRUE, 0);

	row2 = gtk_hbox_new (FALSE, 0);
	gtk_widget_set_name (row2, "row2");
	gtk_widget_ref (row2);
	gtk_object_set_data_full (GTK_OBJECT (options_tab), "row2", row2,
							(GtkDestroyNotify) gtk_widget_unref);
	gtk_widget_show (row2);
	gtk_box_pack_start (GTK_BOX (main_box), row2, TRUE, TRUE, 0);

	duck_box = gtk_hbox_new (FALSE, 0);
	gtk_widget_set_name (duck_box, "duck_box");
	gtk_widget_ref (duck_box);
	gtk_object_set_data_full (GTK_OBJECT (options_tab), "duck_box", duck_box,
							(GtkDestroyNotify) gtk_widget_unref);
	gtk_widget_show (duck_box);
	gtk_box_pack_start (GTK_BOX (row2), duck_box, FALSE, TRUE, 0);

	duck_check = gtk_check_button_new_with_label (_("Duck"));
	gtk_widget_set_name (duck_check, "duck_check");
	gtk_widget_ref (duck_check);
	gtk_object_set_data_full (GTK_OBJECT (options_tab), "duck_check", duck_check,
							(GtkDestroyNotify) gtk_widget_unref);
	gtk_widget_show (duck_check);
	gtk_box_pack_start (GTK_BOX (duck_box), duck_check, FALSE, TRUE, 0);
	gtk_widget_set_usize (duck_check, 220, -2);

	fish_box = gtk_hbox_new (FALSE, 0);
	gtk_widget_set_name (fish_box, "fish_box");
	gtk_widget_ref (fish_box);
	gtk_object_set_data_full (GTK_OBJECT (options_tab), "fish_box", fish_box,
							(GtkDestroyNotify) gtk_widget_unref);
	gtk_widget_show (fish_box);
	gtk_box_pack_start (GTK_BOX (row2), fish_box, TRUE, TRUE, 0);

	fish_check = gtk_check_button_new_with_label (_("Fish"));
	gtk_widget_set_name (fish_check, "fish_check");
	gtk_widget_ref (fish_check);
	gtk_object_set_data_full (GTK_OBJECT (options_tab), "fish_check", fish_check,
							(GtkDestroyNotify) gtk_widget_unref);
	gtk_widget_show (fish_check);
	gtk_box_pack_start (GTK_BOX (fish_box), fish_check, TRUE, TRUE, 0);

	row3 = gtk_hbox_new (FALSE, 0);
	gtk_widget_set_name (row3, "row3");
	gtk_widget_ref (row3);
	gtk_object_set_data_full (GTK_OBJECT (options_tab), "row3", row3,
							(GtkDestroyNotify) gtk_widget_unref);
	gtk_widget_show (row3);
	gtk_box_pack_start (GTK_BOX (main_box), row3, TRUE, TRUE, 0);

	clock_box = gtk_hbox_new (FALSE, 0);
	gtk_widget_set_name (clock_box, "clock_box");
	gtk_widget_ref (clock_box);
	gtk_object_set_data_full (GTK_OBJECT (options_tab), "clock_box", clock_box,
							(GtkDestroyNotify) gtk_widget_unref);
	gtk_widget_show (clock_box);
	gtk_box_pack_start (GTK_BOX (row3), clock_box, FALSE, TRUE, 0);

	clock_check = gtk_check_button_new_with_label (_("Show clock"));
	gtk_widget_set_name (clock_check, "clock_check");
	gtk_widget_ref (clock_check);
	gtk_object_set_data_full (GTK_OBJECT (options_tab), "clock_check", clock_check,
							(GtkDestroyNotify) gtk_widget_unref);
	gtk_widget_show (clock_check);
	gtk_box_pack_start (GTK_BOX (clock_box), clock_check, FALSE, TRUE, 0);
	gtk_widget_set_usize (clock_check, 220, -2);

	fish_traffic_box = gtk_hbox_new (FALSE, 0);
	gtk_widget_set_name (fish_traffic_box, "fish_traffic_box");
	gtk_widget_ref (fish_traffic_box);
	gtk_object_set_data_full (GTK_OBJECT (options_tab), "fish_traffic_box", fish_traffic_box,
							(GtkDestroyNotify) gtk_widget_unref);
	gtk_widget_show (fish_traffic_box);
	gtk_box_pack_start (GTK_BOX (row3), fish_traffic_box, TRUE, TRUE, 0);

	fish_traffic_check = gtk_check_button_new_with_label (_("Fish represents network traffic"));
	gtk_widget_set_name (fish_traffic_check, "fish_traffic_check");
	gtk_widget_ref (fish_traffic_check);
	gtk_object_set_data_full (GTK_OBJECT (options_tab), "fish_traffic_check", fish_traffic_check,
							(GtkDestroyNotify) gtk_widget_unref);
	gtk_widget_show (fish_traffic_check);
	gtk_box_pack_start (GTK_BOX (fish_traffic_box), fish_traffic_check, TRUE, TRUE, 0);

	gkrellm_gtk_spin_button(main_box, NULL, update_interval,
				10.0, 50.0, 1.0, 5.0, 0, 60,
				cb_interval_modified, NULL, FALSE,
				_("Updates per second"));

	setup_toggle_buttons();

	gtk_signal_connect(GTK_OBJECT(cpu_check), "toggled", GTK_SIGNAL_FUNC(option_toggled_cb), NULL);
	gtk_signal_connect(GTK_OBJECT(mem_check), "toggled", GTK_SIGNAL_FUNC(option_toggled_cb), NULL);
	gtk_signal_connect(GTK_OBJECT(duck_check), "toggled", GTK_SIGNAL_FUNC(option_toggled_cb), NULL);
	gtk_signal_connect(GTK_OBJECT(fish_check), "toggled", GTK_SIGNAL_FUNC(option_toggled_cb), NULL);
	gtk_signal_connect(GTK_OBJECT(clock_check), "toggled", GTK_SIGNAL_FUNC(option_toggled_cb), NULL);
	gtk_signal_connect(GTK_OBJECT(fish_traffic_check), "toggled", GTK_SIGNAL_FUNC(option_toggled_cb), NULL);


	/* Info tab */
	info_tab = gkrellm_create_framed_tab(tabs, _("Info"));
	info = gkrellm_scrolled_text(info_tab, NULL, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

	gkrellm_add_info_text(info, info_text, sizeof(info_text) / sizeof(gchar *));


	/* About tab */
	about_tab = gkrellm_create_tab(tabs, _("About"));
	about = gtk_label_new(about_text);
	gtk_box_pack_start(GTK_BOX(about_tab), about, TRUE, TRUE, 0);

}


static void
save_plugin_config(FILE *f)
{
	if(prog)
	{
		fprintf(f, "%s prog %s\n", PLUGIN_KEYWORD, prog);
	}
	fprintf(f, "%s options %d.%d.%d.%d.%d.%d.%d\n", PLUGIN_KEYWORD,
			cpu_enabled,
			duck_enabled,
			memscreen_enabled,
			fish_enabled,
			fish_traffic,
			time_enabled,
			update_interval);

}

static void
load_plugin_config(gchar *config_line)
{
	gchar *config_item, *value;

	config_item = strtok(config_line, " \n");

	if(!config_item)
		return;

	value = strtok(NULL, "\n");

	if(!strcmp(config_item, "prog"))
	{
		g_free(prog);
		prog = g_strdup(value);
	}
	else if(!strcmp(config_item, "options"))
	{
		sscanf(value, "%d.%d.%d.%d.%d.%d.%d",
				&cpu_enabled,
				&duck_enabled,
				&memscreen_enabled,
				&fish_enabled,
				&fish_traffic,
				&time_enabled,
				&update_interval);
	}

}


static Monitor bfm_mon =
{
	PLUGIN_NAME,         /* Name, for config tab.                    */
	0,                   /* Id,  0 if a plugin                       */
	create_plugin,       /* The create_plugin() function             */
	NULL,                /* The update_plugin() function             */
	create_plugin_tab,   /* The create_plugin_tab() config function  */
	NULL,                /* The apply_plugin_config() function       */
	
	save_plugin_config,  /* The save_plugin_config() function        */
	load_plugin_config,  /* The load_plugin_config() function        */
	PLUGIN_KEYWORD,      /* config keyword                           */
	
	NULL,                /* Undefined 2                              */
	NULL,                /* Undefined 1                              */
	NULL,                /* private                                  */
	
	MON_CPU,             /* 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(void)
{
	update_interval = 20;
	style_id = gkrellm_add_meter_style(&bfm_mon, PLUGIN_STYLE);
	return (mon = &bfm_mon);
}



