/*
 *  Copyright (C) 2001 Jorn Baayen
 *
 *  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, 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.
 */

#include "galeon.h"
#include "misc.h"
#include "window.h"
#include "toolbar.h"
#include "toolbar_editor.h"
#include "glade.h"

#include <string.h>
#include <gtk/gtktogglebutton.h>
#include <libgnome/gnome-i18n.h>
#include <libgnome/gnome-config.h>

/* glade callbacks */
void toolbar_editor_add_clicked_cb (GtkWidget *button, PreferencesDialog *pd);
void toolbar_editor_remove_clicked_cb (GtkWidget *button, 
				       PreferencesDialog *pd);
void toolbar_editor_move_up_clicked_cb (GtkWidget *button, 
					PreferencesDialog *pd);
void toolbar_editor_move_down_clicked_cb (GtkWidget *button, 
					  PreferencesDialog *pd);
void available_clist_select_row_cb (GtkCList *clist, gint row, gint column,
				    GdkEventButton *event, 
				    PreferencesDialog *pd);
void available_clist_unselect_row_cb (GtkCList *clist, gint row, gint column,
				      GdkEventButton *event, 
				      PreferencesDialog *pd);
void available_clist_double_click_cb (GtkCList *clist, GdkEventButton *event,
				      PreferencesDialog *pd);
void current_clist_select_row_cb (GtkCList *list, gint row, gint column,
				  GdkEventButton *event, 
				  PreferencesDialog *pd);
void current_clist_unselect_row_cb (GtkCList *clist, gint row, gint column,
				    GdkEventButton *event, 
				    PreferencesDialog *pd);
void current_clist_double_click_cb (GtkCList *clist, GdkEventButton *event,
				    PreferencesDialog *pd);
void current_clist_drag_end_cb (GtkWidget *widget, GdkEvent *event,
				PreferencesDialog *pd);
static void set_button_sensitivity (PreferencesDialog *pd);
static GSList *get_selected_types (GtkCList *clist);
static GList *get_selected_rows (GtkCList *clist);
static gint sort_by_row_cb (const gpointer *r1, const gpointer *r2);
static void add_item (ToolbarItemType type, PreferencesDialog *pd);
static void remove_item (ToolbarItemType type, PreferencesDialog *pd);

/* local variables */
static gint current_clist_selected_row;
static gint available_clist_selected_row;

void
toolbar_editor_add_clicked_cb (GtkWidget *button, PreferencesDialog *pd)
{
	GtkCList *alist = GTK_CLIST (pd->available_clist);
	GtkCList *clist = GTK_CLIST (pd->current_clist);
	ToolbarItemType type;
	GSList *sl, *selection = NULL;

	/* freeze both lists */
	gtk_clist_freeze (alist);
	gtk_clist_freeze (clist);

	/* iterate over list doing actions */
	selection = get_selected_types (alist);
	for (sl = selection; sl != NULL; sl = g_slist_next (sl))
	{
		/* get this */
		type = GPOINTER_TO_INT (sl->data);

		/* add type to current list */
		add_item (type, pd);
	}

	/* free up list */
	g_slist_free (selection);

	/* thaw */
	gtk_clist_thaw (alist);
	gtk_clist_thaw (clist);
}

void
toolbar_editor_remove_clicked_cb (GtkWidget *button, PreferencesDialog *pd)
{
	GtkCList *alist = GTK_CLIST (pd->available_clist);
	GtkCList *clist = GTK_CLIST (pd->current_clist);
	GSList *sl, *selection = NULL;
	ToolbarItemType type;

	/* freeze both lists */
	gtk_clist_freeze (alist);
	gtk_clist_freeze (clist);

	/* iterate over list doing actions */
	selection = get_selected_types (clist);
	for (sl = selection; sl != NULL; sl = g_slist_next (sl))
	{
		/* get this */
		type = GPOINTER_TO_INT (sl->data);

		/* remove from current list */
		remove_item (type, pd);
	}

	/* fre up list */
	g_slist_free (selection);

	/* resort and thaw */
	gtk_clist_sort (alist);
	gtk_clist_thaw (alist);
	gtk_clist_thaw (clist);
}

void
toolbar_editor_move_up_clicked_cb (GtkWidget *button, PreferencesDialog *pd)
{
	GtkCList *clist = GTK_CLIST (pd->current_clist);
	GList *selection, *l;
	gint row;

	/* freeze current list */
	gtk_clist_freeze (clist);

	/* iterate over list in forward order */
	selection = get_selected_rows (clist);
	for (l = selection; l != NULL; l = g_list_next (l))
	{
		/* get row number */
		row = GPOINTER_TO_INT (l->data);

		/* swap with one above */
		gtk_clist_row_move (clist, row, row - 1);

		/* update button sensitivity */
		set_button_sensitivity (pd);
	}
	g_list_free (selection);

	/* thaw */
	gtk_clist_thaw (clist);
}

void
toolbar_editor_move_down_clicked_cb (GtkWidget *button, PreferencesDialog *pd)
{
	GtkCList *clist = GTK_CLIST (pd->current_clist);
	GList *selection, *l;
	gint row;

	/* freeze current list */
	gtk_clist_freeze (clist);

	/* iterate over list in reverse order */
	selection = g_list_reverse (get_selected_rows (clist));
	for (l = selection; l != NULL; l = g_list_next (l))
	{
		/* get row number */
		row = GPOINTER_TO_INT (l->data);

		/* swap with one below */
		gtk_clist_row_move (clist, row, row + 1);
		
		/* update button sensitivity */
		set_button_sensitivity (pd);
	}
	g_list_free (selection);

	/* thaw */
	gtk_clist_thaw (clist);
}

void
available_clist_select_row_cb (GtkCList *clist, gint row, gint column,
			       GdkEventButton *event, PreferencesDialog *pd)
{
	available_clist_selected_row = row;

	/* unselect current list */
	gtk_clist_unselect_all (GTK_CLIST (pd->current_clist));
	
	/* update button sensitivity */
	set_button_sensitivity (pd);
}

void
available_clist_double_click_cb (GtkCList *clist, GdkEventButton *event,
				 PreferencesDialog *pd)
{
	if (event->button == 1 && event->type == GDK_2BUTTON_PRESS)
	{
		GtkCList *alist = GTK_CLIST (pd->available_clist);
		GtkCList *clist = GTK_CLIST (pd->current_clist);
		ToolbarItemType type;
		gpointer p;

		/* freeze both lists */
		gtk_clist_freeze (alist);
		gtk_clist_freeze (clist);

		/* get selected type */
		p = (GTK_CLIST_ROW (g_list_nth (alist->row_list, 
				    available_clist_selected_row))->data);
		type = GPOINTER_TO_INT (p);

		/* add to current list */
		add_item (type, pd);

		/* thaw */
		gtk_clist_thaw (alist);
		gtk_clist_thaw (clist);
	}
}

void
available_clist_unselect_row_cb (GtkCList *clist, gint row, gint column,
				 GdkEventButton *event, PreferencesDialog *pd)
{
	/* update button sensitivity */
	set_button_sensitivity (pd);
}

void 
current_clist_select_row_cb (GtkCList *clist, gint row, gint column,
			     GdkEventButton *event, PreferencesDialog *pd)
{
	current_clist_selected_row = row;

	/* unselect available list */
	gtk_clist_unselect_all (GTK_CLIST (pd->available_clist));
	
	/* update button sensitivity */
	set_button_sensitivity (pd);
}

void
current_clist_unselect_row_cb (GtkCList *clist, gint row, gint column,
			       GdkEventButton *event, PreferencesDialog *pd)
{	
	/* update button sensitivity */
	set_button_sensitivity (pd);
}

void
current_clist_drag_end_cb (GtkWidget *widget, GdkEvent *event,
			   PreferencesDialog *pd)
{
	/* update button sensitivity */
	set_button_sensitivity (pd);
}

void
current_clist_double_click_cb (GtkCList *clist, GdkEventButton *event,
			       PreferencesDialog *pd)
{
	if (event->button == 1 && event->type == GDK_2BUTTON_PRESS)
	{
		GtkCList *alist = GTK_CLIST (pd->available_clist);
		GtkCList *clist = GTK_CLIST (pd->current_clist);
		ToolbarItemType type;
		gpointer p;

		/* freeze both lists */
		gtk_clist_freeze (alist);
		gtk_clist_freeze (clist);

		/* get selected type */
		p = (GTK_CLIST_ROW (g_list_nth (clist->row_list, 
				    current_clist_selected_row))->data);
		type = GPOINTER_TO_INT (p);

		/* remove from current list */
		remove_item (type, pd);

		/* resort and thaw */
		gtk_clist_sort (alist);
		gtk_clist_thaw (alist);
		gtk_clist_thaw (clist);
	}
}

static void
set_button_sensitivity (PreferencesDialog *pd)
{
	GtkCList *alist = GTK_CLIST (pd->available_clist);
	GtkCList *clist = GTK_CLIST (pd->current_clist);
	gboolean add_button_sensitive;
	gboolean remove_button_sensitive;
	gboolean up_button_sensitive;
	gboolean down_button_sensitive;
	
	/* compute states */
	add_button_sensitive = (alist->selection != NULL);
	remove_button_sensitive = (clist->selection != NULL);
	up_button_sensitive = 
		(remove_button_sensitive && 
		 g_list_find (clist->selection, GINT_TO_POINTER (0)) == NULL);
	down_button_sensitive = 
		(remove_button_sensitive && 
		 g_list_find (clist->selection, 
			      GINT_TO_POINTER (clist->rows - 1)) == NULL);
	
        /* set buttons */
	gtk_widget_set_sensitive (pd->add_button,    add_button_sensitive);
	gtk_widget_set_sensitive (pd->remove_button, remove_button_sensitive);
	gtk_widget_set_sensitive (pd->up_button,     up_button_sensitive);
	gtk_widget_set_sensitive (pd->down_button,   down_button_sensitive);
}

static GSList *
get_selected_types (GtkCList *clist)
{
	GSList *selection = NULL;
	gpointer data;
	GList *l;
	gint row;

	/* iterate over selection, add type to list */
	for (l = clist->selection; l != NULL; l = g_list_next (l))
	{
		/* get this row type */
		row = GPOINTER_TO_INT (l->data);
		data = gtk_clist_get_row_data (clist, row);

		/* add to list */
		selection = g_slist_prepend (selection, data);
	}

	/* finished */
	return selection;
}

static GList *
get_selected_rows (GtkCList *clist)
{
	GList *selection;

	/* copy selection */
	selection = g_list_copy (clist->selection);

	/* sort by row */
	return g_list_sort (selection, (GCompareFunc)sort_by_row_cb);
}

static gint
sort_by_row_cb (const gpointer *r1, const gpointer *r2)
{
	gint n1 = GPOINTER_TO_INT (r1);
	gint n2 = GPOINTER_TO_INT (r2);
	
	return n1 - n2;
}

static void
add_item (ToolbarItemType type, PreferencesDialog *pd)
{
	GtkCList *alist = GTK_CLIST (pd->available_clist);
	GtkCList *clist = GTK_CLIST (pd->current_clist);
	ToolbarItemType this_type;
	gint i, row;

	/* scan down current list to find a suitable insertion point */
	for (i = 0; i < clist->rows; i++)
	{
		/* get this row type */
		this_type = GPOINTER_TO_INT (gtk_clist_get_row_data 
					     (clist, i));
		
		/* break out if this is a suitable row */
		if (toolbar_items[type].order < 
		    toolbar_items[this_type].order)
		{
			break;
		}
	}

	/* remove from available list unless separator */
	if (type != TOOLBAR_ITEM_SEPARATOR)
	{
		toolbar_editor_remove_item (alist, type);
	}
	
	/* insert into current list */
	row = toolbar_editor_insert_item (clist, type);
	gtk_clist_row_move (clist, row, i);
	gtk_clist_select_row (clist, i, 0);
}

static void
remove_item (ToolbarItemType type, PreferencesDialog *pd)
{
	GtkCList *alist = GTK_CLIST (pd->available_clist);
	GtkCList *clist = GTK_CLIST (pd->current_clist);
	gint row;

	/* add to the available list unless separator */
	if (type != TOOLBAR_ITEM_SEPARATOR)
	{
		row = toolbar_editor_insert_item (alist, type);
		gtk_clist_select_row (alist, row, 0);
	}
		
	/* remove from current list */
	toolbar_editor_remove_item (clist, type);
}
