/*
 *  Copyright (C) 2002  Ricardo Fernández Pascual
 *  Copyright (C) 2004  Crispin Flowerday
 *
 *  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.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <glib/gi18n.h>

#include "galeon-recent-history-menu.h"
#include <gtk/gtkuimanager.h>
#include <gtk/gtkactiongroup.h>
#include <gtk/gtkaction.h>

#include "galeon-shell.h"
#include "galeon-favicon-cache.h"
#include "galeon-window.h"
#include "galeon-favicon-action.h"
#include "gul-gobject-misc.h"
#include "galeon-marshal.h"
#include "gul-string.h"
#include "gul-gui.h"
#include "galeon-debug.h"

/**
 * Private data
 */
struct _GaleonRecentHistoryMenuPrivate
{
	GaleonWindow *window;
	GtkActionGroup *action_group;
	GaleonWindowRecentHistory *recent_history;
	guint rebuild_timeout;
	guint merge_id;
};

enum
{
	PROP_0,
	PROP_WINDOW,
	PROP_RECENT_HISTORY
};

static gpointer g_object_class;

#define RECENT_HISTORY_MENU_PLACEHOLDER "/menubar/Go/RecentHistoryMenuPlaceholder"
#define MENU_ITEM_MAX_LENGTH 40
#define REBUILD_TIMEOUT 700

static void
activate_tab_cb (GtkAction *action, GaleonRecentHistoryMenu *menu)
{
	/* NOTE, the tooltip is the url */

	char *tooltip;
	g_object_get (G_OBJECT (action), "tooltip", &tooltip, NULL);
	galeon_window_load_url (menu->priv->window, tooltip);
	g_free (tooltip);
}

static GtkAction *
get_action (GaleonRecentHistoryMenu *menu, int num)
{
	GaleonRecentHistoryMenuPrivate *p = menu->priv;
	char *name;
	GtkAction  *action;

	name = g_strdup_printf ("GaleonWindowRecentTab%dAction", num);
	
	action = gtk_action_group_get_action (p->action_group, name);
	if (action)
	{
		g_free (name);
		return action;
	}

	/* Create the action */
	action = g_object_new (GALEON_TYPE_FAVICON_ACTION,
			       "name", name,
			       NULL);

	g_signal_connect_object (action, "activate",
				 G_CALLBACK (activate_tab_cb),
				 menu, 0);
	gtk_action_group_add_action (menu->priv->action_group, action);
	g_object_unref (action);

	g_free (name);
	return action;
}


static void
galeon_recent_history_menu_rebuild (GaleonRecentHistoryMenu *menu)
{
	GaleonRecentHistoryMenuPrivate *p = menu->priv;
	GtkUIManager *merge = GTK_UI_MANAGER (p->window->merge);
	int num, i;
	
	if (p->merge_id > 0)
	{
		gtk_ui_manager_remove_ui (merge, p->merge_id);
		gtk_ui_manager_ensure_update (merge);
		p->merge_id = 0;
	}
	LOG ("Rebuilding recent history menu");

	if (!p->recent_history) return;

	galeon_window_recent_history_get_num_items (p->recent_history, &num);

	if (!num) return;

	p->merge_id = gtk_ui_manager_new_merge_id (merge);

	for (i = 0; i < num; i++)
	{
		gchar *url, *title, *title_s, *escape_title, *label;
		gchar name[128];
		GtkAction *action = get_action (menu, i);

		galeon_window_recent_history_get_item (p->recent_history,
						       i, &url, &title);

		title_s = gul_string_shorten(title, MENU_ITEM_MAX_LENGTH);
		escape_title = gul_string_double_underscores (title_s);
		label = gul_string_new_num_accel (i, escape_title, TRUE);

		/* NOTE, the tooltip is the url */
		g_object_set (action,
			      "tooltip", url,
			      "label", label,
			      "url", url,
			      NULL);
		g_free (title_s);
		g_free (escape_title);
		g_free (url);
		g_free (title);
		g_free (label);

		g_snprintf (name, sizeof(name), "%sItem", gtk_action_get_name (action));

		gtk_ui_manager_add_ui (merge, p->merge_id,
				       RECENT_HISTORY_MENU_PLACEHOLDER,
				       name,
				       gtk_action_get_name (action),
				       GTK_UI_MANAGER_MENUITEM, FALSE);
	}
}


static gboolean
galeon_recent_history_menu_rebuild_timeout_cb (gpointer data)
{
	GaleonRecentHistoryMenu *gm = data;
	GaleonRecentHistoryMenuPrivate *p = gm->priv;
	LOG ("GaleonRecentHistoryMenu rebuild timeout");

	p->rebuild_timeout = 0;

	galeon_recent_history_menu_rebuild (data);
	return FALSE;
}

static void 
galeon_recent_history_menu_rebuild_with_timeout (GaleonRecentHistoryMenu *gm) 
{
	GaleonRecentHistoryMenuPrivate *p = gm->priv;

	LOG ("galeon_recent_history_menu_rebuild_with_timeout");

	if (p->rebuild_timeout)
	{
		g_source_remove (p->rebuild_timeout);
	}
	
	p->rebuild_timeout = g_timeout_add (REBUILD_TIMEOUT, 
					    galeon_recent_history_menu_rebuild_timeout_cb, gm);
}

static void
galeon_recent_history_menu_set_recent_history (GaleonRecentHistoryMenu *menu,
					       GaleonWindowRecentHistory *history)
{
	GaleonRecentHistoryMenuPrivate *p = menu->priv;
	p->recent_history = g_object_ref (history);

	g_signal_connect_object (history, "changed",
				 G_CALLBACK (galeon_recent_history_menu_rebuild_with_timeout),
				 menu, G_CONNECT_SWAPPED);
}

static void
galeon_recent_history_menu_set_window (GaleonRecentHistoryMenu *menu, GaleonWindow *window)
{
	GtkUIManager *merge;
	GaleonRecentHistoryMenuPrivate *p = menu->priv;
	
	p->window = window;

	/* Create the Action Group */
	merge = GTK_UI_MANAGER (window->merge);
	menu->priv->action_group = gtk_action_group_new ("RecentHistoryActions");
	gtk_action_group_set_translation_domain (menu->priv->action_group, NULL);
	gtk_ui_manager_insert_action_group(merge, p->action_group, 0);
}


static void
galeon_recent_history_menu_set_property (GObject *object,
					 guint prop_id,
					 const GValue *value,
					 GParamSpec *pspec)
{
	GaleonRecentHistoryMenu *m = GALEON_RECENT_HISTORY_MENU (object);

	switch (prop_id)
	{
	case PROP_WINDOW:
		galeon_recent_history_menu_set_window 
			(m, GALEON_WINDOW (g_value_get_object (value)));
		break;
	case PROP_RECENT_HISTORY:
		galeon_recent_history_menu_set_recent_history 
			(m, GALEON_WINDOW_RECENT_HISTORY (g_value_get_object (value)));
	default: 
		break;
	}
}

static void
galeon_recent_history_menu_get_property (GObject *object,
					 guint prop_id,
					 GValue *value,
					 GParamSpec *pspec)
{
	GaleonRecentHistoryMenu *m = GALEON_RECENT_HISTORY_MENU (object);
	
	switch (prop_id)
	{
	case PROP_WINDOW:
		g_value_set_object (value, m->priv->window);
		break;
	case PROP_RECENT_HISTORY:
		g_value_set_object (value, m->priv->recent_history);
	default: 
		break;
	}
}


static void
galeon_recent_history_menu_finalize_impl(GObject *o)
{
	GaleonRecentHistoryMenu *gm = GALEON_RECENT_HISTORY_MENU(o);
	GaleonRecentHistoryMenuPrivate *p = gm->priv;
	GtkUIManager *merge = GTK_UI_MANAGER (p->window->merge);

	if (p->merge_id > 0)
	{
		gtk_ui_manager_remove_ui (merge, p->merge_id);
	}

	if (p->action_group)
	{
		gtk_ui_manager_remove_action_group
			(merge, p->action_group);
		g_object_unref (p->action_group);
	}

	if (p->rebuild_timeout)
	{
		g_source_remove (p->rebuild_timeout);
	}

	g_object_unref (p->recent_history);

	g_free(p);

	G_OBJECT_CLASS(g_object_class)->finalize (o);
}

static void 
galeon_recent_history_menu_init(GaleonRecentHistoryMenu *m)
{
	GaleonRecentHistoryMenuPrivate *p = g_new0 (GaleonRecentHistoryMenuPrivate, 1);
	m->priv = p;
}

static void
galeon_recent_history_menu_class_init(GaleonRecentHistoryMenuClass *klass)
{
	GObjectClass *object_class = G_OBJECT_CLASS (klass);
	g_object_class = g_type_class_peek_parent(klass);

	object_class->set_property = galeon_recent_history_menu_set_property;
	object_class->get_property = galeon_recent_history_menu_get_property;
	object_class->finalize = galeon_recent_history_menu_finalize_impl;

	g_object_class_install_property (object_class,
                                         PROP_WINDOW,
                                         g_param_spec_object ("GaleonWindow",
                                                              "GaleonWindow",
                                                              "Parent window",
                                                              GALEON_WINDOW_TYPE,
                                                              G_PARAM_READWRITE |
							      G_PARAM_CONSTRUCT_ONLY));
	g_object_class_install_property (object_class,
                                         PROP_RECENT_HISTORY,
                                         g_param_spec_object ("RecentHistory",
                                                              "RecentHistory",
                                                              "Recent history",
							      GALEON_TYPE_WINDOW_RECENT_HISTORY,
                                                              G_PARAM_READWRITE |
							      G_PARAM_CONSTRUCT_ONLY));
}


MAKE_GET_TYPE(galeon_recent_history_menu, "GaleonRecentHistoryMenu", GaleonRecentHistoryMenu,
	      galeon_recent_history_menu_class_init,
	      galeon_recent_history_menu_init, G_TYPE_OBJECT);


GaleonRecentHistoryMenu *
galeon_recent_history_menu_new (GaleonWindow *window, 
				GaleonWindowRecentHistory* recenthistory)
{
	GaleonRecentHistoryMenu *ret;

	ret = g_object_new 
		(GALEON_TYPE_RECENT_HISTORY_MENU,
		 "RecentHistory", recenthistory, 
		 "GaleonWindow", window, NULL);
	
	return ret;
}
