/*
 *  Copyright (C) 2002  Ricardo Fernández Pascual
 *
 *  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 "bookmarks-context-menu.h"
#include <glib/gi18n.h>
#include "galeon-marshal.h"
#include "gul-gobject-misc.h"
#include "gul-gui.h"
#include "bookmarks-single-editor.h"
#include "bookmarks-clipboard.h"
#include "pixbuf-cache.h"
#include <gtk/gtkclipboard.h>
#include <gtk/gtkstock.h>
#include <gtk/gtkmain.h>
#include <string.h>

/**
 * Private data
 */
struct _GbContextMenuPrivate 
{
	GbBookmark *bm;
	GtkWidget *menu;
	GbLocationSource *location_source;
};

/**
 * Private functions, only availble from this file
 */
static void		gb_context_menu_class_init		(GbContextMenuClass *klass);
static void		gb_context_menu_init			(GbContextMenu *cm);
static void		gb_context_menu_build_menu		(GbContextMenu *cm);
static void		gb_context_menu_finalize_impl		(GObject *o);

static void		gb_context_menu_deactivate_cb		(GtkMenuShell *ms, GbContextMenu *cm);

static void		gb_context_menu_bookmark_activated_cb	(GbContextMenu *gm, 
								 GbBookmarkEventActivated *ev,
								 GObject *o);

static void		gb_context_menu_edit_cb			(GtkWidget *menu_item, GbContextMenu *cm);
static void		gb_context_menu_remove_cb		(GtkWidget *menu_item, GbContextMenu *cm);
static void		gb_context_menu_cut_cb			(GtkWidget *menu_item, GbContextMenu *cm);
static void		gb_context_menu_copy_cb			(GtkWidget *menu_item, GbContextMenu *cm);
static void		gb_context_menu_paste_cb		(GtkWidget *menu_item, GbContextMenu *cm);
static void		gb_context_menu_new_bookmark_cb		(GtkWidget *menu_item, GbContextMenu *cm);
static void		gb_context_menu_add_bookmark_here_cb	(GtkWidget *menu_item, GbContextMenu *cm);
static void		gb_context_menu_add_folder_here_cb	(GtkWidget *menu_item, GbContextMenu *cm);
static void		gb_context_menu_open_new_window_cb	(GtkWidget *menu_item, GbContextMenu *cm);
static void		gb_context_menu_open_new_tab_cb		(GtkWidget *menu_item, GbContextMenu *cm);
static void		gb_context_menu_copy_location_cb	(GtkWidget *menu_item, GbContextMenu *cm);
static void		gb_context_menu_open_folder_tabs_cb	(GtkWidget *menu_item, GbContextMenu *cm);
static void		gb_context_menu_open_folder_windows_cb	(GtkWidget *menu_item, GbContextMenu *cm);
static void		gb_context_menu_show_as_toolbar_cb	(GtkWidget *menu_item, GbContextMenu *cm);
static void		gb_context_menu_set_as_default_folder_cb (GtkWidget *menu_item, GbContextMenu *cm);

static gpointer g_object_class;

enum GbContextMenuSignalsEnum {
	GB_CONTEXT_MENU_BOOKMARK_ACTIVATED,
	GB_CONTEXT_MENU_DEACTIVATED,
	GB_CONTEXT_MENU_LAST_SIGNAL
};
static gint GbContextMenuSignals[GB_CONTEXT_MENU_LAST_SIGNAL];

/**
 * ContextMenu object
 */

MAKE_GET_TYPE (gb_context_menu, "GbContextMenu", GbContextMenu, gb_context_menu_class_init, 
	       gb_context_menu_init, G_TYPE_OBJECT);

static void
gb_context_menu_class_init (GbContextMenuClass *klass)
{
	G_OBJECT_CLASS (klass)->finalize = gb_context_menu_finalize_impl;
	g_object_class = g_type_class_peek_parent (klass);

	GbContextMenuSignals[GB_CONTEXT_MENU_BOOKMARK_ACTIVATED] = g_signal_new (
		"bookmark-activated", G_OBJECT_CLASS_TYPE (klass),  
		G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP,
                G_STRUCT_OFFSET (GbContextMenuClass, gb_context_menu_bookmark_activated), 
		NULL, NULL, 
		g_cclosure_marshal_VOID__POINTER,
		G_TYPE_NONE, 1, G_TYPE_POINTER);
	GbContextMenuSignals[GB_CONTEXT_MENU_DEACTIVATED] = g_signal_new (
		"deactivated", G_OBJECT_CLASS_TYPE (klass),  
		G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP,
                G_STRUCT_OFFSET (GbContextMenuClass, gb_context_menu_deactivated), 
		NULL, NULL, 
		galeon_marshal_VOID__VOID,
		G_TYPE_NONE, 0);
}

static void 
gb_context_menu_init (GbContextMenu *cm)
{
	GbContextMenuPrivate *p = g_new0 (GbContextMenuPrivate, 1);
	cm->priv = p;
}

static void
gb_context_menu_finalize_impl (GObject *o)
{
	GbContextMenu *cm = GB_CONTEXT_MENU (o);
	GbContextMenuPrivate *p = cm->priv;

	gb_context_menu_set_location_source (cm, NULL);

	if (p->bm)
	{
		g_object_unref (p->bm);
	}

	if (p->menu)
	{
		g_signal_handlers_disconnect_matched (p->menu, G_SIGNAL_MATCH_DATA, 0, 0, 
						      NULL, NULL, cm);
		g_object_unref (p->menu);
	}
	
	g_free (p);
	
	G_OBJECT_CLASS (g_object_class)->finalize (o);

}

GbContextMenu *
gb_context_menu_new (void)
{
	GbContextMenu *ret = g_object_new (GB_TYPE_CONTEXT_MENU, NULL);
	return ret;
}

static void
gb_context_menu_deactivate_cb (GtkMenuShell *ms, GbContextMenu *cm)
{
	g_signal_emit (cm, GbContextMenuSignals[GB_CONTEXT_MENU_DEACTIVATED], 0);

}

void
gb_context_menu_popup (GbContextMenu *cm, GdkEventButton *event)
{
	GbContextMenuPrivate *p = cm->priv;
	g_return_if_fail (GB_IS_BOOKMARK (p->bm));

	gb_context_menu_build_menu (cm);
	g_object_ref (cm);

	g_signal_connect (p->menu, "deactivate", G_CALLBACK (gb_context_menu_deactivate_cb), cm);

	gtk_menu_popup (GTK_MENU (p->menu), NULL, NULL, NULL, cm, 
			event ? event->button : 0, 
			event ? event->time : gtk_get_current_event_time ());
}

void
gb_context_menu_set_bookmark (GbContextMenu *cm, GbBookmark *b)
{
	GbContextMenuPrivate *p = cm->priv;

	if (p->bm)
	{
		g_object_unref (p->bm);
	}

	p->bm = b;

	if (b)
	{
		g_object_ref (b);
	}

}

#if 0 
/* this is for debugging gb_bookmark_alias_make_real */
static void
gb_context_menu_gb_bookmark_alias_make_real_cb (GtkWidget *menu_item, GbContextMenu *cm)
{
	GbContextMenuPrivate *p = cm->priv;
	GbBookmark *bm = p->bm;

	gb_bookmark_alias_make_real (bm);

	g_object_unref (cm);
}
#endif 

static void
gb_context_menu_build_menu (GbContextMenu *cm)
{
	GbContextMenuPrivate *p = cm->priv;
	GtkWidget *item;

	g_return_if_fail (GB_IS_BOOKMARK (p->bm));
	
	if (p->menu)
	{
		g_signal_handlers_disconnect_matched (p->menu, G_SIGNAL_MATCH_DATA, 0, 0, 
						      NULL, NULL, cm);
		g_object_unref (p->menu);
	}

	p->menu = gtk_menu_new ();
	g_object_ref (p->menu);
	gtk_object_sink (GTK_OBJECT (p->menu));

	if (GB_IS_SITE (p->bm))
	{
		gul_gui_append_new_menuitem_stock_icon 
			(p->menu, GTK_STOCK_OPEN, _("Open in New _Window"),
			 G_CALLBACK (gb_context_menu_open_new_window_cb), cm);
		gul_gui_append_new_menuitem
			(p->menu,  _("Open in New _Tab"),
			 G_CALLBACK (gb_context_menu_open_new_tab_cb), cm);
		gul_gui_append_new_menuitem_stock_icon 
			(p->menu, GTK_STOCK_COPY, _("Copy _Link Location"),
			 G_CALLBACK (gb_context_menu_copy_location_cb), cm);
	}

	if (GB_IS_FOLDER (p->bm))
	{
		if (p->location_source)
		{
			gul_gui_append_new_menuitem_stock_icon 
				(p->menu, STOCK_ADD_BOOKMARK, _("Add _Bookmark Here"),
				 G_CALLBACK (gb_context_menu_add_bookmark_here_cb), cm);
		}
		else
		{
			gul_gui_append_new_menuitem_stock_icon
				(p->menu, GTK_STOCK_NEW, _("New _Bookmark"),
				 G_CALLBACK (gb_context_menu_new_bookmark_cb), cm);
		}

		gul_gui_append_new_menuitem
			(p->menu, _("New _Folder"),
			 G_CALLBACK (gb_context_menu_add_folder_here_cb), cm);

		gul_gui_append_separator (p->menu);

		gul_gui_append_new_menuitem_stock_icon 
			(p->menu, GTK_STOCK_OPEN, _("Open Folder in _Windows"),
			 G_CALLBACK (gb_context_menu_open_folder_windows_cb), cm);
		gul_gui_append_new_menuitem
			(p->menu, _("Open Folder in _Tabs"),
			 G_CALLBACK (gb_context_menu_open_folder_tabs_cb), cm);
/*
		gul_gui_append_new_menuitem_stock_icon 
			(p->menu, GTK_STOCK_OPEN, _("Open folder in _My Portal"),
			 G_CALLBACK (gb_context_menu_open_folder_myportal_cb), cm);
*/
		gul_gui_append_separator (p->menu);

		gul_gui_append_new_check_menuitem
			(p->menu, _("Show as _Toolbar"), 
			 GB_FOLDER (p->bm)->create_toolbar,
			 G_CALLBACK (gb_context_menu_show_as_toolbar_cb), cm);
		
		item = gul_gui_append_new_menuitem
			(p->menu, _("_Set as Default Folder"), 
			 G_CALLBACK (gb_context_menu_set_as_default_folder_cb), cm);
               if (gb_folder_is_default_folder (GB_FOLDER (p->bm)))
	       {
                       gtk_widget_set_sensitive (item, FALSE);
               }

	}

	gul_gui_append_separator (p->menu);

	gul_gui_append_new_menuitem_stock
		(p->menu, GTK_STOCK_CUT,
		 G_CALLBACK (gb_context_menu_cut_cb), cm);

	gul_gui_append_new_menuitem_stock
		(p->menu, GTK_STOCK_COPY,
		 G_CALLBACK (gb_context_menu_copy_cb), cm);

	gul_gui_append_new_menuitem_stock
		(p->menu, GTK_STOCK_PASTE,
		 G_CALLBACK (gb_context_menu_paste_cb), cm);
	
	gul_gui_append_separator (p->menu);

	gul_gui_append_new_menuitem_stock
			(p->menu, GTK_STOCK_DELETE, 
			 G_CALLBACK (gb_context_menu_remove_cb), cm);
			
	gul_gui_append_separator (p->menu);

	gul_gui_append_new_menuitem_stock 
		(p->menu, GTK_STOCK_PROPERTIES,
		 G_CALLBACK (gb_context_menu_edit_cb), cm);

#if 0 
	/* this is for debugging gb_bookmark_alias_make_real */
	gul_gui_append_new_menuitem
		(p->menu, "gb_bookmark_alias_make_real",
		 G_CALLBACK (gb_context_menu_gb_bookmark_alias_make_real_cb), cm);
#endif
}

/**
 * Creates and pops up a context menu.
 *
 * bm: 			The bookmark
 * event:		Optional button event
 * location_source:	Optional location source (for adding bookmarks)
 * creator:		The object that requests the context menu. It must have a 
 *			bookmark-activated signal, wich will be emitted if neccesary
 */
void
gb_context_menu_quick (GbBookmark *bm, GdkEventButton *event, GbLocationSource *location_source,
		       GObject *creator)
{
	GbContextMenu *cm = gb_context_menu_new_quick (bm, location_source, creator);
	gb_context_menu_popup (cm, event);
	g_object_unref (cm);
}

/**
 * Creates a context menu that will forward activation signals.
 *
 * bm: 			The bookmark
 * location_source:	Optional location source (for adding bookmarks)
 * creator:		The object that requests the context menu. It must have a 
 *			bookmark-activated signal, wich will be emitted if neccesary
 */
GbContextMenu *
gb_context_menu_new_quick  (GbBookmark *bm, GbLocationSource *location_source,
			    GObject *creator)
{
	GbContextMenu *cm = gb_context_menu_new ();
	gb_context_menu_set_bookmark (cm, bm);
	gb_context_menu_set_location_source (cm, location_source);
	if (creator)
	{
		g_signal_connect (cm, "bookmark-activated", 
				  G_CALLBACK (gb_context_menu_bookmark_activated_cb), 
				  creator);
	}
	return cm;
}

static void
gb_context_menu_bookmark_activated_cb (GbContextMenu *gm, 
				       GbBookmarkEventActivated *ev,
				       GObject *o)
{
	g_signal_emit_by_name (o, "bookmark-activated", ev);
}

static void
gb_context_menu_edit_cb (GtkWidget *menu_item, GbContextMenu *cm)
{
	GbSingleEditor *e = gb_single_editor_new ();
	gb_single_editor_set_bookmark (e, cm->priv->bm);
	gb_single_editor_show (e);

	g_object_unref (cm);
}

static void
gb_context_menu_remove_cb (GtkWidget *menu_item, GbContextMenu *cm)
{
	GbContextMenuPrivate *p = cm->priv;
	GbBookmark *bm = p->bm;

	gb_bookmark_unparent_safe (bm);

	g_object_unref (cm);
}

static void
gb_context_menu_cut_cb (GtkWidget *menu_item, GbContextMenu *cm)
{
	GbContextMenuPrivate *p = cm->priv;
	GbBookmark *bm = p->bm;
	GbClipboard *c = gb_clipboard_get_shared ();

	gb_clipboard_clear (c);
	gb_clipboard_add (c, bm);

	gb_bookmark_unparent_safe (bm);

	g_object_unref (cm);
}

static void
gb_context_menu_copy_cb (GtkWidget *menu_item, GbContextMenu *cm)
{
	GbContextMenuPrivate *p = cm->priv;
	GbBookmark *bm = p->bm;
	GbClipboard *c = gb_clipboard_get_shared ();

	gb_clipboard_clear (c);
	gb_clipboard_add (c, bm);

	g_object_unref (c);
	g_object_unref (cm);
}

static void
gb_context_menu_paste_cb (GtkWidget *menu_item, GbContextMenu *cm)
{
	GbContextMenuPrivate *p = cm->priv;
	GbBookmark *bm = p->bm;
	GbClipboard *c = gb_clipboard_get_shared ();
	GbBookmarkSet *s = NULL;
	GbFolder *f = GB_IS_FOLDER (bm) ? GB_FOLDER (bm) : bm->parent;
	gint idx;

	g_return_if_fail (GB_IS_FOLDER (f));

	idx = GB_IS_FOLDER (bm) ? 0 : gb_folder_get_child_index (bm->parent, bm);

	if (gb_clipboard_can_paste (c))
	{
		s = gb_clipboard_paste (c);
		if (s) 
		{
			GSList *l;
			GSList *li;
			g_return_if_fail (GB_IS_BOOKMARK_SET (s) && GB_IS_FOLDER (s->root));
			
			l = gb_folder_list_children (s->root);
			for (li = l; li; li = li->next)
			{
				gb_folder_add_child (f, li->data, idx++);
			}
			if (l && l->data)
			{
				gb_activated_emit (cm, GbContextMenuSignals[GB_CONTEXT_MENU_BOOKMARK_ACTIVATED],
						   GB_BOOKMARK (l->data), NULL, GB_BAF_EDITOR);
			}
			g_object_unref (s);
			g_slist_free (l);
		}
	}
	g_object_unref (cm);
}

static void
gb_context_menu_open_new_window_cb (GtkWidget *menu_item, GbContextMenu *cm)
{
	GbContextMenuPrivate *p = cm->priv;
	GbBookmark *bm = p->bm;
	
	g_return_if_fail (GB_IS_SITE (bm));
	
	gb_activated_emit (cm, GbContextMenuSignals[GB_CONTEXT_MENU_BOOKMARK_ACTIVATED],
		           bm, GB_SITE (bm)->url, GB_BAF_NEW_WINDOW);
	g_object_unref (cm);
}

static void
gb_context_menu_open_new_tab_cb (GtkWidget *menu_item, GbContextMenu *cm)
{
	GbContextMenuPrivate *p = cm->priv;
	GbBookmark *bm = p->bm;
	
	g_return_if_fail (GB_IS_SITE (bm));
	
	gb_activated_emit (cm, GbContextMenuSignals[GB_CONTEXT_MENU_BOOKMARK_ACTIVATED],
		           bm, GB_SITE (bm)->url, GB_BAF_NEW_TAB);
	g_object_unref (cm);
}

static void
gb_context_menu_copy_location_cb (GtkWidget *menu_item, GbContextMenu *cm)
{
	GbContextMenuPrivate *p = cm->priv;
	GbBookmark *bm = p->bm;
	
	g_return_if_fail (GB_IS_SITE (bm));

	gtk_clipboard_set_text (gtk_clipboard_get (GDK_NONE),
				GB_SITE (bm)->url, strlen (GB_SITE (bm)->url));
	gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
				GB_SITE (bm)->url, strlen (GB_SITE (bm)->url));

	g_object_unref (cm);
}

static void
gb_context_menu_open_folder_tabs_cb (GtkWidget *menu_item, GbContextMenu *cm)
{
	GbContextMenuPrivate *p = cm->priv;
	GbBookmark *bm = p->bm;
	
	g_return_if_fail (GB_IS_FOLDER (bm));
	
	gb_activated_emit (cm, GbContextMenuSignals[GB_CONTEXT_MENU_BOOKMARK_ACTIVATED],
		           bm, NULL, GB_BAF_NEW_TAB);
	g_object_unref (cm);
}

static void
gb_context_menu_open_folder_windows_cb (GtkWidget *menu_item, GbContextMenu *cm)
{
	GbContextMenuPrivate *p = cm->priv;
	GbBookmark *bm = p->bm;
	
	g_return_if_fail (GB_IS_FOLDER (bm));
	
	gb_activated_emit (cm, GbContextMenuSignals[GB_CONTEXT_MENU_BOOKMARK_ACTIVATED],
		           bm, NULL, GB_BAF_NEW_WINDOW);
	g_object_unref (cm);
}

static void
gb_context_menu_show_as_toolbar_cb (GtkWidget *menu_item, GbContextMenu *cm)
{
	GbContextMenuPrivate *p = cm->priv;
	GbBookmark *bm = p->bm;
	
	g_return_if_fail (GB_IS_FOLDER (bm));
	
	gb_folder_set_create_toolbar (GB_FOLDER (bm), !GB_FOLDER (bm)->create_toolbar);
	
	g_object_unref (cm);
}

static void
gb_context_menu_set_as_default_folder_cb (GtkWidget *menu_item, GbContextMenu *cm)
{
	GbContextMenuPrivate *p = cm->priv;
	GbBookmark *bm = p->bm;
	
	g_return_if_fail (GB_IS_FOLDER (bm));
	
	if (bm->set)
	{
		gb_bookmark_set_set_default_folder (bm->set, GB_FOLDER (bm));
	}
	
	g_object_unref (cm);
}

void
gb_context_menu_set_location_source (GbContextMenu *cm, GbLocationSource *src)
{
	GbContextMenuPrivate *p = cm->priv;

	if (p->location_source)
	{
		g_object_remove_weak_pointer (G_OBJECT (p->location_source),
					      (gpointer *) &p->location_source);
	}

	p->location_source = src;

	if (p->location_source)
	{
		g_object_add_weak_pointer (G_OBJECT (p->location_source), 
					   (gpointer *) &p->location_source);
	}
}
static void
gb_context_menu_new_bookmark_cb (GtkWidget *menu_item, GbContextMenu *cm)
{
	GbContextMenuPrivate *p = cm->priv;
	GbBookmark *bm = p->bm;
	GbSite *niu;

	g_return_if_fail (GB_IS_FOLDER (bm));
	
	/* see also bookmarks-editor.c */
	niu = gb_site_new (bm->set, _("New Site"), "http://");

	gb_folder_add_child (GB_FOLDER (bm), GB_BOOKMARK (niu), 0);
	gb_bookmark_set_time_added_now (GB_BOOKMARK (niu));

	gb_activated_emit (cm, GbContextMenuSignals[GB_CONTEXT_MENU_BOOKMARK_ACTIVATED],
		           GB_BOOKMARK (niu), niu->url, GB_BAF_EDITOR);

	g_object_unref (niu);

	g_object_unref (cm);
}

static void
gb_context_menu_add_bookmark_here_cb (GtkWidget *menu_item, GbContextMenu *cm)
{
	GbContextMenuPrivate *p = cm->priv;
	GbBookmark *bm = p->bm;
	GbLocationSource *src = p->location_source;
	GbSite *niu;
	gchar *title;
	gchar *location;

	g_return_if_fail (GB_IS_FOLDER (bm));
	g_return_if_fail (GB_IS_LOCATION_SOURCE (src));
	
	title = gb_location_source_get_title (src);
	location = gb_location_source_get_location (src);

	niu = gb_site_new (bm->set, title, location);

	g_free (title);
	g_free (location);

	gb_folder_add_child (GB_FOLDER (bm), GB_BOOKMARK (niu), -1);
	gb_activated_emit (cm, GbContextMenuSignals[GB_CONTEXT_MENU_BOOKMARK_ACTIVATED],
		           GB_BOOKMARK (niu), niu->url, GB_BAF_EDITOR);
	gb_bookmark_set_time_added_now (GB_BOOKMARK (niu));
	gb_site_set_time_visited_now (niu);

	g_object_unref (niu);

	g_object_unref (cm);
}

static void		
gb_context_menu_add_folder_here_cb (GtkWidget *menu_item, GbContextMenu *cm)
{
	GbContextMenuPrivate *p = cm->priv;
	GbBookmark *bm = p->bm;
	GbFolder *niu;
	
	g_return_if_fail (GB_IS_FOLDER (bm));

	niu = gb_folder_new (bm->set, _("New folder"));
	gb_folder_add_child (GB_FOLDER (bm), GB_BOOKMARK (niu), -1);
	gb_bookmark_set_time_added_now (GB_BOOKMARK (niu));
	gb_activated_emit (cm, GbContextMenuSignals[GB_CONTEXT_MENU_BOOKMARK_ACTIVATED],
		           GB_BOOKMARK (niu), NULL, GB_BAF_EDITOR);
	g_object_unref (niu);

	g_object_unref (cm);
}

