/*
 *  Copyright (C) 2000 Marco Pesenti Gritti
 *
 *  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 "history.h"
#include "embed.h"
#include "window.h"
#include "state.h"
#include "misc.h"
#include "eel-gconf-extensions.h"

#include <libgnome/gnome-defs.h>
#include <libgnome/gnome-config.h>
#include <gtk/gtkcheckmenuitem.h>
#include <gtk/gtkctree.h>
#include <gtk/gtktogglebutton.h>
#include <gtk/gtkcheckbutton.h>
#include <gtk/gtkmenu.h>
#include <gtk/gtkoptionmenu.h>
#include <gtk/gtkmenushell.h>
#include <gtk/gtkentry.h>
#include <gdk/gdkkeysyms.h>

/* local function prototypes */
gboolean history_clist_button_press_event_cb (GtkWidget *widget, 
					      GdkEventButton *event,
					      HistoryView *hv);
gboolean history_clist_key_press_event_cb (GtkWidget *widget,
					GdkEventKey *event, HistoryView *hv);
gboolean history_dialog_delete_event_cb (GtkWidget *widget, GdkEvent *event, 
					 HistoryView *hv);
gboolean history_dialog_close_cb (GtkWidget *widget, HistoryView *hv);
void history_ok_button_clicked_cb(GtkButton *button, HistoryView *hv);
void history_attach_button_clicked_cb(GtkButton *button, HistoryView *hv);
void history_dock_close_button_clicked_cb (GtkButton *button, 
					   HistoryView *hv);
void history_dock_detach_button_clicked_cb (GtkButton *button, 
					    HistoryView *hv);
void history_entry_activate_cb (GtkEditable *editable,
				HistoryView *hv);
void history_time_optionmenu_leave_cb (GtkOptionMenu *optionmenu,
				       HistoryView *hv);
void history_host_checkbutton_toggled_cb (GtkCheckButton *check_button,
					  HistoryView *hv);
void history_dock_destroy_cb (GtkWidget *dock, HistoryView *hv);
void history_ctree_click_column_cb (GtkCTree *ctree, gint column,
				    HistoryView *hv);

/* FIXME: tidy */
static void 
history_handle_link_clicked (HistoryView *hv, LinkState state)
{
	GaleonEmbed *embed = NULL, *new = NULL;
	if (!hv->selected_item)
	{
		return;
	}

	/* Check if the window that is selected is already (still) open */
	if (hv->window && !g_list_find (all_windows, hv->window))
	{
		hv->window = NULL;
	}
	if (hv->window)
	{
		embed = hv->window->active_embed;
	}

	embed_activate_link (embed, &new, hv->selected_item->url, state);

	/* remember created window if necessary */
	if (!hv->window && new)
	{
		hv->window = new->parent_window;
	}
}

/**
 * Loads the selected row in the browser
 */
gboolean
history_clist_button_press_event_cb (GtkWidget *widget, GdkEventButton *event,
				     HistoryView *hv)
{
        gint arow, acolumn;

	/* get the selection */
        gtk_clist_get_selection_info (GTK_CLIST (hv->ctree), 
				      event->x, event->y, &arow, &acolumn);

	/* get the item that's been selected */
	hv->selected_item = gtk_clist_get_row_data (GTK_CLIST (widget), arow);

	/* select it unless it's a left button selection */
        if (event->button != 1)
	{
                gtk_clist_select_row (GTK_CLIST (hv->ctree), arow, acolumn);
        }

	/* double click or middle click opens the window */
	if (event->button != 1 || event->type == GDK_2BUTTON_PRESS)
	{
		history_handle_link_clicked (hv, 
		       mouse_state_to_link_state (event->button, 
						  event->state));
	}

        return FALSE;
}

/**
 * Make Return key load the selected item rather than close the dialog
 */
gboolean
history_clist_key_press_event_cb (GtkWidget *widget, GdkEventKey *event,
				     HistoryView *hv)
{
	/* get the item that's been selected */
	hv->selected_item = gtk_clist_get_row_data (GTK_CLIST (widget),
					GTK_CLIST (hv->ctree)->focus_row);

	if (event->keyval == GDK_Return)
	{
		history_handle_link_clicked (hv, 
				key_state_to_link_state(event->state));
		/* stop event from closing the dialog */
		gtk_signal_emit_stop_by_name (GTK_OBJECT(widget),
				"key-press-event");
		return TRUE;
	}
	return FALSE;
}

/**
 * Hides the window
 */
gboolean
history_dialog_delete_event_cb (GtkWidget *widget, GdkEvent *event,
				HistoryView *hv)
{
	history_hide_dialog (hv);
        return TRUE;
}

/**
 * Hides the window
 */
gboolean
history_dialog_close_cb (GtkWidget *widget, HistoryView *hv)
{
	history_hide_dialog (hv);
	return FALSE;
}

/**
 * Hides the window
 */
void
history_ok_button_clicked_cb (GtkButton *button, HistoryView *hv)
{
	history_hide_dialog (hv);
}

/**
 * Hides the dock
 */
void
history_dock_close_button_clicked_cb (GtkButton *button, HistoryView *hv)
{
	return_if_not_window (hv->window);
	window_undock (hv->window);
}

/*
 * history_entry_activate_cb: search text is changed, update the tree
 */
void 
history_entry_activate_cb (GtkEditable *editable, HistoryView *hv)
{
	/* free existing text */
	if (hv->search != NULL)
	{
		g_free (hv->search);
	}

	/* get the text */
	hv->search = g_strdup (gtk_entry_get_text (GTK_ENTRY (editable)));
	
	/* store in config */
	eel_gconf_set_string (CONF_HISTORY_SEARCH_TEXT, hv->search);
}

/*
 * history_time_optionmenu_deactivate_cb: time option menu is changed
 * update the tree
 */
void
history_time_optionmenu_deactivate_cb (GtkWidget *menushell, HistoryView *hv)
{
	GtkWidget *active_item;

	/* find which item has been selected */
	active_item = gtk_menu_get_active (GTK_MENU (menushell));
	hv->time = g_list_index (GTK_MENU_SHELL (menushell)->children,
				 active_item);

	/* store in config */
	eel_gconf_set_integer (CONF_HISTORY_SEARCH_TIME, hv->time);
}

/*
 * history_host_checkbutton_toggled_cb: the host group checkbox status is
 * changed, update the tree
 */
void
history_host_checkbutton_toggled_cb (GtkCheckButton *check_button,
				     HistoryView *hv)
{
	/* get new state */
	hv->group = gtk_toggle_button_get_active 
		(GTK_TOGGLE_BUTTON (check_button));

	/* store in config */
	eel_gconf_set_boolean (CONF_HISTORY_HOST_GROUP, hv->group);
}

void 
history_attach_button_clicked_cb (GtkButton *button, HistoryView *hv)
{
	GaleonWindow *window;

	window = hv->window;
	return_if_not_window (window);
	eel_gconf_set_boolean (CONF_STATE_HISTORY_DOCK_ENABLE, TRUE);
	history_hide_dialog (hv);
	history_show_dock (window);
}


void 
history_dock_detach_button_clicked_cb (GtkButton *button, HistoryView *hv)
{
	GaleonWindow *window;

	window = hv->window;
	return_if_not_window (window);
	eel_gconf_set_boolean (CONF_STATE_HISTORY_DOCK_ENABLE, FALSE);
	window_undock (window);
	history_show_dialog (window);
}

/**
 * history_hide_destroy_cb: called when the dock is destroyed
 */
void 
history_dock_destroy_cb (GtkWidget *dock, HistoryView *hv)
{
	history_notifiers_remove ();

	/* save dock column widths */
	state_save_column_widths (hv->ctree, "history_dock");	

	/* destroy the view structure */
	history_destroy_view (hv);
}

/**
 * history_ctree_click_column_cb: called when a column is clicked, change
 * the sort type accordingly.
 */
void
history_ctree_click_column_cb (GtkCTree *ctree, gint column, HistoryView *hv)
{
	gint sort_column;
	gint sort_order;

	/* fetch current setup */
	sort_column = eel_gconf_get_integer (CONF_HISTORY_SORT_COLUMN);
	sort_order  = eel_gconf_get_integer (CONF_HISTORY_SORT_ORDER);

	/* if we're already sorting on this column, reverse the sort */
	if (sort_column == column)
	{
		if (sort_order == GTK_SORT_ASCENDING)
		{
			sort_order = GTK_SORT_DESCENDING;
		}
		else
		{
			sort_order = GTK_SORT_ASCENDING;
		}
	}
	else
	{
		sort_order = GTK_SORT_ASCENDING;
	}

	/* store new setup */
        eel_gconf_set_integer (CONF_HISTORY_SORT_COLUMN, column);
	eel_gconf_set_integer (CONF_HISTORY_SORT_ORDER, sort_order);
}

/**
 * history_compare_title_cb; compare function for "sort on last title"
 */
gint 
history_compare_title_cb (gconstpointer a, gconstpointer b)
{
	HistoryItem *hi1 = (HistoryItem *)((GTK_CTREE_ROW (a)->row).data);
	HistoryItem *hi2 = (HistoryItem *)((GTK_CTREE_ROW (b)->row).data);

	return g_strcasecmp (hi1->title_utf8, hi2->title_utf8);
}

/**
 * history_compare_url_cb; compare function for "sort on last url"
 */
gint 
history_compare_url_cb (gconstpointer a, gconstpointer b)
{
	HistoryItem *hi1 = (HistoryItem *)((GTK_CTREE_ROW (a)->row).data);
	HistoryItem *hi2 = (HistoryItem *)((GTK_CTREE_ROW (b)->row).data);

	return g_strcasecmp (hi1->url, hi2->url);
}

/**
 * history_compare_last_cb: compare function for "sort on last visit"
 */
gint 
history_compare_last_cb (gconstpointer a, gconstpointer b)
{
	HistoryItem *hi1 = (HistoryItem *)((GTK_CTREE_ROW (a)->row).data);
	HistoryItem *hi2 = (HistoryItem *)((GTK_CTREE_ROW (b)->row).data);

	return (hi2->last - hi1->last);
}

/**
 * history_compare_first_cb: compare function for "sort on first visit"
 */
gint 
history_compare_first_cb (gconstpointer a, gconstpointer b)
{
	HistoryItem *hi1 = (HistoryItem *)((GTK_CTREE_ROW (a)->row).data);
	HistoryItem *hi2 = (HistoryItem *)((GTK_CTREE_ROW (b)->row).data);

	return (hi2->first - hi1->first);
}

/**
 * history_compare_visits_cb: compare function for "sort on number of visits"
 */
gint 
history_compare_visits_cb (gconstpointer a, gconstpointer b)
{
	HistoryItem *hi1 = (HistoryItem *)((GTK_CTREE_ROW (a)->row).data);
	HistoryItem *hi2 = (HistoryItem *)((GTK_CTREE_ROW (b)->row).data);

	return (hi2->visits - hi1->visits);
}

/**
 * history_periodic_save_cb: save the history (if dirty) every once in a while
 */
gboolean
history_periodic_save_cb (gpointer data)
{
	/* save it */
	history_save ();

	/* call again */
	return TRUE;
}

void
history_properties_notifier (GConfClient *client,
			     guint cnxn_id,
			     GConfEntry *entry,
			     gpointer user_data)
{
	/* refresh view */
	history_refresh_view ((HistoryView *)(user_data));
}

void
history_sort_notifier (GConfClient *client,
		       guint cnxn_id,
		       GConfEntry *entry,
		       gpointer user_data)
{
	/* request a re-sort */
	history_resort_view ((HistoryView *)(user_data));
}
