/*
 *  Copyright (C) 2001, 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.
 */


#include <config.h>
#include <libgnome/gnome-macros.h>
#include <bonobo/bonobo-zoomable.h>
#include <bonobo/bonobo-ui-util.h>
#include <string.h>

#include "ephy-embed-popup-control.h"
#include "ephy-nautilus-view.h"
#include "ephy-embed.h"
#include "ephy-embed-utils.h"
#include "find-dialog.h"
#include "print-dialog.h"
#include "ephy-zoom.h"
#include "ephy-debug.h"

static void		gnv_embed_location_cb 			(EphyEmbed *embed, 
								 EphyNautilusView *view);
static void		gnv_embed_title_cb 			(EphyEmbed *embed, 
								 EphyNautilusView *view);
static void		gnv_embed_new_window_cb			(EphyEmbed *embed, 
								 EphyEmbed **new_embed,
								 EmbedChromeMask chromemask,
								 EphyNautilusView *view);
static void		gnv_embed_link_message_cb 		(EphyEmbed *embed, 
								 const char *message,
								 EphyNautilusView *view);
static gint		gnv_embed_dom_mouse_click_cb		(EphyEmbed *embed,
								 EphyEmbedEvent *event,
								 EphyNautilusView *view);
static void		gnv_embed_context_menu_cb		(EphyEmbed *embed,
								 EphyEmbedEvent *event,
								 EphyNautilusView *view);
static void		gnv_embed_zoom_change_cb 		(EphyNautilusView *embed,
								 float new_zoom, 
								 EphyNautilusView *view);


static void 		gnv_load_location_cb 			(EphyNautilusView *view,
								 const char *location,
								 gpointer user_data);
static void		gnv_stop_loading_cb			(EphyNautilusView *view,
								 gpointer user_data);
static void		gnv_bonobo_control_activate_cb 		(BonoboControl *control,
								 gboolean state,
								 EphyNautilusView *view);

/* zoomable */
static void 		gnv_zoomable_set_zoom_level_cb		(BonoboZoomable *zoomable,
								 float level,
								 EphyNautilusView *view);
static void		gnv_zoomable_zoom_in_cb			(BonoboZoomable *zoomable,
								 EphyNautilusView *view);
static void 		gnv_zoomable_zoom_out_cb 		(BonoboZoomable *zoomable,
								 EphyNautilusView *view);
static void		gnv_zoomable_zoom_to_fit_cb		(BonoboZoomable *zoomable,
								 EphyNautilusView *view);
static void		gnv_zoomable_zoom_to_default_cb		(BonoboZoomable *zoomable,
								 EphyNautilusView *view);
/* commands */
static void		gnv_cmd_set_encoding			(BonoboUIComponent *uic, 
								 EphyNautilusView *view,
								 const char* verbname);
static void 		gnv_cmd_file_print			(BonoboUIComponent *uic, 
								 EphyNautilusView *view, 
								 const char* verbname);
static void 		gnv_cmd_edit_find			(BonoboUIComponent *uic, 
								 EphyNautilusView *view, 
								 const char* verbname);


/* popups */
static EphyNautilusView *gnv_view_from_popup			(EphyEmbedPopupControl*popup);

static void 		gnv_popup_cmd_new_window		(BonoboUIComponent *uic, 
								 EphyEmbedPopupControl*popup, 
								 const char* verbname);
static void 		gnv_popup_cmd_image_in_new_window	(BonoboUIComponent *uic, 
								 EphyEmbedPopupControl*popup, 
								 const char* verbname);
static void 		gnv_popup_cmd_frame_in_new_window	(BonoboUIComponent *uic, 
								 EphyEmbedPopupControl*popup, 
								 const char* verbname);

struct EphyNautilusViewPrivate {
	EphyEmbed *embed;
	char *title;
	char *location;
	int load_percent;

	EphyEmbedPopupControl *popup;
	BonoboUIComponent *popup_ui;
	BonoboControl *control;
	BonoboUIComponent *ui;
	BonoboZoomable *zoomable;

	EphyDialog *find_dialog;
};

static BonoboUIVerb ephy_popup_verbs [] = {
        BONOBO_UI_VERB ("EPOpenInNewWindow", (BonoboUIVerbFn) gnv_popup_cmd_new_window),
	BONOBO_UI_VERB ("EPOpenImageInNewWindow", (BonoboUIVerbFn) gnv_popup_cmd_image_in_new_window),
	BONOBO_UI_VERB ("DPOpenFrameInNewWindow", (BonoboUIVerbFn) gnv_popup_cmd_frame_in_new_window),

        BONOBO_UI_VERB_END
};

BonoboUIVerb ephy_verbs [] = {
        BONOBO_UI_VERB ("FilePrint", (BonoboUIVerbFn) gnv_cmd_file_print),
        BONOBO_UI_VERB ("EditFind", (BonoboUIVerbFn) gnv_cmd_edit_find),
        BONOBO_UI_VERB_END
};

#define ENCODING_MENU_PATH "/menu/View/Encoding"


BONOBO_CLASS_BOILERPLATE (EphyNautilusView, ephy_nautilus_view,
			  NautilusView, NAUTILUS_TYPE_VIEW)

static void
ephy_nautilus_view_instance_init (EphyNautilusView *view)
{
	GtkWidget *w;
	EphyNautilusViewPrivate *p = g_new0 (EphyNautilusViewPrivate, 1);
	EphyEmbedSingle *single;
	float *levels;
	gchar **names;
	guint i;

	single = ephy_embed_shell_get_embed_single
		(EPHY_EMBED_SHELL (ephy_shell));

	view->priv = p;
	view->priv->embed = ephy_embed_new (G_OBJECT (single));

	g_object_ref (G_OBJECT (ephy_shell));

	g_signal_connect (view->priv->embed, "ge_link_message",
			  G_CALLBACK (gnv_embed_link_message_cb), 
			  view);
	g_signal_connect (view->priv->embed, "ge_location",
			  G_CALLBACK (gnv_embed_location_cb), 
			  view);
	g_signal_connect (view->priv->embed, "ge_title",
			  G_CALLBACK (gnv_embed_title_cb), 
			  view);
	g_signal_connect (view->priv->embed, "ge_new_window",
			  G_CALLBACK (gnv_embed_new_window_cb), 
			  view);
	g_signal_connect (view->priv->embed, "ge_dom_mouse_click", 
			  G_CALLBACK (gnv_embed_dom_mouse_click_cb), 
			  view);
	g_signal_connect (view->priv->embed, "ge_context_menu", 
			  G_CALLBACK (gnv_embed_context_menu_cb), 
			  view);
	g_signal_connect (view->priv->embed, "ge_zoom_change",
			  G_CALLBACK (gnv_embed_zoom_change_cb), 
			  view);

	w = GTK_WIDGET (view->priv->embed);
	gtk_widget_show (w);

	nautilus_view_construct (NAUTILUS_VIEW (view), w);

	g_signal_connect (G_OBJECT (view), "load_location",
			  G_CALLBACK (gnv_load_location_cb), NULL);

	g_signal_connect (G_OBJECT (view), "stop_loading",
			  G_CALLBACK (gnv_stop_loading_cb), NULL);

        g_signal_connect (G_OBJECT (nautilus_view_get_bonobo_control (NAUTILUS_VIEW (view))),
                          "activate",
                          G_CALLBACK (gnv_bonobo_control_activate_cb), view);

	view->priv->zoomable = bonobo_zoomable_new ();
	bonobo_object_add_interface (BONOBO_OBJECT (view),
				     BONOBO_OBJECT (view->priv->zoomable));

	/* get zoom levels */
	levels = g_new0 (float, n_zoom_levels);
	names = g_new0 (gchar *, n_zoom_levels);
	for (i = 0; i < n_zoom_levels; i++)
	{
		levels[i] = zoom_levels[i].level;
		names[i] = zoom_levels[i].name;
	}

	bonobo_zoomable_set_parameters_full (view->priv->zoomable,
					     1.0,
					     levels [0],
					     levels [n_zoom_levels-1],
					     FALSE, FALSE, TRUE,
					     levels,
					     (const gchar **) names,
					     n_zoom_levels);

	g_free (levels);
	g_free (names);

	bonobo_object_add_interface (BONOBO_OBJECT (view),
				     BONOBO_OBJECT (view->priv->zoomable));

	g_signal_connect (view->priv->zoomable, "set_zoom_level",
			    G_CALLBACK (gnv_zoomable_set_zoom_level_cb), view);
	g_signal_connect (view->priv->zoomable, "zoom_in",
			    G_CALLBACK (gnv_zoomable_zoom_in_cb), view);
	g_signal_connect (view->priv->zoomable, "zoom_out",
			    G_CALLBACK (gnv_zoomable_zoom_out_cb), view);
	g_signal_connect (view->priv->zoomable, "zoom_to_fit",
			    G_CALLBACK (gnv_zoomable_zoom_to_fit_cb), view);
	g_signal_connect (view->priv->zoomable, "zoom_to_default",
			    G_CALLBACK (gnv_zoomable_zoom_to_default_cb), view);

	p->control = nautilus_view_get_bonobo_control (NAUTILUS_VIEW (view));
	
	p->popup_ui = bonobo_control_get_popup_ui_component (p->control);
	g_assert (BONOBO_IS_UI_COMPONENT (p->popup_ui));
	bonobo_ui_util_set_ui (p->popup_ui, SHARE_DIR,
			       "nautilus-epiphany-view.xml",
			       "EphyNautilusView", NULL);
	p->popup = ephy_embed_popup_control_new (p->control);
	ephy_embed_popup_control_connect_verbs
		(EPHY_EMBED_POPUP_CONTROL (p->popup), p->popup_ui);
	g_object_set_data (G_OBJECT (p->popup), "NautilisView", view);

	bonobo_ui_component_add_verb_list_with_data (p->popup_ui, ephy_popup_verbs, p->popup);
}

/**
 * Returns a new EphyNautilusView as a BonoboObject 
 **/
BonoboObject *
ephy_nautilus_view_new_component (EphyShell *gs)
{
	EphyNautilusView *view;
	view = EPHY_NAUTILUS_VIEW (g_object_new (EPHY_TYPE_NAUTILUS_VIEW, NULL));
	return BONOBO_OBJECT (view);
}

static void
ephy_nautilus_view_finalize (GObject *object)
{
	EphyNautilusView *view = EPHY_NAUTILUS_VIEW (object);
	EphyNautilusViewPrivate *p = view->priv;

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

	g_object_unref (p->popup);

	g_free (p->title);
	g_free (p->location);
	g_free (p);

	GNOME_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));

	g_object_unref (G_OBJECT (ephy_shell));
}

static void
ephy_nautilus_view_class_init (EphyNautilusViewClass *class)
{
	G_OBJECT_CLASS (class)->finalize = ephy_nautilus_view_finalize;
}

static gint
gnv_embed_dom_mouse_click_cb (EphyEmbed *embed,
			      EphyEmbedEvent *event,
			      EphyNautilusView *view)
{
	EphyEmbedEventType type;
	EmbedEventContext context;

	ephy_embed_event_get_event_type (event, &type);
	ephy_embed_event_get_context (event, &context);

	if (type == EPHY_EMBED_EVENT_MOUSE_BUTTON2
	    && (context & EMBED_CONTEXT_LINK))
	{
		const GValue *value;
		const gchar *url;
		ephy_embed_event_get_property (event, "link", &value);
		url = g_value_get_string (value);

		g_return_val_if_fail (url, FALSE);

		nautilus_view_open_location_force_new_window (NAUTILUS_VIEW (view),
							      url, NULL);
	}

	return FALSE;
}

static void
gnv_embed_context_menu_cb (EphyEmbed *embed,
			   EphyEmbedEvent *event,
			   EphyNautilusView *view)
{
	EphyNautilusViewPrivate *p = view->priv;
	EmbedEventContext context;

	ephy_embed_event_get_context (event, &context);
	ephy_embed_popup_control_set_event (p->popup, event);
	ephy_embed_popup_control_show (p->popup, embed);
}

static void
gnv_embed_link_message_cb (EphyEmbed *embed, const char *message, EphyNautilusView *view)
{
	g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
	g_return_if_fail (message != NULL);

	nautilus_view_report_status (NAUTILUS_VIEW (view), message);
}

static void
gnv_embed_location_cb (EphyEmbed *embed, EphyNautilusView *view)
{
	EphyNautilusViewPrivate *p;
	const gchar *prefixes_to_ignore[] = 
		{
			"about:",
			"javascript:",
			NULL 
		};
	int i = 0;
	gchar *new_uri;

 	g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
	p = view->priv;
	g_return_if_fail (view->priv->embed == embed);

	ephy_embed_get_location (embed, TRUE, &new_uri);

 	g_return_if_fail (new_uri != NULL);


	/* don't inform nautilus about uris that it can't understand */
	while (prefixes_to_ignore[i] != NULL)
	{
		if (!strncmp (prefixes_to_ignore[i], new_uri, strlen (prefixes_to_ignore[i])))
		{
			g_free (new_uri);
			return;
		}
		++i;
	}

	nautilus_view_report_location_change (NAUTILUS_VIEW (view), new_uri, NULL, new_uri);

	g_free (p->location);
	p->location = new_uri;
}

static void
gnv_embed_title_cb (EphyEmbed *embed, EphyNautilusView *view)
{
	EphyNautilusViewPrivate *p;

 	g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
	p = view->priv;
	g_return_if_fail (view->priv->embed == embed);

	g_free (p->title);
	ephy_embed_get_title (embed, &p->title);

 	nautilus_view_set_title (NAUTILUS_VIEW (view), p->title);
}

static void
gnv_load_location_cb (EphyNautilusView *view, const char *location, gpointer user_data)
{
	g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
	g_return_if_fail (location != NULL);

	nautilus_view_report_load_underway (NAUTILUS_VIEW (view));
        ephy_embed_load_url (view->priv->embed, location);

}

static void
gnv_stop_loading_cb (EphyNautilusView *view, gpointer user_data)
{
}

static void
gnv_embed_new_window_cb (EphyEmbed *embed, EphyEmbed **new_embed,
			 EmbedChromeMask chromemask, EphyNautilusView *view)
{
	EphyTab *new_tab;
	EphyWindow *window;
	
	window = ephy_window_new ();
	if (!(chromemask & EMBED_CHROME_OPENASCHROME))
	{
		ephy_window_set_chrome (window, 
					  chromemask | 
					  EMBED_CHROME_OPENASPOPUP);
	}
	new_tab = ephy_tab_new ();
	ephy_window_add_tab (window, new_tab, EPHY_NOTEBOOK_INSERT_LAST, FALSE);

	*new_embed = ephy_tab_get_embed (new_tab);
}


static void
gnv_bonobo_control_activate_cb (BonoboControl *control, gboolean state, EphyNautilusView *view)
{
	if (state)
	{
		EphyNautilusViewPrivate *p = view->priv;
		
		p->ui = nautilus_view_set_up_ui (NAUTILUS_VIEW (view), SHARE_DIR,
						 "nautilus-epiphany-view.xml", "EphyNautilusView");
		g_return_if_fail (BONOBO_IS_UI_COMPONENT (p->ui));
		
		ephy_embed_utils_build_encodings_submenu (p->ui,
							   ENCODING_MENU_PATH,
							   (BonoboUIVerbFn) gnv_cmd_set_encoding,
							   view);

		bonobo_ui_component_add_verb_list_with_data (p->ui, ephy_verbs, view);
	}
}

static EphyNautilusView *
gnv_view_from_popup (EphyEmbedPopupControl*popup)
{
	return g_object_get_data (G_OBJECT (popup), "NautilisView");
}


static void 
gnv_popup_cmd_new_window (BonoboUIComponent *uic, 
			  EphyEmbedPopupControl*popup, 
			  const char* verbname)
{
	EphyEmbedEvent *info;
	EphyNautilusView *view;
	const GValue *value;

	view = gnv_view_from_popup (popup);
	
	info = ephy_embed_popup_control_get_event (popup);
	
	ephy_embed_event_get_property (info, "link", &value);

	nautilus_view_open_location_force_new_window (NAUTILUS_VIEW (view),
						      g_value_get_string (value), NULL);
}

static void 
gnv_popup_cmd_image_in_new_window (BonoboUIComponent *uic, 
				   EphyEmbedPopupControl*popup, 
				   const char* verbname)
{
	EphyEmbedEvent *info;
	EphyNautilusView *view;
	const GValue *value;

	view = gnv_view_from_popup (popup);
	
	info = ephy_embed_popup_control_get_event (popup);
	
	ephy_embed_event_get_property (info, "image", &value);

	nautilus_view_open_location_force_new_window (NAUTILUS_VIEW (view),
						      g_value_get_string (value), NULL);
}

static void 
gnv_popup_cmd_frame_in_new_window (BonoboUIComponent *uic, 
				   EphyEmbedPopupControl*popup, 
				   const char* verbname)
{
	EphyEmbedEvent *info;
	EphyNautilusView *view;
	gchar *location;

	view = gnv_view_from_popup (popup);
	
	info = ephy_embed_popup_control_get_event (popup);
	
	ephy_embed_get_location (view->priv->embed, FALSE, &location);

	nautilus_view_open_location_force_new_window (NAUTILUS_VIEW (view),
						      location, NULL);
	g_free (location);
}

void 
gnv_cmd_set_encoding (BonoboUIComponent *uic, 
		      EphyNautilusView *view,
		      const char* verbname)
{
	const char *encoding;

	g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));

	if (strncmp (verbname, "Encoding", 8) == 0)
	{
		encoding = verbname + 8;
		
		LOG ("Set encoding %s", encoding)

		ephy_embed_set_encoding (view->priv->embed, encoding);
	}
}

static void
gnv_cmd_file_print (BonoboUIComponent *uic, 
		    EphyNautilusView *view, 
		    const char* verbname)
{
	EphyDialog *dialog;
	EphyNautilusViewPrivate *p = view->priv;
	
	dialog = print_dialog_new (p->embed, NULL);

	ephy_dialog_set_modal (dialog, TRUE);
	ephy_dialog_show (dialog);

}

static void
gnv_cmd_edit_find (BonoboUIComponent *uic, 
		   EphyNautilusView *view, 
		   const char* verbname)
{
	EphyNautilusViewPrivate *p = view->priv;

	if (!p->find_dialog)
	{
		p->find_dialog = find_dialog_new (p->embed);
	}

	ephy_dialog_show (p->find_dialog);
}


/* zoomable */
static void
gnv_zoomable_set_zoom_level_cb (BonoboZoomable *zoomable,
				float level,
				EphyNautilusView *view)
{
	g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
	ephy_embed_zoom_set (view->priv->embed,
			     ephy_zoom_get_nearest_zoom_level (level), TRUE);
}

static void
gnv_zoomable_zoom_in_cb (BonoboZoomable *zoomable,
			 EphyNautilusView *view)
{
	float zoom, new_zoom;
	gresult rv;
	
	g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));

	rv = ephy_embed_zoom_get (view->priv->embed, &zoom);
	if (rv == G_FAILED) return;

	new_zoom = ephy_zoom_get_changed_zoom_level (zoom, 1);
	ephy_embed_zoom_set (view->priv->embed, new_zoom, TRUE);
}

static void
gnv_zoomable_zoom_out_cb (BonoboZoomable *zoomable,
			  EphyNautilusView *view)
{
	float zoom, new_zoom;
	gresult rv;
		
	g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));

	rv = ephy_embed_zoom_get (view->priv->embed, &zoom);
	if (rv == G_FAILED) return;

	new_zoom = ephy_zoom_get_changed_zoom_level (zoom, -1);
	ephy_embed_zoom_set (view->priv->embed, new_zoom, TRUE);
}

static void
gnv_zoomable_zoom_to_fit_cb (BonoboZoomable *zoomable,
			     EphyNautilusView *view)
{
	gnv_zoomable_zoom_to_default_cb (zoomable, view);
}

static void
gnv_zoomable_zoom_to_default_cb	(BonoboZoomable *zoomable,
				 EphyNautilusView *view)
{
	g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
	ephy_embed_zoom_set (view->priv->embed, 1.0, TRUE);
}

static void
gnv_embed_zoom_change_cb (EphyNautilusView *embed,
			  float new_zoom, 
			  EphyNautilusView *view)
{
	g_return_if_fail (EPHY_IS_NAUTILUS_VIEW (view));
	
	bonobo_zoomable_report_zoom_level_changed (view->priv->zoomable,
						   new_zoom, NULL);
}