/*
 *  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/gtkaction.h>

#include "session.h"
#include "galeon-window.h"
#include "galeon-shell.h"
#include "galeon-window-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 _GaleonWindowMenuPrivate
{
	GaleonWindow *window;
	GtkUIManager *merge;

	GtkActionGroup *item_action_group;
	GtkActionGroup *menu_action_group;
	guint merge_id;
};

enum
{
	PROP_0,
	PROP_WINDOW
};

static gpointer g_object_class;

#define WINDOW_MENU_PLACEHOLDER_PATH    "/menubar/Tabs/WindowMenuPlaceholder"
#define TABS_MENU_PATH			"/menubar/Tabs"
#define WINDOW_KEY                      "galeon-window"
#define MENU_ITEM_MAX_LENGTH 40

static void
activate_window_cb (GtkAction *action, GaleonWindowMenu *menu)
{
	GaleonWindow *window = g_object_get_data (G_OBJECT (action), WINDOW_KEY);

	galeon_window_reparent_tab (window, menu->priv->window,
		 galeon_window_get_active_tab (menu->priv->window));	
	
}

static GtkAction *
create_window_action (GaleonWindowMenu *menu, GaleonWindow *window)
{
	GtkAction  *action;
	char *name;
	gchar *title_s, *title_enc, *tooltip, *label;
	const char *title;
	GaleonTab *tab = galeon_window_get_active_tab (window);
	GulNotebook *notebook;
	int num;

	title = galeon_tab_get_title(tab);
	title_s   = gul_string_shorten(title,  MENU_ITEM_MAX_LENGTH);
	title_enc = gul_string_double_underscores (title_s);
	
	notebook = galeon_window_get_notebook (window);
	num = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook));

	label = g_strdup_printf (ngettext ("%s (%d tab)",
					   "%s (%d tabs)", num),
				 title_enc, num);

	tooltip = g_strdup_printf( _("Move tab to window \"%s\""), title);

	name = g_strdup_printf ("GaleonWindow%pAction", window);
	action = g_object_new (GTK_TYPE_ACTION,
			       "name", name,
			       "label", label,
			       "tooltip", tooltip,
			       "sensitive", (window != menu->priv->window),
			       NULL);

	g_object_set_data (G_OBJECT(action), WINDOW_KEY, window);

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

	gtk_action_group_add_action (menu->priv->item_action_group, action);
	g_object_unref (action);

	g_free (name);
	g_free (title_s);
	g_free (title_enc);
	g_free (label);
	g_free (tooltip);
	return action;
}

static void
galeon_window_menu_rebuild (GaleonWindowMenu *menu)
{
	GaleonWindowMenuPrivate *p = menu->priv;
	GList *windows, *l;
	Session *session;
	int count = 0;
	GtkAction *action;
	
	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->item_action_group)
	{
		gtk_ui_manager_remove_action_group (p->merge, p->item_action_group);
		g_object_unref (p->item_action_group);
		p->item_action_group = 0;
	}


	session = galeon_shell_get_session (galeon_shell);
	g_return_if_fail (session != NULL);
	
	windows = session_get_windows (session);

	LOG ("Rebuilding window menu");

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

	p->merge_id = gtk_ui_manager_new_merge_id (p->merge);

	gtk_ui_manager_add_ui (p->merge, p->merge_id,
			       WINDOW_MENU_PLACEHOLDER_PATH,
			       "TabsMoveMenu",
			       "TabsMoveMenuAction",
			       GTK_UI_MANAGER_MENU, FALSE);

	for (l = windows; l ; l = l->next)
	{
		gchar name[128];
		GaleonWindow *window = GALEON_WINDOW (l->data);
		action = create_window_action (menu, window);

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

		gtk_ui_manager_add_ui (p->merge, p->merge_id,
				       WINDOW_MENU_PLACEHOLDER_PATH "/TabsMoveMenu",
				       name, gtk_action_get_name (action),
				       GTK_UI_MANAGER_MENUITEM, FALSE);
		count++;
	}

	action = gtk_action_group_get_action (p->menu_action_group, "TabsMoveMenuAction");
	g_object_set(G_OBJECT(action), "sensitive", count == 1 ? FALSE : TRUE, NULL);

	gtk_ui_manager_ensure_update (p->merge);
}


static GtkActionEntry entries[] = {
	{ "TabsMoveMenuAction", NULL, N_("_Move Tab to Another Window"),
	  NULL, N_("Move the current tab to a different window"), NULL },
};
static guint n_entries = G_N_ELEMENTS(entries);

static void
galeon_window_menu_set_window (GaleonWindowMenu *menu, GaleonWindow *window)
{
	GaleonWindowMenuPrivate *p = menu->priv;
	GtkAction *action;

	p->window = window;
	
	/* Create the Action Group */
	p->merge = g_object_ref (GTK_UI_MANAGER (window->merge));
	menu->priv->menu_action_group = gtk_action_group_new ("WindowMenuActions");
	gtk_action_group_set_translation_domain (menu->priv->menu_action_group, NULL);
	gtk_ui_manager_insert_action_group(p->merge, p->menu_action_group, 0);
	gtk_action_group_add_actions(p->menu_action_group, entries,
				     n_entries, window);
	
	action = gtk_action_group_get_action (menu->priv->menu_action_group, "TabsMoveMenuAction");
	g_object_set (action, "hide_if_empty", FALSE, NULL);

	action = gtk_ui_manager_get_action (p->merge, TABS_MENU_PATH);
	g_return_if_fail (GTK_IS_ACTION (action));

	g_signal_connect_object (action, "activate",
				 G_CALLBACK (galeon_window_menu_rebuild),
				 menu, G_CONNECT_SWAPPED);

	galeon_window_menu_rebuild (menu);
}


static void
galeon_window_menu_set_property (GObject *object,
			      guint prop_id,
			      const GValue *value,
			      GParamSpec *pspec)
{
	GaleonWindowMenu *m = GALEON_WINDOW_MENU (object);

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

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


static void
galeon_window_menu_finalize_impl(GObject *o)
{
	GaleonWindowMenu *gm = GALEON_WINDOW_MENU(o);
	GaleonWindowMenuPrivate *p = gm->priv;

	LOG ("galeon_window_menu_finalize_impl");

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

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

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

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

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

static void 
galeon_window_menu_init(GaleonWindowMenu *m)
{
	GaleonWindowMenuPrivate *p = g_new0 (GaleonWindowMenuPrivate, 1);
	m->priv = p;
}

static void
galeon_window_menu_class_init(GaleonWindowMenuClass *klass)
{
	GObjectClass *object_class = G_OBJECT_CLASS (klass);
	g_object_class = g_type_class_peek_parent(klass);

	object_class->set_property = galeon_window_menu_set_property;
	object_class->get_property = galeon_window_menu_get_property;
	object_class->finalize = galeon_window_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_window_menu, "GaleonWindowMenu", GaleonWindowMenu,
	      galeon_window_menu_class_init,
	      galeon_window_menu_init, G_TYPE_OBJECT);


GaleonWindowMenu *
galeon_window_menu_new (GaleonWindow *window)
{
	GaleonWindowMenu *ret = g_object_new (GALEON_TYPE_WINDOW_MENU, 
					      "GaleonWindow", window, NULL);
	return ret;
}
