/*
** 1998-07-13 -	A more or less general helper module. Uses the dialog module to provide
**		a clist showing the contents of a hash table. Very useful for selecting
**		a command (native or user); originally written for the cfg_buttons module.
** 1998-08-01 -	Discovered (and fixed) a weird bug; the clist's selection event handler was
**		being called as the list was being populated, which caused a read-out of
**		row data not yet installed. Seg-fault. Can't understand why it just popped
**		up today... Fixed it with an ugly little flag (open).
** 1998-08-04 -	Now handles immediate closing, without user clicking in list first. :)
** 1999-03-13 -	Adapted for new dialog module, and generally touched up a little.
*/

#include "gentoo.h"
#include "dialog.h"
#include "hash_dialog.h"

/* ----------------------------------------------------------------------------------------- */

typedef struct {
	Dialog		*dlg;
	gboolean	open;		/* Keeps selection from crashing. */
	GtkWidget	*clist;
	GSList		*slist;
	gpointer	row_data;	/* Data for currently selected row. */
	gpointer	user;		/* Original user data (from hdl_dialog() call). */
	HDlgFunction	func;		/* Hash dialog callback. */
} HDlgInfo;

/* ----------------------------------------------------------------------------------------- */

/* 1998-07-13 -	This is used to compare hash elements as they are insorted :) into the
**		singly linked list.
*/
static gint compare(gpointer a, gpointer b)
{
	if(a == NULL || b == NULL)
		return 1;
	return strcmp((char *) a, (char *) b);
}

/* 1998-07-13 -	Sort the hash elements into a singly linked list. */
static void populate_slist(gpointer key, gpointer value, gpointer data)
{
	HDlgInfo	*hdl = (HDlgInfo *) data;

	hdl->slist = g_slist_insert_sorted(hdl->slist, key, (GCompareFunc) compare);
}

/* 1998-07-13 -	Populate clist with elements from hash table, via singly linked list. */
static void populate_clist(gpointer data, gpointer user)
{
	HDlgInfo	*hdl = (HDlgInfo *) user;
	gchar		*line[1];
	gint		row;

	if(data != NULL)
	{
		line[0] = data;
		row = gtk_clist_append(GTK_CLIST(hdl->clist), line);
		gtk_clist_set_row_data(GTK_CLIST(hdl->clist), row, data);
	}
}

/* ----------------------------------------------------------------------------------------- */

/* 1998-07-14 -	This gets called when user clicks on rows of the clist. */
static void evt_clist_select(GtkWidget *wid, gint row, gint col, GdkEventButton *evt)
{
	HDlgInfo	*hdl = (HDlgInfo *) gtk_object_get_user_data(GTK_OBJECT(wid));

	hdl->row_data = gtk_clist_get_row_data(GTK_CLIST(hdl->clist), row);

	if(!hdl->open)
		return;

	if((evt != NULL) && (evt->button == 1) && (evt->type == GDK_2BUTTON_PRESS))
		dlg_dialog_close_left(hdl->dlg);
}

/* ----------------------------------------------------------------------------------------- */

/* 1998-07-14 -	Dialog-module callback. If response is positive, we go ahead and call the
**		hash_dialog-module callback. Dizzy yet? No? Good.
*/
static void done(Dialog *dlg, guint response, void *data)
{
	HDlgInfo	*hdl = (HDlgInfo *) data;

	if(response == DLG_POSITIVE)
		hdl->func(hdl->row_data, hdl->user);
}

/* ----------------------------------------------------------------------------------------- */

void hdl_dialog(GHashTable *hash, HDlgFunction func, gpointer user_data)
{
	static HDlgInfo	hdl;
	GtkWidget	*scwin;

	hdl.open = FALSE;
	hdl.row_data = NULL;
	hdl.func = func;
	hdl.user = user_data;

	scwin = gtk_scrolled_window_new(NULL, NULL);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scwin), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
	hdl.clist = gtk_clist_new(1);
	gtk_object_set_user_data(GTK_OBJECT(hdl.clist), (gpointer) &hdl);
	gtk_signal_connect(GTK_OBJECT(hdl.clist), "select_row", GTK_SIGNAL_FUNC(evt_clist_select), NULL);
	gtk_clist_set_selection_mode(GTK_CLIST(hdl.clist), GTK_SELECTION_BROWSE);
/*	gtk_clist_set_policy(GTK_CLIST(hdl.clist), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);*/
	gtk_widget_set_usize(hdl.clist, 200, 300);
	gtk_container_add(GTK_CONTAINER(scwin), hdl.clist);
	gtk_widget_show(hdl.clist);
	hdl.slist = NULL;
	g_hash_table_foreach(hash, populate_slist, &hdl);
	g_slist_foreach(hdl.slist, populate_clist, &hdl);
	g_slist_free(hdl.slist);
	hdl.open = TRUE;
	hdl.dlg  = dlg_dialog(scwin, NULL, "OK|Cancel", done, &hdl);
}
