#include "gtweakui.h"

GSList *gt_add(GSList *prefs, GSList *item) {
	prefs = g_slist_prepend(prefs, item);
	return prefs;
}

GSList *gt_pair(GConfClient *gcid, char *gconf, GtkWidget *widget, gpointer init, char *event, gpointer gtk_callback, gpointer gconf_callback, gpointer kill_callback) {
	GSList *pair = NULL;

	pair = g_slist_prepend(pair, gcid);
	pair = g_slist_prepend(pair, init);
	pair = g_slist_prepend(pair, widget);
	pair = g_slist_prepend(pair, gconf);
	pair = g_slist_prepend(pair, kill_callback);

	gsc(widget, event, gtk_callback, pair);
	gconfc(gcid, gconf, gconf_callback, pair);

	return pair;
}

void gt_callback_gconf_bool(GConfClient *client, guint cid, GConfEntry *e, gpointer d) {
	GSList *type = (GSList *)d, *gconf = type->next, *toggle = gconf->next, *old = toggle->next;

	if ((gconf_entry_get_value(e) != NULL) && (gconf_entry_get_value(e)->type == GCONF_VALUE_BOOL)) {
		gboolean new = gconf_value_get_bool(gconf_entry_get_value(e));
		if ((gboolean)(old->data) != new) {
			old->data = (gpointer)new;
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON((GtkWidget *)(toggle->data)), new);
		}
	}
}

void gt_callback_checkbox_bool(GtkWidget *widget, gpointer d) {
	GSList *type = (GSList *)d, *gconf = type->next, *toggle = gconf->next, *old = toggle->next, *gc = old->next;
	gboolean new = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));

	if (new != (gboolean)(old->data)) {
		old->data = (gpointer)new;
		gconf_client_set_bool(gc->data, gconf->data, new, NULL);
	}
}

GSList *gt_bool(GConfClient *gcid, char *gconf, GtkWidget *checkbox) {
	gboolean init = gconf_client_get_bool(gcid, gconf, NULL);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbox), init);
	return gt_pair(gcid, gconf, checkbox, (gpointer)init, "toggled", gt_callback_checkbox_bool, gt_callback_gconf_bool, NULL);
}

void gt_callback_gconf_string(GConfClient *client, guint cid, GConfEntry *e, gpointer d) {
	GSList *type = (GSList *)d, *gconf = type->next, *entry = gconf->next, *old = entry->next, *gc = old->next;

	if ((gconf_entry_get_value(e) != NULL) && (gconf_entry_get_value(e)->type == GCONF_VALUE_STRING)) {
		const gchar *new = gconf_value_get_string(gconf_entry_get_value(e));
		if (g_utf8_collate(((GString *)(old->data))->str, new) != 0) {
			old->data = g_string_assign((GString *)(old->data), new);
			gtk_entry_set_text(GTK_ENTRY(entry->data), new);
		}
	}
}

void gt_callback_entry_string(GtkWidget *w, gpointer d) {
	GSList *type = (GSList *)d, *gconf = type->next, *entry = gconf->next, *old = entry->next, *gc = old->next;

	const gchar *new = gtk_entry_get_text(GTK_ENTRY(w));

	if (g_utf8_collate(((GString *)(old->data))->str, new) != 0) {
		old->data = g_string_assign((GString *)(old->data), new);
		gconf_client_set_string(gc->data, gconf->data, new, NULL);
	}
}

void gt_callback_kill_string(GSList *pair) {
	g_string_free((GString *)pair->next->next->next->data, TRUE);
}

GSList *gt_string(GConfClient *gcid, char *gconf, GtkWidget *entry) {
	gchar *cinit = gconf_client_get_string(gcid, gconf, NULL);
	GString *init = g_string_new("");
	if (cinit != NULL) {
		init = g_string_assign(init, cinit);
		gtk_entry_set_text(GTK_ENTRY(entry), cinit);
		g_free(cinit);
	}
	return gt_pair(gcid, gconf, entry, (gpointer)init, "changed", gt_callback_entry_string, gt_callback_gconf_string, gt_callback_kill_string);
}

void gt_callback_gconf_int(GConfClient *client, guint cid, GConfEntry *e, gpointer d) {
	GSList *type = (GSList *)d, *gconf = type->next, *toggle = gconf->next, *old = toggle->next;

	if ((gconf_entry_get_value(e) != NULL) && (gconf_entry_get_value(e)->type == GCONF_VALUE_INT)) {
		guint new = gconf_value_get_int(gconf_entry_get_value(e));
		if ((guint)(old->data) != new) {
			old->data = (gpointer)new;
			gtk_spin_button_set_value(GTK_SPIN_BUTTON((GtkWidget *)(toggle->data)), new);
		}
	}
}

void gt_callback_spin_int(GtkWidget *widget, gpointer d) {
	GSList *type = (GSList *)d, *gconf = type->next, *toggle = gconf->next, *old = toggle->next, *gc = old->next;
	guint new = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget));

	if (new != (guint)(old->data)) {
		old->data = (gpointer)new;
		gconf_client_set_int(gc->data, gconf->data, new, NULL);
	}
}

GSList *gt_int(GConfClient *gcid, char *gconf, GtkWidget *w, guint max) {
	guint init = gconf_client_get_int(gcid, gconf, NULL);
	if ((init >= 0) && (init <= max)) {
		gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), init);
	}
	return gt_pair(gcid, gconf, w, (gpointer)init, "value-changed", gt_callback_spin_int, gt_callback_gconf_int, NULL);
}

void gt_callback_gconf_intmenu(GConfClient *client, guint cid, GConfEntry *e, gpointer d) {
	GSList *type = (GSList *)d, *gconf = type->next, *toggle = gconf->next, *old = toggle->next;

	if ((gconf_entry_get_value(e) != NULL) && (gconf_entry_get_value(e)->type == GCONF_VALUE_INT)) {
		guint new = gconf_value_get_int(gconf_entry_get_value(e));
		if ((guint)(old->data) != new) {
			old->data = (gpointer)new;
			gtk_combo_box_set_active(GTK_COMBO_BOX(toggle->data), new);
		}
	}
}

void gt_callback_menu_int(GtkWidget *widget, gpointer d) {
	GSList *type = (GSList *)d, *gconf = type->next, *toggle = gconf->next, *old = toggle->next, *gc = old->next;
	guint new = gtk_combo_box_get_active(GTK_COMBO_BOX(widget));

	if (new != (guint)(old->data)) {
		old->data = (gpointer)new;
		gconf_client_set_int(gc->data, gconf->data, new, NULL);
	}
}

GSList *gt_intmenu(GConfClient *gcid, char *gconf, GtkWidget *w) {
	guint init = gconf_client_get_int(gcid, gconf, NULL);
	if (init >= 0) {
		gtk_combo_box_set_active(GTK_COMBO_BOX(w), init);
	}
	return gt_pair(gcid, gconf, w, (gpointer)init, "changed", gt_callback_menu_int, gt_callback_gconf_intmenu, NULL);
}

void gt_callback_kill_color(GSList *pair) {
	g_free((GdkColor *)pair->next->next->next->data);
}

void gt_callback_gconf_color(GConfClient *client, guint cid, GConfEntry *e, gpointer d) {
	GSList *type = (GSList *)d, *gconf = type->next, *w = gconf->next, *old = w->next, *gc = old->next;
	GdkColor new;
	if ((gconf_entry_get_value(e) != NULL) && (gconf_entry_get_value(e)->type == GCONF_VALUE_STRING)) {
		const gchar *newc = gconf_value_get_string(gconf_entry_get_value(e));
		if (gdk_color_parse(newc, &new)) {
			if ((new.red != ((GdkColor *)(old->data))->red) || (new.green != ((GdkColor *)(old->data))->green) || (new.blue != ((GdkColor *)(old->data))->blue)) {
				((GdkColor *)(old->data))->red = new.red;
				((GdkColor *)(old->data))->green = new.green;
				((GdkColor *)(old->data))->blue = new.blue;
				gtk_color_button_set_color(GTK_COLOR_BUTTON(w->data), &new);
			}
		}
	}
}

void gt_callback_color_color(GtkWidget *w, gpointer d) {
	GSList *type = (GSList *)d, *gconf = type->next, *wi = gconf->next, *old = wi->next, *gc = old->next;
	GdkColor new;
	char code[8];

	gtk_color_button_get_color(GTK_COLOR_BUTTON(w), &new);

	if ((new.red != ((GdkColor *)(old->data))->red) || (new.green != ((GdkColor *)(old->data))->green) || (new.blue != ((GdkColor *)(old->data))->blue)) {
		((GdkColor *)(old->data))->red = new.red;
		((GdkColor *)(old->data))->green = new.green;
		((GdkColor *)(old->data))->blue = new.blue;
		g_sprintf(code, "#%02x%02x%02x", new.red >> 8, new.green >> 8, new.blue >> 8); // yeah!
		gconf_client_set_string(gc->data, gconf->data, code, NULL);
	}
}

GSList *gt_color(GConfClient *gcid, char *gconf, GtkWidget *w) {
	gchar *cinit = gconf_client_get_string(gcid, gconf, NULL);
	GdkColor *init = g_malloc(sizeof(GdkColor));

	if ((cinit == NULL) || !gdk_color_parse(cinit, init)) {
		init->red=0;
		init->green=0;
		init->blue=0;
	}

	if (cinit != NULL)
		g_free(cinit);

	gtk_color_button_set_color(GTK_COLOR_BUTTON(w), init);
	return gt_pair(gcid, gconf, w, (gpointer)init, "color-set", gt_callback_color_color, gt_callback_gconf_color, gt_callback_kill_color);
}

void gt_free(GSList *prefs) {
	GSList *head = prefs, *old;
	void (*freer)(GSList *);

	while (head != NULL) {
		freer = ((GSList *)(head->data))->data;
		if (freer != NULL)
			freer(head->data);
		g_slist_free(head->data);
		head = head->next;
	}

	g_slist_free(prefs);
}
