/*
 *  Copyright (C) 2003  Ricardo Fernández Pascual
 *  Copyright (C) 2003  Philip Langdale
 *  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 <gtk/gtkuimanager.h>
#include <gtk/gtkactiongroup.h>
#include <gtk/gtkradioaction.h>
#include <gtk/gtkaccelmap.h>

#include "galeon-window.h"
#include "galeon-tab-menu.h"
#include "gul-gobject-misc.h"
#include "galeon-marshal.h"
#include "galeon-debug.h"
#include "gul-string.h"
#include "gul-gui.h"


/**
 * Private data
 */
struct _GaleonTabMenuPrivate
{
	GtkUIManager *merge;
	GaleonWindow *window;
	GtkActionGroup *action_group;
	guint merge_id;

	gboolean block_signal;
};

enum
{
	PROP_0,
	PROP_WINDOW
};

static gpointer g_object_class;

#define TAB_MENU_PLACEHOLDER_PATH "/menubar/Tabs/TabMenuPlaceholder"
#define MENU_ITEM_MAX_LENGTH 40

static void
update_title_cb (GaleonEmbed* embed, GtkAction *action)
{
	GaleonTab *tab = g_object_get_data (G_OBJECT (action), "GaleonTab");

	const char *title = galeon_tab_get_title(tab);
	gchar *title_s = gul_string_shorten(title,
					    MENU_ITEM_MAX_LENGTH);

	gchar *escape_title = gul_string_double_underscores (title_s);

	gchar *tooltip = g_strdup_printf( _("View tab titled \"%s\""), title);

	g_object_set (G_OBJECT (action),
		      "label", escape_title,
		      "tooltip", tooltip,
		      NULL);
	g_free (tooltip);
	g_free (title_s);
	g_free (escape_title);
}

static void
activate_tab_cb (GtkAction *action, GaleonTabMenu *menu)
{
	GaleonTab *tab = g_object_get_data (G_OBJECT (action), "GaleonTab");

	if (menu->priv->block_signal) return;

	galeon_window_jump_to_tab (menu->priv->window, tab);
}

static GtkAction *
get_tab_action (GaleonTabMenu *menu, int num, GaleonTab *tab)
{
	GtkAction  *action;
	GaleonEmbed *embed;
	char *name;
	char accel_buffer[7];
	char *accel = NULL;
	gint accel_number;

	name = g_strdup_printf ("GaleonTab%dAction", num);

	/* Create the action */
	embed = galeon_tab_get_embed (tab);

	action = g_object_new (GTK_TYPE_RADIO_ACTION,
			       "name", name,
			       NULL);
	g_object_set_data (G_OBJECT(action), "GaleonTab", tab);

	g_signal_connect_object (embed, "ge_title",
				 G_CALLBACK (update_title_cb),
				 action, 0);
	update_title_cb (embed, action);

	g_signal_connect_object (action, "activate",
				 G_CALLBACK (activate_tab_cb),
				 menu, 0);


	if (num < 10)
	{
		accel_number = (num + 1) % 10;

		g_snprintf (accel_buffer, 7, "<alt>%d", accel_number);
		accel = accel_buffer;
	}

	gtk_action_group_add_action_with_accel (menu->priv->action_group, action, accel);

	g_object_unref (action);

	g_free (name);
	return action;
}

static void
galeon_tabs_menu_rebuild (GaleonTabMenu *menu)
{
	GaleonTabMenuPrivate *p = menu->priv;
	GList *tabs, *l;
	GaleonTab *active;
	int i = 0;
	GSList *radio_group = NULL;

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

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

	/* Create the new action group */
	p->action_group = gtk_action_group_new ("TabMenuActions");
	gtk_action_group_set_translation_domain (p->action_group, NULL);
	gtk_ui_manager_insert_action_group (p->merge, p->action_group, 0);

	tabs = galeon_window_get_tabs (p->window);	
	active = galeon_window_get_active_tab (p->window);

	LOG ("Rebuilding tab menu");
	p->merge_id = gtk_ui_manager_new_merge_id (p->merge);

	p->block_signal = TRUE;

	for (l = tabs; l ; l = l->next)
	{
		gchar name[128];
		GaleonTab *tab = GALEON_TAB (l->data);
		GtkAction *action = get_tab_action (menu, i, tab);

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

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

		/* Make sure all widgets are in the same radio_gruop */
		gtk_radio_action_set_group (GTK_RADIO_ACTION (action), radio_group);
		radio_group = gtk_radio_action_get_group (GTK_RADIO_ACTION (action));

		gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), 
					      (tab == active));
		i++;
	}

	g_list_free (tabs);
	gtk_ui_manager_ensure_update (p->merge);

	p->block_signal = FALSE;
}

static void
galeon_tab_menu_set_window (GaleonTabMenu *menu, GaleonWindow *window)
{
	GulNotebook *notebook;
	GaleonTabMenuPrivate *p = menu->priv;
	
	p->window = window;

	p->merge = g_object_ref (GTK_UI_MANAGER (window->merge));

	/* Connect up the signals for the notebook */
	notebook = galeon_window_get_notebook (window);
	g_signal_connect_object (notebook, "tab_added",
			         G_CALLBACK (galeon_tabs_menu_rebuild),
				 menu, G_CONNECT_SWAPPED);
	g_signal_connect_object (notebook, "tab_removed",
			         G_CALLBACK (galeon_tabs_menu_rebuild),
				 menu, G_CONNECT_SWAPPED);
	g_signal_connect_object (notebook, "tabs_reordered",
			         G_CALLBACK (galeon_tabs_menu_rebuild),
				 menu, G_CONNECT_SWAPPED);
	g_signal_connect_object (notebook, "switch_page",
			         G_CALLBACK (galeon_tabs_menu_rebuild),
				 menu, G_CONNECT_SWAPPED|G_CONNECT_AFTER);
}



static void
galeon_tab_menu_set_property (GObject *object,
			      guint prop_id,
			      const GValue *value,
			      GParamSpec *pspec)
{
	GaleonTabMenu *m = GALEON_TAB_MENU (object);

	switch (prop_id)
	{
	case PROP_WINDOW:
		{
			galeon_tab_menu_set_window 
				(m, GALEON_WINDOW (g_value_get_object (value)));
		}
		break;
	default: 
		break;
	}
}

static void
galeon_tab_menu_get_property (GObject *object,
			      guint prop_id,
			      GValue *value,
			      GParamSpec *pspec)
{
	GaleonTabMenu *m = GALEON_TAB_MENU (object);
	
	switch (prop_id)
	{
	case PROP_WINDOW:
		g_value_set_object (value, m->priv->window);
		break;
	default: 
		break;
	}
}


static void
galeon_tab_menu_finalize_impl(GObject *o)
{
	GaleonTabMenu *gm = GALEON_TAB_MENU(o);
	GaleonTabMenuPrivate *p = gm->priv;

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

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

	g_object_unref (p->merge);
	g_free(p);

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

static void 
galeon_tab_menu_init(GaleonTabMenu *m)
{
	GaleonTabMenuPrivate *p = g_new0 (GaleonTabMenuPrivate, 1);
	m->priv = p;
}

static void
galeon_tab_menu_class_init(GaleonTabMenuClass *klass)
{
	GObjectClass *object_class = G_OBJECT_CLASS (klass);
	g_object_class = g_type_class_peek_parent(klass);

	object_class->set_property = galeon_tab_menu_set_property;
	object_class->get_property = galeon_tab_menu_get_property;
	object_class->finalize = galeon_tab_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));
}


MAKE_GET_TYPE(galeon_tab_menu, "GaleonTabMenu", GaleonTabMenu,
	      galeon_tab_menu_class_init,
	      galeon_tab_menu_init, G_TYPE_OBJECT);


GaleonTabMenu *
galeon_tab_menu_new (GaleonWindow *window)
{
	GaleonTabMenu *ret = g_object_new (GALEON_TYPE_TAB_MENU, 
					   "GaleonWindow", window, NULL);
	return ret;
}
