/*
 *  Copyright (C) 2003  Tommi Komulainen
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation. 
 *
 *  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 HAVE_CONFIG_H
#include "config.h"
#endif

#include "galeon-language-editor.h"

#include <glib/gi18n.h>
#include <glade/glade-xml.h>
#include <gtk/gtkcellrenderertext.h>
#include <gtk/gtkcelllayout.h>
#include <gtk/gtkstock.h>
#include <gtk/gtktreeselection.h>
#include <gtk/gtktreemodelsort.h>
#include <gtk/gtkcombobox.h>

#include "gul-glade.h"
#include "gul-gobject-misc.h"
#include "galeon-marshal.h"

#include <string.h>

static GtkDialogClass *parent_class;

enum {
	CHANGED,	/* indicate language selection changed */
	TITLE,		/* request a title for a custom value  */
	LAST_SIGNAL
};

static guint signals[LAST_SIGNAL] = { 0 };

/**
 * galeon_language_editor_set_available:
 * @languages: an array of #GulGuiOption items
 * @n_languages: number of items in @languages
 *
 * Sets the available languages and their titles.
 */
void
galeon_language_editor_set_available (GaleonLanguageEditor *self,
		                      const GulGuiOption   *languages,
				      guint                 n_languages)
{
	gul_gui_option_combobox_populate(GTK_COMBO_BOX(self->combobox),
					 languages, n_languages, TRUE);

	/* 
	 * Adding rows produces a warning if this is not done. *sigh*
	 */
	gtk_widget_realize(self->combobox);
}

/**
 * galeon_language_editor_set_selected:
 * @values: list of strings
 */
void
galeon_language_editor_set_selected (GaleonLanguageEditor *self, GSList *values)
{
	GtkListStore *store;
	GSList       *l;

	store = GTK_LIST_STORE(gtk_tree_view_get_model (GTK_TREE_VIEW(self->treeview)));
	gtk_list_store_clear (store);

	for (l = values; l != NULL; l = l->next)
	{
		const char   *value = l->data;
		GtkTreeIter   iter;
		gboolean      found = FALSE;
		gboolean      valid = FALSE;
		gchar        *title = NULL;

		GtkTreeModel *model = gtk_combo_box_get_model(GTK_COMBO_BOX(self->combobox)); 

		valid = gtk_tree_model_get_iter_first(model, &iter);
		while (valid)
		{
			gchar *iter_value, *iter_title;
			gtk_tree_model_get(model, &iter,
					   OPTION_COL_TITLE, &iter_title,
					   OPTION_COL_VALUE, &iter_value,
					   -1);
			if (strcmp(value, iter_value) == 0)
			{
				found = TRUE;
				title = iter_title;
				g_free(iter_value);
				break;
			}
			g_free(iter_title);
			g_free(iter_value);
			valid = gtk_tree_model_iter_next(model, &iter);
		}

		if (!found)
		{
			g_signal_emit (G_OBJECT(self), signals[TITLE], 0, value, &title);

			if (title != NULL)
			{
				GtkTreeIter new_iter;
				GtkTreeModel *real_model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(model));

				gtk_list_store_append(GTK_LIST_STORE(real_model), &new_iter);
				gtk_list_store_set(GTK_LIST_STORE(real_model), &new_iter,
						   OPTION_COL_TITLE, title,
						   OPTION_COL_VALUE, value,
						   -1);
				found = TRUE;
			}
		}

		if (found)
		{
			GtkTreeIter sel_iter;
			gtk_list_store_append (store, &sel_iter);
			gtk_list_store_set (store, &sel_iter,
					OPTION_COL_TITLE, title,
					OPTION_COL_VALUE, value,
					-1);
		}
	
		g_free(title);
	}
}

/** galeon_language_editor_get_selected:
 * @values: where to store the values or %NULL
 * @titles: where to store the titles or %NULL
 *
 * Get the currently selected list of languages.
 *
 * The lists and the strings in the lists must be freed by the caller.
 */
void
galeon_language_editor_get_selected (GaleonLanguageEditor *self,
		                     GSList **values, GSList **titles)
{
	GtkTreeModel *model;
	GtkTreeIter   iter;

	g_return_if_fail (values != NULL || titles != NULL);

	if (values) *values = NULL;
	if (titles) *titles = NULL;

	model = gtk_tree_view_get_model (GTK_TREE_VIEW(self->treeview));

	if (!gtk_tree_model_get_iter_first (model, &iter))
		return;

	do {
		gchar *title, *value;

		gtk_tree_model_get (model, &iter,
				OPTION_COL_TITLE, &title,
				OPTION_COL_VALUE, &value,
				-1);

		if (values)
		{
			 *values = g_slist_prepend (*values, value);
		}
		else
		{
			g_free(value);
		}

		if (titles)
		{
			*titles = g_slist_prepend (*titles, title);
		}
		else
		{
			g_free(title);
		}

	} while (gtk_tree_model_iter_next (model, &iter));

	if (values) *values = g_slist_reverse (*values);
	if (titles) *titles = g_slist_reverse (*titles);
}

static void
treeview_construct (GtkWidget *treeview)
{
	GtkListStore      *store;
	GtkTreeViewColumn *column;
	GtkCellRenderer   *renderer;

	g_return_if_fail (GTK_IS_TREE_VIEW(treeview));

	/* model */

	store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);

	/* view */

	column = gtk_tree_view_column_new ();

	renderer = gtk_cell_renderer_text_new ();
	gtk_tree_view_column_pack_start (column, renderer, TRUE);
	gtk_tree_view_column_add_attribute (column, renderer,
			                    "text", OPTION_COL_TITLE);

	gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), column);

	gtk_tree_view_set_model (GTK_TREE_VIEW(treeview),
			         GTK_TREE_MODEL(store));
}

static void
on_selection_changed (GtkTreeSelection *selection, GaleonLanguageEditor *self)
{
	GtkTreeModel     *model;
	GtkTreeIter       iter;
	gboolean          can_up, can_down, can_remove;

	if (gtk_tree_selection_get_selected (selection, &model, &iter))
	{
		GtkTreePath *path;

		path = gtk_tree_model_get_path (model, &iter);

		can_up     = gtk_tree_path_prev (path);
		can_down   = gtk_tree_model_iter_next (model, &iter);
		can_remove = TRUE;

		gtk_tree_path_free (path);
	}
	else
	{
		can_up = can_down = can_remove = FALSE;
	}

	gtk_widget_set_sensitive (self->remove, can_remove);
	gtk_widget_set_sensitive (self->up,     can_up);
	gtk_widget_set_sensitive (self->down,   can_down);
}

static void
update_buttons_sensitivity (GaleonLanguageEditor *self)
{
	GtkTreeSelection *selection;

	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(self->treeview));
	on_selection_changed (selection, self);
}

static void
on_add_clicked (GtkWidget *button, GaleonLanguageEditor *self)
{
	GtkListStore *store;
	GtkTreeIter   iter;
	GtkTreeIter   combo_iter;
	gchar *title, *value;

	g_return_if_fail(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(self->combobox),
						       &combo_iter));
	gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(self->combobox)), &combo_iter,
			   OPTION_COL_TITLE, &title,
			   OPTION_COL_VALUE, &value,
			   -1);

	store = GTK_LIST_STORE(gtk_tree_view_get_model (GTK_TREE_VIEW(self->treeview)));

	gtk_list_store_append (store, &iter);
	gtk_list_store_set (store, &iter,
			OPTION_COL_TITLE, title,
			OPTION_COL_VALUE, value,
			-1);

	g_free(title);
	g_free(value);

	update_buttons_sensitivity (self);
	g_signal_emit (G_OBJECT(self), signals[CHANGED], 0);
}

static void
on_remove_clicked (GtkWidget *button, GaleonLanguageEditor *self)
{
	GtkTreeSelection *selection;
	GtkTreeModel     *model;
	GtkTreeIter       iter;

	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(self->treeview));

	g_return_if_fail (gtk_tree_selection_get_selected (selection, &model, &iter));
	g_return_if_fail (GTK_IS_LIST_STORE(model));

	gtk_list_store_remove (GTK_LIST_STORE(model), &iter);

	g_signal_emit (G_OBJECT(self), signals[CHANGED], 0);
}

static void
on_up_clicked (GtkWidget *button, GaleonLanguageEditor *self)
{
	GtkTreeSelection *selection;
	GtkTreeModel     *model;
	GtkTreeIter       iter;
	GtkTreePath      *path;
	GtkTreeIter       prev;

	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(self->treeview));

	g_return_if_fail (gtk_tree_selection_get_selected (selection, &model, &iter));
	g_return_if_fail (GTK_IS_LIST_STORE(model));

	path = gtk_tree_model_get_path (model, &iter);
	g_return_if_fail (path != NULL);
	gtk_tree_path_prev (path);
	gtk_tree_model_get_iter (model, &prev, path);
	gtk_tree_path_free (path);

	gtk_list_store_swap (GTK_LIST_STORE(model), &iter, &prev);

	g_signal_emit (G_OBJECT(self), signals[CHANGED], 0);
	update_buttons_sensitivity (self);
}

static void
on_down_clicked (GtkWidget *button, GaleonLanguageEditor *self)
{
	GtkTreeSelection *selection;
	GtkTreeModel     *model;
	GtkTreeIter       iter;
	GtkTreeIter      *next;

	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(self->treeview));

	g_return_if_fail (gtk_tree_selection_get_selected (selection, &model, &iter));
	g_return_if_fail (GTK_IS_LIST_STORE(model));

	next = gtk_tree_iter_copy (&iter);
	gtk_tree_model_iter_next (model, next);
	gtk_list_store_swap (GTK_LIST_STORE(model), &iter, next);
	gtk_tree_iter_free (next);

	g_signal_emit (G_OBJECT(self), signals[CHANGED], 0);
	update_buttons_sensitivity (self);
}

/* GObject boilerplate */

GtkWidget *
galeon_language_editor_new (void)
{
	GaleonLanguageEditor *self;

	self = GALEON_LANGUAGE_EDITOR(g_object_new (
			GALEON_TYPE_LANGUAGE_EDITOR, 
			"title",         _("Edit Languages"),
			"has-separator", FALSE,
			"resizable",     TRUE,
			"border-width",  6,
			NULL));
	gtk_container_set_border_width (GTK_CONTAINER(GTK_DIALOG(self)->vbox), 0);
	gtk_container_set_border_width (GTK_CONTAINER(GTK_DIALOG(self)->action_area), 6);

	gtk_dialog_add_buttons (GTK_DIALOG(self), 
			        /* FIXME need docs
				 * GTK_STOCK_HELP,  GTK_RESPONSE_HELP,
				 */
			        GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
				NULL);

	return GTK_WIDGET(self);
}

static void
galeon_language_editor_init (GaleonLanguageEditor *self)
{
	GladeXML         *gxml;
	GtkWidget        *content;
	GtkTreeSelection *selection;

	gxml = gul_glade_widget_new ("prefs-dialog.glade", "language_dialog", NULL, self);
	g_return_if_fail (gxml != NULL);

	gul_glade_get_widgets (gxml,
			"content_area",  &content,
			"combobox",    &self->combobox,
			"treeview",      &self->treeview,
			"add_button",    &self->add,
			"remove_button", &self->remove,
			"up_button",     &self->up,
			"down_button",   &self->down,
			NULL);

	gtk_widget_reparent (content, GTK_DIALOG(self)->vbox);

	treeview_construct (self->treeview);

	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(self->treeview));
	g_signal_connect (G_OBJECT(selection), "changed", G_CALLBACK(on_selection_changed), self);
	on_selection_changed (selection, self);

	g_signal_connect (G_OBJECT(self->add),    "clicked", G_CALLBACK(on_add_clicked),    self);
	g_signal_connect (G_OBJECT(self->remove), "clicked", G_CALLBACK(on_remove_clicked), self);
	g_signal_connect (G_OBJECT(self->up),     "clicked", G_CALLBACK(on_up_clicked),     self);
	g_signal_connect (G_OBJECT(self->down),   "clicked", G_CALLBACK(on_down_clicked),   self);

	g_object_unref (gxml);
}

static void
galeon_language_editor_finalize (GObject *object)
{
	G_OBJECT_CLASS(parent_class)->finalize (object);
}

static void
galeon_language_editor_class_init (GaleonLanguageEditorClass *klass)
{
	GObjectClass *object_class = G_OBJECT_CLASS(klass);

	parent_class = g_type_class_peek_parent (klass);

	object_class->finalize = galeon_language_editor_finalize;

	signals[CHANGED] = 
		g_signal_new ("changed",
			G_OBJECT_CLASS_TYPE (klass),
			G_SIGNAL_RUN_FIRST,
			G_STRUCT_OFFSET (GaleonLanguageEditorClass, changed),
			NULL, NULL,
			g_cclosure_marshal_VOID__VOID,
			G_TYPE_NONE, 0);

	signals[TITLE] =
		g_signal_new ("title",
			G_OBJECT_CLASS_TYPE (klass),
			G_SIGNAL_RUN_LAST,
			G_STRUCT_OFFSET (GaleonLanguageEditorClass, title),
			NULL, NULL,
			galeon_marshal_STRING__STRING,
			G_TYPE_STRING, 1,
			G_TYPE_STRING);
}

GUL_TYPE_FUNC(galeon_language_editor, GaleonLanguageEditor, GTK_TYPE_DIALOG)
