/*
** 1998-08-24 -	Configure search paths, i.e. lists of directories gentoo might search for
**		different kinds of files. Currently there's only one path; the one used
**		for icons. This might change in the future, though (sounds, helper apps...).
** 1998-12-25 -	Finally changed the config file format for paths. Much better now.
*/

#include "gentoo.h"
#include "fileutil.h"
#include "guiutil.h"
#include "strutil.h"
#include "xmlutil.h"

#include "cfg_gui.h"
#include "cfg_module.h"

#include "cfg_paths.h"

#define	NODE	"Paths"

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

typedef struct {
	GtkWidget	*path;
} Path;

typedef struct {
	GtkWidget	*frame;
	GSList		*hgroup;
	GtkWidget	*hmode[3];
	GtkWidget	*hre;
	GtkWidget	*hicase;		/* Check button. */
} HFrame;

typedef struct {
	MainInfo	*main;
	GtkWidget	*vbox;
	GtkWidget	*pframe;		/* Frame for path widgets. */
	GtkWidget	*ptable;		/* Table holding labels and entry widgets. */
	Path		path[PTID_NUM_PATHS];	/* Widgets for editing the paths. */

	HFrame		hide;

	HideInfo	hideinfo;
	gint		open;
	gint		modified;
} P_Paths;

static P_Paths	the_page;

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

/* 1998-08-24 -	User modified a path by editing it. Remember that. */
static gint evt_path_changed(GtkWidget *wid, gpointer data)
{
	P_Paths	*page = (P_Paths *) data;

	if(page->open)
		page->modified = TRUE;

	return TRUE;
}

/* 1998-10-30 -	User just changed the hiding mode. */
static gint evt_hmode_clicked(GtkWidget *wid, gpointer data)
{
	P_Paths	*page = (P_Paths *) data;

	if(GTK_TOGGLE_BUTTON(wid)->active)
	{
		page->hideinfo.mode = (HMode) gtk_object_get_data(GTK_OBJECT(wid), "mode");
		gtk_widget_set_sensitive(page->hide.hre, page->hideinfo.mode == HIDE_REGEXP);
		gtk_widget_set_sensitive(page->hide.hicase, page->hideinfo.mode == HIDE_REGEXP);
			
		page->modified = TRUE;
	}

	return TRUE;
}

/* 1998-10-30 -	User edited the hide RE. Register change, and grab the string. */
static gint evt_hre_changed(GtkWidget *wid, gpointer data)
{
	P_Paths	*page = (P_Paths *) data;

	str_strncpy(page->hideinfo.hide_re_src, gtk_entry_get_text(GTK_ENTRY(wid)), sizeof page->hideinfo.hide_re_src);
	page->modified = TRUE;
	return TRUE;
}

/* 1998-10-26 -	The "No Case?" check button for hide RE has been hit. */
static gint evt_hicase_clicked(GtkWidget *wid, gpointer data)
{
	P_Paths	*page = (P_Paths *) data;

	page->hideinfo.no_case = GTK_TOGGLE_BUTTON(wid)->active;
	page->modified = TRUE;

	return TRUE;
}

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

/* 1998-08-24 -	Populate the paths. Not very complicated.
** 1998-10-26 -	Now also initializes the hide widgetry.
*/
static void populate_paths(CfgInfo *cfg, P_Paths *page)
{
	int	i;

	for(i = 0; i < PTID_NUM_PATHS; i++)
		gtk_entry_set_text(GTK_ENTRY(page->path[i].path), cfg->path.path[i]->str);

	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->hide.hmode[cfg->path.hideinfo.mode]), TRUE);
	gtk_entry_set_text(GTK_ENTRY(page->hide.hre), cfg->path.hideinfo.hide_re_src);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->hide.hicase), cfg->path.hideinfo.no_case);
	gtk_widget_set_sensitive(page->hide.hre, page->hideinfo.mode == HIDE_REGEXP);
	gtk_widget_set_sensitive(page->hide.hicase, page->hideinfo.mode == HIDE_REGEXP);
}

/* 1998-08-24 -	Open up the paths config page. Very simple at this time, since there's only
**		one path to configure.
*/
static GtkWidget * cpt_init(MainInfo *min, char **name)
{
	P_Paths		*page = &the_page;
	GtkWidget	*label, *vbox;
	const gchar	*labtxt[] = { "Icons", "GTK+ RC", "fstab", "mtab" },
			*hlab[] = { "None", "Beginning With Dot (.)", "Matching RE" };
	guint		i;

	if(name == NULL)
		return NULL;

	*name = "Paths & Hide";

	page->main = min;
	page->open = FALSE;
	page->modified = FALSE;

	page->vbox = gtk_vbox_new(FALSE, 0);
	page->pframe = gtk_frame_new("Paths");
	page->ptable = gtk_table_new(1, 2, FALSE);

	if(sizeof labtxt / sizeof labtxt[0] == PTID_NUM_PATHS)
	{
		for(i = 0; i < PTID_NUM_PATHS; i++)
		{
			label = gtk_label_new(labtxt[i]);
			gtk_table_attach(GTK_TABLE(page->ptable), label, 0, 1, i, i+1, 0,0,0,0);
			gtk_widget_show(label);
			page->path[i].path = gtk_entry_new();
			gtk_signal_connect(GTK_OBJECT(page->path[i].path), "changed", GTK_SIGNAL_FUNC(evt_path_changed), (gpointer) page);
			gtk_table_attach_defaults(GTK_TABLE(page->ptable), page->path[i].path, 1, 2, i, i+1);
#if defined(__OpenBSD__)
			if(i == 2 || i == 3)
				gtk_widget_set_sensitive(page->path[i].path, FALSE);
#endif
			gtk_widget_show(page->path[i].path);
		}
	}
	else
		fprintf(stderr, "**CFGPATHS: Missing labels!\n");

	gtk_container_add(GTK_CONTAINER(page->pframe), page->ptable);
	gtk_widget_show(page->ptable);
	gtk_box_pack_start(GTK_BOX(page->vbox), page->pframe, FALSE, FALSE, 5);
	gtk_widget_show(page->pframe);

	page->hide.frame  = gtk_frame_new("Hide Entries");
	page->hide.hgroup = gui_radio_group_new(3, hlab, page->hide.hmode);
	vbox = gtk_vbox_new(FALSE, 0);
	for(i = 0; i < sizeof page->hide.hmode / sizeof page->hide.hmode[0]; i++)
	{
		gtk_object_set_data(GTK_OBJECT(page->hide.hmode[i]), "mode", (gpointer) i);
		gtk_signal_connect(GTK_OBJECT(page->hide.hmode[i]), "clicked", GTK_SIGNAL_FUNC(evt_hmode_clicked), (gpointer) page);
		if(i < 2)
		{
			gtk_box_pack_start(GTK_BOX(vbox), page->hide.hmode[i], FALSE, FALSE, 0);
			gtk_widget_show(page->hide.hmode[i]);
		}
		else
		{
			GtkWidget	*hbox;

			hbox = gtk_hbox_new(FALSE, 0);
			gtk_box_pack_start(GTK_BOX(hbox), page->hide.hmode[i], FALSE, FALSE, 0);
			gtk_widget_show(page->hide.hmode[i]);
			page->hide.hre = gtk_entry_new_with_max_length(sizeof min->cfg.path.hideinfo.hide_re_src - 1);
			gtk_signal_connect(GTK_OBJECT(page->hide.hre), "changed", GTK_SIGNAL_FUNC(evt_hre_changed), (gpointer) page);
			gtk_box_pack_start(GTK_BOX(hbox), page->hide.hre, TRUE, TRUE, 0);
			gtk_widget_show(page->hide.hre);
			page->hide.hicase = gtk_check_button_new_with_label("No Case?");
			gtk_signal_connect(GTK_OBJECT(page->hide.hicase), "clicked", GTK_SIGNAL_FUNC(evt_hicase_clicked), (gpointer) page);
			gtk_box_pack_start(GTK_BOX(hbox), page->hide.hicase, FALSE, FALSE, 0);
			gtk_widget_show(page->hide.hicase);
			gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
			gtk_widget_show(hbox);
		}
	}
	gtk_container_add(GTK_CONTAINER(page->hide.frame), vbox);
	gtk_widget_show(vbox);
	gtk_box_pack_start(GTK_BOX(page->vbox), page->hide.frame, FALSE, FALSE, 0);
	gtk_widget_show(page->hide.frame);

	gtk_widget_show(page->vbox);

	return page->vbox;
}

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

/* 1998-08-24 -	Update path widgets. Tough. */
static void cpt_update(MainInfo *min)
{
	P_Paths	*page = &the_page;

	page->hideinfo = min->cfg.path.hideinfo;
	populate_paths(&min->cfg, page);
	page->open = TRUE;
}

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

/* 1998-08-24 -	Accept changes to paths (if any).
** 1998-08-30 -	Now detects changes, and only alters the main current setting if there really
**		has been changes made. Also added a switch() allowing different actions to be
**		carried out when a path has changed. Initial use: rescan when icon path changes.
*/
static void cpt_accept(MainInfo *min)
{
	P_Paths	*page = &the_page;
	char	*text;
	int	i;

	if(page->open && page->modified)
	{
		for(i = 0; i < PTID_NUM_PATHS; i++)
		{
			text = gtk_entry_get_text(GTK_ENTRY(page->path[i].path));
			if(strcmp(text, min->cfg.path.path[i]->str))
			{
				g_string_assign(min->cfg.path.path[i], text);
				switch((PathID) i)
				{
					case PTID_ICON:
						cfg_set_flags(CFLG_FLUSH_ICONS);
						break;
					default:
						break;
				}
			}
		}
		min->cfg.path.hideinfo = page->hideinfo;
		fut_check_hide(&min->gui->pane[0], NULL);		/* Frees any precompiled RE. */
		cfg_set_flags(CFLG_RESCAN_BOTH);
		page->modified = FALSE;
	}
}

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

/* 1998-08-24 -	Save out the paths. Not very complex.
** 1998-10-26 -	Added the hide info, too.
*/
static gint cpt_save(MainInfo *min, FILE *out)
{
	int	i;

	xml_put_node_open(out, NODE);

	xml_put_node_open(out, "PathList");
	for(i = 0; i < PTID_NUM_PATHS; i++)
	{
		xml_put_node_open(out, "Path");
		xml_put_integer(out, "index", i);
		xml_put_text(out, "path", min->cfg.path.path[i]->str);
		xml_put_node_close(out, "Path");
	}
	xml_put_node_close(out, "PathList");

	xml_put_node_open(out, "HideInfo");
	xml_put_integer(out, "mode", min->cfg.path.hideinfo.mode);
 	xml_put_text(out, "re", min->cfg.path.hideinfo.hide_re_src);
	xml_put_boolean(out, "re_nocase", min->cfg.path.hideinfo.no_case);
	xml_put_node_close(out, "HideInfo");

	xml_put_node_close(out, NODE);

	return TRUE;
}

static void load_path(XmlNode *data, gpointer user)
{
	CfgInfo	*cfg = (CfgInfo *) user;
	char	*path;
	gint	index;

	if(xml_get_integer(data, "index", &index))
	{
		if(index >= 0 && index < PTID_NUM_PATHS)
		{
			if(xml_get_text(data, "path", &path))
				g_string_assign(cfg->path.path[index], path);
		}
		else
			fprintf(stderr, "**CFGPATHS: Path index %d is illegal\n", index);
	}
}

static void load_hideinfo(MainInfo *min, XmlNode *node)
{
	gint	tmp;

	xml_get_integer(node, "mode", (gint *) &min->cfg.path.hideinfo.mode);
	xml_get_text_copy(node, "re", min->cfg.path.hideinfo.hide_re_src, sizeof min->cfg.path.hideinfo.hide_re_src);
	if(xml_get_boolean(node, "re_nocase", &tmp))
		min->cfg.path.hideinfo.no_case = tmp;
}

/* 1998-08-24 -	Load paths from config tree. Ugly. */
static void cpt_load(MainInfo *min, XmlNode *node)
{
	XmlNode		*data;

	if((data = xml_tree_search(node, "PathList")) != NULL)
		xml_node_visit_children(data, load_path, (gpointer) &min->cfg);
	if((data = xml_tree_search(node, "HideInfo")) != NULL)
		load_hideinfo(min, data);
}

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

/* 1998-08-24 -	Hide the paths page. Not very much to do. */
static void cpt_hide(MainInfo *min)
{
	the_page.open = FALSE;
}

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

/* 1998-08-24 -	Describe the paths config page. */
CfgPage * cpt_describe(MainInfo *min)
{
	static CfgPage	desc = { NODE, cpt_init, cpt_update, cpt_accept, cpt_save, cpt_load, cpt_hide };

	return &desc;
}

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

/* 1998-08-25 -	Return pointer to current setting for path <id>. */
char * cpt_get_path(PathID id)
{
	GtkEntry	*ent = NULL;

	switch(id)
	{
		case PTID_ICON:
			ent = GTK_ENTRY(the_page.path[id].path);
			break;
		default:
			fprintf(stderr, "**CFGPATHS: Someone requested an illegal path!\n");
	}
	if(ent != NULL)
		return gtk_entry_get_text(ent);

	return NULL;
}
