// -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-

//
//  Copyright (C) 2002-2003 Hiroyuki Ikezoe
//  Copyright (C) 2003 Takuro Ashie
//
//  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 "kz-mozembed.h"

#include <string.h>
#include <math.h>
#include <gtkmozembed.h>
#include <gtkmozembed_internal.h>
#include <glib/gi18n.h>

#include "kazehakase.h"
#include "kz-window.h"
#include "kz-mozwrapper.h"
#include "kz-mozprogresslistener.h"
#include "kz-mozthumbnailcreator.h"
#include "gobject-utils.h"
#include "mozilla.h"
#include "mozilla-prefs.h"
#include "bookmarks/kz-bookmark.h"
#if USE_MIGEMO
#include "migemo.h"
#endif
#include "utils.h"
#include "estsearch.h"

#include <nsCOMPtr.h>
#include <nsIDOMDocument.h>
#include <content/nsIDocumentViewer.h>
#include <content/nsIContent.h>
#include <nsIWebBrowser.h>
#include <content/nsIDocument.h>
#include <nsIDOMMouseEvent.h>
#include <dom/nsIDOMKeyEvent.h>
#include <nsIDOMEventTarget.h>
#include <dom/nsIDOMNSHTMLElement.h>  
#include <nsIDOMHTMLElement.h>  
#include <nsIDOMHTMLTextAreaElement.h>  
#include <nsIDOMNamedNodeMap.h>
#include <webbrowserpersist/nsIWebBrowserPersist.h>
#include <necko/nsNetUtil.h>
#include <nsIWebBrowserFind.h>
#include <dom/nsIDOMNSDocument.h>
#include <dom/nsIDOMNSEvent.h>
#include <docshell/nsIDocShell.h>
#include <docshell/nsIDocShellTreeItem.h>
#include <docshell/nsIDocShellTreeOwner.h>
#include <nsIPresShell.h>
#include <nsIDOMNodeList.h>
#include <nsIDOMWindow.h>
#include <nsISelection.h>
#include <nsIDOMRange.h>
#include <nsIWebBrowserFind.h>
#include <necko/nsNetUtil.h>
#include <uconv/nsICharsetConverterManager.h>
#if MOZILLA_SNAPSHOT < 10
#	include <uconv/nsICharsetConverterManager2.h>
#endif
#include <nsIDOMWindow.h>
#include <nsISelection.h>
#include <nsISHistory.h>
#include <nsIHistoryEntry.h>
#include <nsISHEntry.h>
#include <nsISHistoryInternal.h>
#include <nsIWebNavigation.h>
#include <nsCWebBrowserPersist.h>
#include <widget/nsIBaseWindow.h>
#include <nsIWebPageDescriptor.h>
#include <nsIEventStateManager.h>
#include <nsICommandManager.h>
#include <nsTime.h>

#define N_LINKS 6

static gchar *nav_names[N_LINKS] =
{
 "NEXT", "PREV", "INDEX", "CONTENTS", "START", "ALTERNATE"
};

struct _KzMozEmbedPriv
{
	KzMozWrapper *wrapper;
	gint size_inited;
	gint cur_requests;
	gint total_requests;
	
	gboolean lock;

	/* for navigation link */
	gchar *nav_links[N_LINKS];

#ifdef USE_MIGEMO
	gchar *migemo_keyword;
#endif
	gchar *first_url;
};

static void kz_moz_embed_class_init    (KzMozEmbedClass *klass);
static void kz_moz_embed_init          (KzMozEmbed  *kzembed);
static void kz_moz_embed_destroy       (GtkObject   *object);
static void kz_moz_embed_finalize      (GObject     *object);
static void kz_moz_embed_realize       (GtkWidget   *widget);
static void kz_moz_embed_unrealize     (GtkWidget   *widget);
static void kz_moz_embed_size_allocate (GtkWidget   *widget,
					GtkAllocation *allocation);
static void kz_moz_embed_destroy_brsr  (GtkMozEmbed *embed);
static void kz_moz_embed_link_message  (GtkMozEmbed *embed);
static void kz_moz_embed_js_status     (GtkMozEmbed *embed);
static void kz_moz_embed_title         (GtkMozEmbed *embed);
static void kz_moz_embed_location      (GtkMozEmbed *embed);
static void kz_moz_embed_net_start     (GtkMozEmbed *embed);
static void kz_moz_embed_new_window    (GtkMozEmbed *embed,
					GtkMozEmbed **newembed,
					guint        chromemask);
static gint kz_moz_embed_open_uri      (GtkMozEmbed *embed,
					const char  *uri);
static void kz_moz_embed_size_to       (GtkMozEmbed *embed,
					gint         width,
					gint         height);
static void kz_moz_embed_visibility    (GtkMozEmbed *embed,
					gboolean     visibility);
static void kz_moz_embed_net_stop      (GtkMozEmbed *embed);
static void kz_moz_embed_net_state_all (GtkMozEmbed *embed,
					const char  *aURI,
					gint         state,
					guint        status);
#if 0
static void kz_moz_embed_security_change (GtkMozEmbed *embed,
					  gpointer     request,
					  guint        state);
#endif
static void kz_moz_embed_navigation_link_free(KzMozEmbed *kzembed);

static gint kz_moz_embed_dom_key_down        (GtkMozEmbed *embed, gpointer event);
static gint kz_moz_embed_dom_key_up          (GtkMozEmbed *embed, gpointer event);
static gint kz_moz_embed_dom_key_press       (GtkMozEmbed *embed, gpointer event);
static gint kz_moz_embed_dom_mouse_down      (GtkMozEmbed *embed, gpointer event);
static gint kz_moz_embed_dom_mouse_up        (GtkMozEmbed *embed, gpointer event);
static gint kz_moz_embed_dom_mouse_click     (GtkMozEmbed *embed, gpointer event);
static gint kz_moz_embed_dom_mouse_dbl_click (GtkMozEmbed *embed, gpointer event);

static glong     mozilla_set_event_context  (KzMozEmbed *kzembed,
					     nsIDOMEventTarget *target,
					     KzEmbedEvent *info);

static gchar	*mozilla_store_history_file (KzMozEmbed *kzembed);

static void         kz_moz_embed_load_url              (KzEmbed      *kzembed,
							const gchar  *url);
static void         kz_moz_embed_view_source           (KzEmbed      *kzembed,
							const gchar  *url);

static gboolean     kz_moz_embed_is_loading            (KzEmbed      *kzembed);

static const gchar *kz_moz_embed_get_title             (KzEmbed      *kzembed);
static const gchar *kz_moz_embed_get_location          (KzEmbed      *kzembed);
static gchar       *kz_moz_embed_ensure_title          (KzEmbed      *kzembed);
static gchar       *kz_moz_embed_get_link_message      (KzEmbed      *kzembed);

static gdouble      kz_moz_embed_get_progress          (KzEmbed      *kzembed);

static gboolean     kz_moz_embed_can_cut_selection     (KzEmbed      *kzembed);
static gboolean     kz_moz_embed_can_copy_selection    (KzEmbed      *kzembed);
static gboolean     kz_moz_embed_can_paste             (KzEmbed      *kzembed);
static void         kz_moz_embed_cut_selection         (KzEmbed      *kzembed);
static void         kz_moz_embed_copy_selection        (KzEmbed      *kzembed);
static void         kz_moz_embed_paste                 (KzEmbed      *kzembed);
static void         kz_moz_embed_select_all            (KzEmbed      *kzembed);

static gchar       *kz_moz_embed_get_selection_string  (KzEmbed      *kzembed);

static gboolean     kz_moz_embed_find                  (KzEmbed      *kzembed,
							const char   *keyword,
							gboolean      backward);
static gboolean     kz_moz_embed_incremental_search    (KzEmbed      *kzembed,
							const char   *keyword,
							gboolean      backward);

static gboolean     kz_moz_embed_selection_is_collapsed(KzEmbed      *kzembed);

static gboolean     kz_moz_embed_get_links             (KzEmbed      *kzembed,
							GList       **list,
							gboolean      selected_only);

static void         kz_moz_embed_copy_page             (KzEmbed      *kzembed,
							KzEmbed      *dkzembed);
static gboolean     kz_moz_embed_shistory_copy         (KzEmbed      *source,
							KzEmbed      *dest,
							gboolean      back_history,
							gboolean      forward_history,
							gboolean      set_current);
static gboolean     kz_moz_embed_shistory_get_pos      (KzEmbed      *kzembed,
							int          *pos,
							int          *count);
static void         kz_moz_embed_shistory_get_nth      (KzEmbed      *kzembed, 
							int           nth,
							gboolean      is_relative,
							char        **aUrl,
							char        **aTitle);

static void         kz_moz_embed_reload                (KzEmbed      *kzembed,
							gint32        flags);
static void         kz_moz_embed_stop_load             (KzEmbed      *kzembed);
static void         kz_moz_embed_go_back               (KzEmbed      *kzembed);
static void         kz_moz_embed_go_forward            (KzEmbed      *kzembed);

static gboolean     kz_moz_embed_can_go_back           (KzEmbed      *kzembed);
static gboolean     kz_moz_embed_can_go_forward        (KzEmbed      *kzembed);
#if 0
static void         kz_moz_embed_go_up                 (KzEmbed      *kzembed);
static gboolean     kz_moz_embed_can_go_up             (KzEmbed      *kzembed);
#endif
static gboolean     kz_moz_embed_can_go_nav_link       (KzEmbed      *kzembed,
							KzEmbedNavLink link);
static void         kz_moz_embed_go_nav_link           (KzEmbed      *kzembed,
							KzEmbedNavLink link);
static void         kz_moz_embed_set_nav_link          (KzEmbed      *kzembed,
							const gchar  *name,
							const gchar  *link);
static void         kz_moz_embed_go_history_index      (KzEmbed      *kzembed,
							gint          index);

static void         kz_moz_embed_do_command            (KzEmbed      *kzembed,
							const char   *command);
static gboolean     kz_moz_embed_can_do_command        (KzEmbed      *kzembed,
							const char   *command);

static gboolean     kz_moz_embed_get_lock              (KzEmbed      *kzembed);
static void         kz_moz_embed_set_lock              (KzEmbed      *kzembed,
							gboolean      lock);

static gchar       *kz_moz_embed_get_body_text         (KzEmbed      *kzembed);
#if 0
static gchar       *kz_moz_embed_get_selection_source  (KzEmbed      *kzembed);
#endif
static void         kz_moz_embed_set_encoding          (KzEmbed      *kzembed,
							const char   *encoding);
static void         kz_moz_embed_get_encoding          (KzEmbed      *kzembed,
							char        **encoding,
							gboolean     *forced);
static void         kz_moz_embed_print                 (KzEmbed      *kzembed);
static void         kz_moz_embed_print_preview         (KzEmbed      *kzembed);
static void         kz_moz_embed_create_thumbnail      (KzEmbed      *kzembed);


static gboolean     kz_moz_embed_save_with_content     (KzEmbed      *kzembed,
							const char   *rawfilename);

static gboolean     kz_moz_embed_set_text_into_textarea(KzEmbed      *kzembed,
							gpointer      element,
							const gchar  *text);
static gchar       *kz_moz_embed_get_text_from_textarea(KzEmbed      *kzembed,
							gpointer      element);


static void         kz_moz_embed_zoom_set              (KzEmbed      *kzembed, 
							int           zoom, 
							gboolean      reflow);
static int          kz_moz_embed_zoom_get              (KzEmbed      *kzembed);
static void         kz_moz_embed_set_text_size         (KzEmbed      *kzembed, 
							int           zoom, 
							gboolean      reflow);
static int          kz_moz_embed_get_text_size         (KzEmbed      *kzembed);

static gchar       *kz_moz_embed_get_html_with_contents
						(KzEmbed      *kzembed,
						 const gchar  *storedir);

static void	     kz_moz_embed_set_history           (KzEmbed      *kzembed,
							 KzBookmark   *history);
static void	     kz_moz_embed_get_history           (KzEmbed      *kzembed,
							 KzBookmark   *history);
static guint	     kz_moz_embed_get_last_modified     (KzEmbed      *kzembed);
#if 0
static void         kz_moz_embed_set_edit_mode         (KzEmbed      *kzembed);
static void         kz_moz_embed_set_view_mode         (KzEmbed      *kzembed);
#endif

static GtkMozEmbedClass *parent_class = NULL;

static void
kz_moz_embed_iface_init (KzEmbedIFace *iface)
{
	iface->load_url               = kz_moz_embed_load_url;
	iface->view_source            = kz_moz_embed_view_source;
	iface->is_loading             = kz_moz_embed_is_loading;
	iface->get_title              = kz_moz_embed_get_title;
	iface->get_location           = kz_moz_embed_get_location;
	iface->ensure_title           = kz_moz_embed_ensure_title;
	iface->get_link_message       = kz_moz_embed_get_link_message;
	iface->get_progress           = kz_moz_embed_get_progress;
	iface->can_cut_selection      = kz_moz_embed_can_cut_selection;
	iface->can_copy_selection     = kz_moz_embed_can_copy_selection;
	iface->can_paste              = kz_moz_embed_can_paste;
	iface->cut_selection          = kz_moz_embed_cut_selection;
	iface->copy_selection         = kz_moz_embed_copy_selection;
	iface->paste                  = kz_moz_embed_paste;
	iface->select_all             = kz_moz_embed_select_all;
	iface->get_selection_string   = kz_moz_embed_get_selection_string;
	iface->find                   = kz_moz_embed_find;
	iface->incremental_search     = kz_moz_embed_incremental_search;
	iface->selection_is_collapsed = kz_moz_embed_selection_is_collapsed;
	iface->get_links              = kz_moz_embed_get_links;
	iface->copy_page              = kz_moz_embed_copy_page;
	iface->shistory_copy          = kz_moz_embed_shistory_copy;
	iface->shistory_get_pos       = kz_moz_embed_shistory_get_pos;
	iface->shistory_get_nth       = kz_moz_embed_shistory_get_nth;
	iface->reload                 = kz_moz_embed_reload;
	iface->stop_load              = kz_moz_embed_stop_load;
	iface->go_back                = kz_moz_embed_go_back;
	iface->go_forward             = kz_moz_embed_go_forward;
	iface->can_go_back            = kz_moz_embed_can_go_back;
	iface->can_go_forward         = kz_moz_embed_can_go_forward;
// go_up function moved into kz-embed.c
//	iface->go_up                  = kz_moz_embed_go_up;
//	iface->can_go_up              = kz_moz_embed_can_go_up;
	iface->can_go_nav_link        = kz_moz_embed_can_go_nav_link;
	iface->go_nav_link            = kz_moz_embed_go_nav_link;
	iface->set_nav_link           = kz_moz_embed_set_nav_link;
	iface->go_history_index       = kz_moz_embed_go_history_index;
	iface->do_command             = kz_moz_embed_do_command;
	iface->can_do_command         = kz_moz_embed_can_do_command;
	iface->get_lock               = kz_moz_embed_get_lock;
	iface->set_lock               = kz_moz_embed_set_lock;
	iface->get_body_text          = kz_moz_embed_get_body_text;
#if 0
	iface->get_selection_source   = kz_moz_embed_get_selection_source;
#endif
	iface->set_encoding           = kz_moz_embed_set_encoding;
	iface->get_encoding           = kz_moz_embed_get_encoding;
	iface->print                  = kz_moz_embed_print;
	iface->print_preview          = kz_moz_embed_print_preview;
	iface->create_thumbnail       = kz_moz_embed_create_thumbnail;
	iface->save_with_content      = kz_moz_embed_save_with_content;
	iface->set_text_into_textarea = kz_moz_embed_set_text_into_textarea;
	iface->get_text_from_textarea = kz_moz_embed_get_text_from_textarea;
	iface->zoom_set               = kz_moz_embed_zoom_set;
	iface->zoom_get               = kz_moz_embed_zoom_get;
	iface->set_text_size          = kz_moz_embed_set_text_size;
	iface->get_text_size          = kz_moz_embed_get_text_size;
	iface->get_html_with_contents = kz_moz_embed_get_html_with_contents;
	iface->set_history            = kz_moz_embed_set_history;
	iface->get_history            = kz_moz_embed_get_history;
	iface->get_last_modified      = kz_moz_embed_get_last_modified;
#if 0
	iface->set_edit_mode          = set_edit_mode;
	iface->set_view_mode          = set_view_mode;
#endif

	iface->link_message        = NULL;
	iface->js_status           = NULL;
	iface->location            = NULL;
	iface->title               = NULL;
	iface->progress            = NULL;
	iface->net_start           = NULL;
	iface->net_stop            = NULL;
	iface->new_window          = NULL;
	iface->open_uri            = NULL;
	iface->size_to             = NULL;
	iface->dom_key_down        = NULL;
	iface->dom_key_press       = NULL;
	iface->dom_key_up          = NULL;
	iface->dom_mouse_down      = NULL;
	iface->dom_mouse_up        = NULL;
	iface->dom_mouse_click     = NULL;
	iface->dom_mouse_dbl_click = NULL;
	iface->dom_mouse_over      = NULL;
	iface->dom_mouse_out       = NULL;
	iface->security_change     = NULL;
	iface->status_change       = NULL;
}

KZ_OBJECT_GET_TYPE_IFACE(kz_moz_embed, "KzMozEmbed", KzMozEmbed,
			 kz_moz_embed_class_init, kz_moz_embed_init,
			 GTK_TYPE_MOZ_EMBED,
			 kz_moz_embed_iface_init, KZ_TYPE_EMBED)


static void
kz_moz_embed_class_init (KzMozEmbedClass *klass)
{
	GObjectClass *gobject_class;
	GtkObjectClass *object_class;
	GtkWidgetClass *widget_class;
	GtkMozEmbedClass *moz_embed_class;

	parent_class    = (GtkMozEmbedClass *) g_type_class_peek_parent (klass);

	gobject_class   = (GObjectClass *) klass;
	object_class    = (GtkObjectClass *) klass;
	widget_class    = (GtkWidgetClass *) klass;
	moz_embed_class = (GtkMozEmbedClass *) klass;

	// GObject
	gobject_class->finalize = kz_moz_embed_finalize;

	// GtkObject signals
	object_class->destroy = kz_moz_embed_destroy;
 
	// widget class
	widget_class->realize         = kz_moz_embed_realize;
	widget_class->unrealize       = kz_moz_embed_unrealize;
	widget_class->size_allocate   = kz_moz_embed_size_allocate;
 
	// GtkMozEmbedSignals
	moz_embed_class->net_state_all   = kz_moz_embed_net_state_all;
#if 0
	moz_embed_class->security_change     = kz_moz_embed_security_change;
	moz_embed_class->dom_mouse_over      = kz_moz_embed_dom_mouse_over;
	moz_embed_class->dom_mouse_out       = kz_moz_embed_dom_mouse_out;
	moz_embed_class->net_state           = kz_moz_embed_net_state;
	moz_embed_class->progress            = kz_moz_embed_progress;
	moz_embed_class->progress_all        = kz_moz_embed_progress_all;
#endif
	moz_embed_class->destroy_brsr        = kz_moz_embed_destroy_brsr;

	moz_embed_class->link_message        = kz_moz_embed_link_message;
	moz_embed_class->js_status           = kz_moz_embed_js_status;
	moz_embed_class->title               = kz_moz_embed_title;
	moz_embed_class->location            = kz_moz_embed_location;
	moz_embed_class->net_start           = kz_moz_embed_net_start;
	moz_embed_class->net_stop            = kz_moz_embed_net_stop;
	moz_embed_class->new_window          = kz_moz_embed_new_window;
	moz_embed_class->open_uri            = kz_moz_embed_open_uri;
	moz_embed_class->size_to             = kz_moz_embed_size_to;
	moz_embed_class->visibility          = kz_moz_embed_visibility;
	moz_embed_class->dom_key_press       = kz_moz_embed_dom_key_press;
	moz_embed_class->dom_key_down        = kz_moz_embed_dom_key_down;
	moz_embed_class->dom_key_up          = kz_moz_embed_dom_key_up;
	moz_embed_class->dom_mouse_down      = kz_moz_embed_dom_mouse_down;
	moz_embed_class->dom_mouse_up        = kz_moz_embed_dom_mouse_up;
	moz_embed_class->dom_mouse_click     = kz_moz_embed_dom_mouse_click;
	moz_embed_class->dom_mouse_dbl_click = kz_moz_embed_dom_mouse_dbl_click;
}

static void
kz_moz_embed_init (KzMozEmbed *kzembed)
{
	gint i;
	// widgets
	kzembed->popup_window          = NULL;

	// status
	kzembed->location              = NULL;
	kzembed->title                 = NULL;
	kzembed->load_started          = 0;
	kzembed->load_percent          = 0;
	kzembed->bytes_loaded          = 0;
	kzembed->max_bytes_loaded      = 0;
	kzembed->is_loading            = FALSE;
	kzembed->load_status_message   = NULL;

	// priv
	kzembed->priv = g_new0(KzMozEmbedPriv, 1);
	kzembed->priv->wrapper        = NULL;
	kzembed->priv->size_inited    = FALSE;
	kzembed->priv->total_requests = 0;
	kzembed->priv->cur_requests   = 0;
	
	for (i =0; i < N_LINKS; i++)
	{
		kzembed->priv->nav_links[i] = NULL;
	}
#ifdef USE_MIGEMO
	kzembed->priv->migemo_keyword = NULL;
#endif
	kzembed->priv->first_url      = NULL;
	kz_moz_embed_load_url(KZ_EMBED(kzembed), "about:blank");
}

GtkWidget *
kz_moz_embed_new (const gchar *url)
{
	KzMozEmbed *kzembed = KZ_MOZ_EMBED(g_object_new(KZ_TYPE_MOZ_EMBED, NULL));

#if 0
	//
	// set the chrome type so it's stored in the object
	//
	g_moz_embed_set_chrome_mask(GTK_MOZ_EMBED(kzembed->mozembed),
				    actualChromeMask);
#endif
	
	// To use the gesture in empty tab, 
	// After "about:balnk" was loaded, the first url start to load.  
	if (url)
		kzembed->priv->first_url = g_strdup(url);
	//kz_moz_embed_load_url(KZ_EMBED(kzembed), url);

	return GTK_WIDGET(kzembed);
}

static void
kz_moz_embed_destroy (GtkObject *object)
{
	KzMozEmbed *kzembed = KZ_MOZ_EMBED(object);

	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));

	g_free(kzembed->location);
	kzembed->location = NULL;
	g_free(kzembed->title);
	kzembed->title = NULL;

	if (kzembed->priv->first_url)
		g_free(kzembed->priv->first_url);
	kzembed->priv->first_url = NULL;

	if (GTK_OBJECT_CLASS(parent_class)->destroy)
		GTK_OBJECT_CLASS(parent_class)->destroy(object);
}


KZ_OBJECT_FINALIZE (kz_moz_embed, KzMozEmbed)


static void
kz_moz_embed_realize (GtkWidget *widget)
{
	if (GTK_WIDGET_CLASS(parent_class)->realize)
		GTK_WIDGET_CLASS(parent_class)->realize(widget);

	KzMozEmbed *kzembed = KZ_MOZ_EMBED(widget);

	if (!kzembed->priv->wrapper)
	{
		kzembed->priv->wrapper = new KzMozWrapper();
		nsresult rv = kzembed->priv->wrapper->Init(kzembed);
		if (NS_FAILED(rv))
		{
			g_error("KzMozEmbed: Faild to init KzMozWrapper!");
		}
	}
}


static void
kz_moz_embed_unrealize (GtkWidget *widget)
{
	KzMozEmbed *kzembed = KZ_MOZ_EMBED(widget);

	kzembed->priv->size_inited = FALSE;

	if (kzembed->priv->wrapper)
	{
		kzembed->priv->wrapper->Destroy();
		delete kzembed->priv->wrapper;
		kzembed->priv->wrapper = NULL;
	}
	
	kz_moz_embed_navigation_link_free(kzembed);
	
	if (GTK_WIDGET_CLASS(parent_class)->unrealize)
		GTK_WIDGET_CLASS(parent_class)->unrealize(widget);
}


static void
kz_moz_embed_navigation_link_free(KzMozEmbed *kzembed)
{	
	gint i;
	
	for (i =0; i < N_LINKS; i++)
	{
		if (kzembed->priv->nav_links[i])
		{
			g_free(kzembed->priv->nav_links[i]);
			kzembed->priv->nav_links[i] = NULL;
		}
	}
#ifdef USE_MIGEMO
	if (kzembed->priv->migemo_keyword)
		g_free(kzembed->priv->migemo_keyword);
	kzembed->priv->migemo_keyword =NULL;
#endif
}


static void
kz_moz_embed_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
{
	KzMozEmbed *kzembed = KZ_MOZ_EMBED(widget);

	g_return_if_fail(GTK_IS_WIDGET(widget));

	if (!GTK_WIDGET_REALIZED(widget)) return;

	if (!kzembed->priv->size_inited) 
	{
		// for preventing invalid scroll position 
		// when new tab background opens with anchor (html#xx)  
		nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(kzembed->priv->wrapper->mWebBrowser);
		baseWindow->SetPositionAndSize(0, 0,
					       allocation->width,
					       allocation->height,
					       PR_FALSE);
	}
	if (!GTK_WIDGET_MAPPED(widget))
		return;
	
	if (GTK_WIDGET_CLASS(parent_class)->size_allocate)
		GTK_WIDGET_CLASS(parent_class)->size_allocate(widget, allocation);

	kzembed->priv->size_inited = TRUE;
}


static void
kz_moz_embed_load_url (KzEmbed *kzembed, const gchar *url)
{
	gchar *start_page = NULL, *str;

	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));

	KzMozEmbed *mozembed = KZ_MOZ_EMBED(kzembed);

	str = KZ_CONF_GET_STR("Global", "startup_page");

	if (url && *url)
	{
		start_page = g_strdup(url);
	}
	else if (str)
	{
		start_page = g_strdup(str);
	}
	else
	{
		start_page = g_strdup("about:blank");
	}

	if (!mozembed->priv->first_url &&
	    kz_moz_embed_get_lock(kzembed))
	{
		GtkMozEmbed *newembed = NULL;
		g_signal_emit_by_name(G_OBJECT(kzembed), 
				      "new-window",
				      &newembed, 0);
		gtk_moz_embed_load_url(newembed, start_page);
	}
	else
		gtk_moz_embed_load_url(GTK_MOZ_EMBED(kzembed), start_page);
	
	if (mozembed->location)
		g_free(mozembed->location);
	mozembed->location = start_page;

	g_free(str);
}


static void
kz_moz_embed_view_source (KzEmbed *kzembed, const gchar *url)
{
	KzMozWrapper *wrapper = KZ_MOZ_EMBED(kzembed)->priv->wrapper;
	nsresult rv;

        nsCOMPtr<nsISupports> pageDescriptor;
        rv = wrapper->GetPageDescriptor(getter_AddRefs(pageDescriptor));
        if (!pageDescriptor || NS_FAILED(rv)) return;

        rv = wrapper->LoadDocument(pageDescriptor, 
				   nsIWebPageDescriptor::DISPLAY_AS_SOURCE);
}


static gboolean
kz_moz_embed_is_loading (KzEmbed *kzembed)
{
	return KZ_IS_MOZ_EMBED(kzembed)
		? KZ_MOZ_EMBED(kzembed)->is_loading
		: FALSE;
}


static const gchar *
kz_moz_embed_get_title (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_MOZ_EMBED(kzembed), NULL);
	return KZ_MOZ_EMBED(kzembed)->title;
}

static gchar *
kz_moz_embed_ensure_title (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_MOZ_EMBED(kzembed), NULL);

	KzMozEmbed *mozembed = KZ_MOZ_EMBED(kzembed);

	if (mozembed->title && *mozembed->title)
		return g_strdup(mozembed->title);

	if (mozembed->location && *mozembed->location)
	{
		if (kz_moz_embed_is_loading(kzembed))
		{
			return g_strdup_printf(_("Loading %s ..."),
					       mozembed->location);
		}
		else
		{
			return g_strdup(mozembed->location);
		}
	}
	else
	{
		if (kz_moz_embed_is_loading(kzembed))
			return g_strdup(_("Loading..."));
	}

	return g_strdup(_("No title"));
}

static gchar * 
kz_moz_embed_get_link_message (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_MOZ_EMBED(kzembed), NULL);

	gchar *message;
	nsXPIDLString  uMessage;

	*getter_Copies(uMessage) = gtk_moz_embed_get_link_message_unichar
						(GTK_MOZ_EMBED(kzembed));
	message = g_strdup(NS_ConvertUCS2toUTF8(uMessage).get());

	return message;
}


static gdouble
kz_moz_embed_get_progress (KzEmbed *kzembed)
{
	gdouble progress;

	g_return_val_if_fail(KZ_MOZ_EMBED(kzembed), 0.0);

	KzMozEmbed *mozembed = KZ_MOZ_EMBED(kzembed);

	if (mozembed->priv->total_requests <= 0 ||
	    mozembed->priv->cur_requests <= 0)
	{
		return 0.0;
	}

	progress = (gdouble) mozembed->priv->cur_requests
		/ (gdouble) mozembed->priv->total_requests;

	if (progress > 1.0)
		return 1.0;

	return progress;
}


static const gchar *
kz_moz_embed_get_location (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_MOZ_EMBED(kzembed), NULL);

	KzMozEmbed *mozembed = KZ_MOZ_EMBED(kzembed);

	if (mozembed->location != NULL &&
	    !strncmp(mozembed->location, "about:blank", 11))
	{
		return "";
	}

	return mozembed->location;
}

static void
kz_moz_embed_destroy_brsr (GtkMozEmbed *embed)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(embed));

	gtk_widget_destroy(GTK_WIDGET(embed));
}


static void
kz_moz_embed_link_message (GtkMozEmbed *embed)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(embed));

	g_signal_emit_by_name(G_OBJECT(embed), "kz-link-message");

	if (parent_class->link_message)
		parent_class->link_message(embed);
}

static void
kz_moz_embed_js_status (GtkMozEmbed *embed)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(embed));

	g_signal_emit_by_name(G_OBJECT(embed), "kz-js-status");

	if (parent_class->js_status)
		parent_class->js_status(embed);
}

static void
kz_moz_embed_title (GtkMozEmbed *embed)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(embed));

	KzMozEmbed *kzembed = KZ_MOZ_EMBED(embed);

	g_free(kzembed->title);

	nsXPIDLString  uTitle;
	*getter_Copies(uTitle) = gtk_moz_embed_get_title_unichar(embed);
	kzembed->title = g_strdup (NS_ConvertUCS2toUTF8(uTitle).get());

	g_signal_emit_by_name(G_OBJECT(embed), "kz-title");

	if (parent_class->title)
		parent_class->title(embed);
}

static void
kz_moz_embed_location (GtkMozEmbed *embed)
{
	KzMozEmbed *kzembed = KZ_MOZ_EMBED(embed);

	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));
	
	if (kzembed->priv->first_url)
	{
		gchar *tmp = g_strdup(kzembed->priv->first_url);
		g_free(kzembed->priv->first_url);
		kzembed->priv->first_url = NULL;

		kz_moz_embed_load_url(KZ_EMBED(kzembed),
				      tmp);
		g_free(tmp);

		return;
	}
	if (kzembed->location)
		g_free(kzembed->location);
	kzembed->location = gtk_moz_embed_get_location(embed);

	g_signal_emit_by_name(G_OBJECT(embed), "kz-location");

	if (parent_class->location)
		parent_class->location(embed);
}


static void
kz_moz_embed_net_start (GtkMozEmbed *embed)
{
	KzMozEmbed *kzembed = KZ_MOZ_EMBED(embed);

	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));

	if (kzembed->priv->first_url)
		return;

	kzembed->is_loading = TRUE;
	g_signal_emit_by_name(G_OBJECT(embed), "kz-net-start");

	if (parent_class->net_start)
		parent_class->net_start(embed);
}

static void
net_stop_proccess (KzMozEmbed *kzembed)
{
	gboolean create_thumbnail = FALSE, store_cache = TRUE;
	KZ_CONF_GET("Global", "create_thumbnail", create_thumbnail, BOOL);
	KZ_CONF_GET("History", "store_cache", store_cache, BOOL);

	gchar *cache = g_strconcat("file://", g_get_home_dir(),
			    	   HISTORY_DIR, NULL);
	const gchar *location = kz_moz_embed_get_location(KZ_EMBED(kzembed));
	if (location && 
	    (g_str_has_prefix(location, "http:") || 
	     g_str_has_prefix(location, "https:") || 
	     g_str_has_prefix(location, "history-search:") || 
	     g_str_has_prefix(location, "file:")) &&
	    !g_str_has_prefix(location, cache))
	{
		//get the last modification time
		nsCOMPtr<nsIDOMDocument> domDoc;
        	kzembed->priv->wrapper->GetMainDomDocument(getter_AddRefs(domDoc));
		nsCOMPtr<nsIDOMNSDocument> doc = do_QueryInterface(domDoc);
		nsAutoString value;
		doc->GetLastModified(value);
		nsTime lm (NS_ConvertUCS2toUTF8(value).get(), PR_TRUE);
		GTime last_modified;
		LL_DIV(last_modified,
		       NS_STATIC_CAST(PRTime, lm), PR_USEC_PER_SEC);

		nsCOMPtr<nsIURI> inURI;
		nsCAutoString sURI;
		nsresult rv;

		rv = kzembed->priv->wrapper->GetDocumentUrl(sURI);
      		rv = NS_NewURI(getter_AddRefs(inURI), sURI);

		gchar *uri = ToNewCString(sURI);

		if (create_thumbnail && 
		    (!last_modified || (thumbnail_get_last_modified(uri) < last_modified)))
		{
			kz_moz_embed_create_thumbnail(KZ_EMBED(kzembed));
		}
		
		if (store_cache && exists_estindex &&
		    (!last_modified || (history_get_last_modified(uri) < last_modified)) &&
		    !g_str_has_prefix(location, "history-search:"))
		{
			gchar *filename;
			filename = mozilla_store_history_file(kzembed);
			if (filename)
				g_idle_add(estsearch_update_index, filename);
		}
		g_free(uri);
	}
	
	g_free(cache);
}

static void
kz_moz_embed_net_stop (GtkMozEmbed *embed)
{
	KzMozEmbed *kzembed = KZ_MOZ_EMBED(embed);

	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));

	kzembed->is_loading = FALSE;

	if (parent_class->net_stop)
		parent_class->net_stop(embed);

	/* First free previous link */
	kz_moz_embed_navigation_link_free(kzembed);

	net_stop_proccess(kzembed);

	g_signal_emit_by_name(G_OBJECT(embed), "kz-net-stop");
}

static void
kz_moz_embed_net_state_all (GtkMozEmbed *embed, const char *aURI,
			    gint state, guint status)
{
	KzMozEmbed *kzembed = KZ_MOZ_EMBED(embed);

	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));

	if (state & GTK_MOZ_EMBED_FLAG_IS_NETWORK)
	{
		kzembed->priv->total_requests = 0;
		kzembed->priv->cur_requests = 0;
#if 0
                if (state & GTK_MOZ_EMBED_FLAG_START)
                {
		}
                else if (state & EMBED_STATE_STOP)
                {
                        kzembed->priv->total_requests = 0;
                        kzembed->priv->cur_requests = 0;
		} 
#endif
	}
        if (state & GTK_MOZ_EMBED_FLAG_IS_REQUEST)
        {
                if (state & GTK_MOZ_EMBED_FLAG_START)
                        kzembed->priv->total_requests ++;
                else if (state & GTK_MOZ_EMBED_FLAG_STOP)
                        kzembed->priv->cur_requests ++;
        }

	g_signal_emit_by_name(G_OBJECT(embed), "kz-progress");

	if (parent_class->net_state_all)
		parent_class->net_state_all(embed, aURI, state, status);
}

static void 
cb_embed_destroy_browser (GtkMozEmbed *embed, GtkWidget *transient_window)
{
	gtk_widget_destroy(GTK_WIDGET(transient_window));
}

static void
kz_moz_embed_new_window (GtkMozEmbed *embed, GtkMozEmbed **newEmbed,
			 guint chromemask)
{
	if ((chromemask & GTK_MOZ_EMBED_FLAG_OPENASCHROME) != 0)
	{
		/* FIXME! this is ad hoc. */
		GtkWidget *newWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);

		gtk_window_set_transient_for(GTK_WINDOW(newWindow),
					     GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(embed))));
		*newEmbed = GTK_MOZ_EMBED(kz_moz_embed_new(NULL));
		g_signal_connect(G_OBJECT(*newEmbed),"destroy_browser",
				 G_CALLBACK(cb_embed_destroy_browser),
				 newWindow);
		gtk_container_add(GTK_CONTAINER(newWindow),
				  GTK_WIDGET(*newEmbed));
	}
	else
	{
		g_signal_emit_by_name(G_OBJECT(embed), "kz-new-window", newEmbed);
	}
}

static gint
kz_moz_embed_open_uri (GtkMozEmbed *embed, const char *uri)
{
	gint ret = FALSE;

	g_signal_emit_by_name(G_OBJECT(embed), "kz-open-uri", uri, &ret);

	if (parent_class->open_uri)
		ret = parent_class->open_uri(embed, uri);

#if 0
	if (!strncmp(uri, "mailto:", 7))
	{
		return TRUE;
	}
#endif

	return ret;
}

static void
kz_moz_embed_size_to (GtkMozEmbed *embed, gint width, gint height)
{
	gtk_widget_set_size_request(GTK_WIDGET(embed), width, height);
	gtk_widget_queue_resize(GTK_WIDGET(embed));

	g_signal_emit_by_name(G_OBJECT(embed), "kz-size-to", width, height);
}

static gint
kz_moz_embed_dom_key_down (GtkMozEmbed *embed, gpointer event)
{
	KzEmbedEventKey *kzevent;
	gint ret = FALSE;

	kz_moz_embed_get_key_event_info(KZ_MOZ_EMBED(embed), event, &kzevent);
	g_signal_emit_by_name(G_OBJECT(embed), "kz-dom-key-down",
			      kzevent, &ret);
	kz_embed_event_free((KzEmbedEvent *) kzevent);

	return ret;
}

static gint
kz_moz_embed_dom_key_up (GtkMozEmbed *embed, gpointer event)
{
	KzEmbedEventKey *kzevent;
	gint ret = FALSE;

	kz_moz_embed_get_key_event_info(KZ_MOZ_EMBED(embed), event, &kzevent);
	g_signal_emit_by_name(G_OBJECT(embed), "kz-dom-key-up",
			      kzevent, &ret);
	kz_embed_event_free((KzEmbedEvent *) kzevent);

	return ret;
}

static gint
kz_moz_embed_dom_key_press (GtkMozEmbed *embed, gpointer event)
{
	KzEmbedEventKey *kzevent;
	gint ret = FALSE;

	kz_moz_embed_get_key_event_info(KZ_MOZ_EMBED(embed), event, &kzevent);
	g_signal_emit_by_name(G_OBJECT(embed), "kz-dom-key-press",
			      kzevent, &ret);
	kz_embed_event_free((KzEmbedEvent *) kzevent);

	return ret;
}

static gint
kz_moz_embed_dom_mouse_down (GtkMozEmbed *embed, gpointer event)
{
	KzEmbedEventMouse *kzevent;
	gint ret = FALSE;

	kz_moz_embed_get_mouse_event_info(KZ_MOZ_EMBED(embed), event, &kzevent);
	g_signal_emit_by_name(G_OBJECT(embed), "kz-dom-mouse-down",
			      kzevent, &ret);
	kz_embed_event_free((KzEmbedEvent *) kzevent);

	return ret;
}

static
gint kz_moz_embed_dom_mouse_up (GtkMozEmbed *embed, gpointer event)
{
	KzEmbedEventMouse *kzevent;
	gint ret = FALSE;

	kz_moz_embed_get_mouse_event_info(KZ_MOZ_EMBED(embed), event, &kzevent);
	g_signal_emit_by_name(G_OBJECT(embed), "kz-dom-mouse-up",
			      kzevent, &ret);
	kz_embed_event_free((KzEmbedEvent *) kzevent);

	return ret;
}

static gint
kz_moz_embed_dom_mouse_click (GtkMozEmbed *embed, gpointer event)
{
	KzEmbedEventMouse *kzevent;
	gint ret = FALSE;

	kz_moz_embed_get_mouse_event_info(KZ_MOZ_EMBED(embed), event, &kzevent);
	g_signal_emit_by_name(G_OBJECT(embed), "kz-dom-mouse-click",
			      kzevent, &ret);
	kz_embed_event_free((KzEmbedEvent *) kzevent);

	return ret;
}

static gint
kz_moz_embed_dom_mouse_dbl_click (GtkMozEmbed *embed, gpointer event)
{
	KzEmbedEventMouse *kzevent;
	gint ret = FALSE;

	kz_moz_embed_get_mouse_event_info(KZ_MOZ_EMBED(embed), event, &kzevent);
	g_signal_emit_by_name(G_OBJECT(embed), "kz-dom-mouse-dbl-click",
			      kzevent, &ret);
	kz_embed_event_free((KzEmbedEvent *) kzevent);

	return ret;
}

static void
kz_moz_embed_visibility (GtkMozEmbed *embed, gboolean visibility)
{
	GtkWidget *parent = NULL;

	parent = gtk_widget_get_parent(GTK_WIDGET(embed));
	g_return_if_fail(parent != NULL);
	
	if (visibility) 
	{
		gtk_widget_show(GTK_WIDGET(embed));
		gtk_widget_show(parent);
	}
	else
	{
		gtk_widget_hide(GTK_WIDGET(embed));
		gtk_widget_hide(parent);
	}
}

#if 0
static void
kz_moz_embed_security_change (GtkMozEmbed *embed,
			      gpointer request,
			      guint state)
{
	if (parent_class->security_change)
		parent_class->security_change(embed, request, state);
}
#endif

static gboolean
kz_moz_embed_can_cut_selection (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_MOZ_EMBED(kzembed), FALSE);

	if (!KZ_MOZ_EMBED(kzembed)->priv->wrapper) return TRUE;

	PRBool retval;
	nsresult rv = KZ_MOZ_EMBED(kzembed)->priv->wrapper->CanCutSelection(&retval);

	if (NS_FAILED(rv)) return FALSE;

	return retval;
}

static gboolean
kz_moz_embed_can_copy_selection (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_MOZ_EMBED(kzembed), FALSE);

	if (!KZ_MOZ_EMBED(kzembed)->priv->wrapper) return TRUE;

	PRBool retval;
	nsresult rv = KZ_MOZ_EMBED(kzembed)->priv->wrapper->CanCopySelection(&retval);

	if (NS_FAILED(rv)) return FALSE;

	return retval;
}

static gboolean
kz_moz_embed_can_paste (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_MOZ_EMBED(kzembed), FALSE);

	if (!KZ_MOZ_EMBED(kzembed)->priv->wrapper) return TRUE;

	PRBool retval;
	nsresult rv = KZ_MOZ_EMBED(kzembed)->priv->wrapper->CanPaste(&retval);

	if (NS_FAILED(rv)) return FALSE;

	return retval;
}

static void
kz_moz_embed_cut_selection (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));
	g_return_if_fail(KZ_MOZ_EMBED(kzembed)->priv->wrapper);

	KZ_MOZ_EMBED(kzembed)->priv->wrapper->CutSelection();
}

static void
kz_moz_embed_copy_selection (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));
	g_return_if_fail(KZ_MOZ_EMBED(kzembed)->priv->wrapper);

	KZ_MOZ_EMBED(kzembed)->priv->wrapper->CopySelection();
}

static void
kz_moz_embed_paste (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));
	g_return_if_fail(KZ_MOZ_EMBED(kzembed)->priv->wrapper);

	KZ_MOZ_EMBED(kzembed)->priv->wrapper->Paste();
}

static void
kz_moz_embed_select_all (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));
	g_return_if_fail(KZ_MOZ_EMBED(kzembed)->priv->wrapper);

	KzMozWrapper *wrapper = KZ_MOZ_EMBED(kzembed)->priv->wrapper;

	wrapper->SelectAll();
}

static gchar *
kz_moz_embed_get_selection_string(KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_MOZ_EMBED(kzembed), NULL);

	KzMozEmbed *mozembed = KZ_MOZ_EMBED(kzembed);
	if (!mozembed->priv->wrapper) return NULL;

	nsresult rv;

	nsCOMPtr<nsISelection> selection;
	rv = mozembed->priv->wrapper->GetSelection(getter_AddRefs(selection));
	if (!selection) return NULL;

	PRUnichar *string;
	rv = selection->ToString(&string);
	
	if (NS_FAILED(rv)) return NULL;

	return g_strdup (NS_ConvertUCS2toUTF8(string).get());
}

static gchar *
kz_moz_embed_get_html_with_contents (KzEmbed *kzembed, const gchar *storedir)
{
	g_return_val_if_fail(KZ_IS_MOZ_EMBED(kzembed), NULL);

	KzMozEmbed *mozembed = KZ_MOZ_EMBED(kzembed);
	if (!mozembed->priv->wrapper) return NULL;

	nsresult rv;

	nsCOMPtr<nsISelection> selection;
	rv = mozembed->priv->wrapper->GetSelection(getter_AddRefs(selection));
	if (!selection) return NULL;

	nsAutoString string;
	rv = mozembed->priv->wrapper->GetHtmlWithContents(selection, 
							  storedir,
							  string);
	if (NS_FAILED(rv)) return NULL;

	return g_strdup(NS_ConvertUCS2toUTF8(string).get());
}
#if 0
static gchar *
kz_moz_embed_get_selection_source(KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_MOZ_EMBED(kzembed), NULL);

	KzMozEmbed *mozembed = KZ_MOZ_EMBED(kzembed);
	if (!mozembed->priv->wrapper) return NULL;

	nsresult rv;

	nsCOMPtr<nsISelection> selection;
	rv = mozembed->priv->wrapper->GetSelection(getter_AddRefs(selection));
	if (!selection) return NULL;

	nsAutoString string;
	rv = mozembed->priv->wrapper->GetSelectionSource(selection, PR_TRUE, string);
	if (NS_FAILED(rv)) return NULL;

	return g_strdup(NS_ConvertUCS2toUTF8(string).get());
}
#endif

static gboolean
kz_moz_embed_find (KzEmbed *kzembed, const char *keyword,
		   gboolean backward)
{
	g_return_val_if_fail(KZ_IS_MOZ_EMBED(kzembed), FALSE);
	g_return_val_if_fail(keyword, FALSE);

	nsCOMPtr<nsIWebBrowser> web;
	gtk_moz_embed_get_nsIWebBrowser(GTK_MOZ_EMBED(kzembed),
					getter_AddRefs(web));
	if (!web) return FALSE;

	nsresult rv;
	nsCOMPtr<nsIWebBrowserFind> finder(do_GetInterface(web));
#if USE_MIGEMO
	KzMozEmbed *mozembed = KZ_MOZ_EMBED(kzembed);
	gboolean use_migemo;
	KZ_CONF_GET("Global", "use_migemo", use_migemo, BOOL);

	if (use_migemo)
	{
		nsAutoString text;
		gchar *body_string;

		rv = mozembed->priv->wrapper->GetStringSelection(text, backward);
		if (NS_FAILED(rv))
			goto START_SEARCH;
		body_string = g_strdup(NS_ConvertUCS2toUTF8(text).get());

		if (mozembed->priv->migemo_keyword)
			g_free(mozembed->priv->migemo_keyword);
		mozembed->priv->migemo_keyword =
			migemo_get_matched_text(body_string, keyword);
		
		if (mozembed->priv->migemo_keyword)
		{
			finder->SetSearchString(NS_ConvertUTF8toUCS2(mozembed->priv->migemo_keyword).get());
		}
		else
		{
			finder->SetSearchString(NS_ConvertUTF8toUCS2(keyword).get());
		}
		g_free(body_string);
	}
	else
	{
		finder->SetSearchString(NS_ConvertUTF8toUCS2(keyword).get());
	}
START_SEARCH:
#else
	finder->SetSearchString(NS_ConvertUTF8toUCS2(keyword).get());
#endif
	finder->SetFindBackwards(backward);
	finder->SetWrapFind(TRUE);
	finder->SetEntireWord(TRUE);
	finder->SetSearchFrames(TRUE);
	finder->SetMatchCase(FALSE);
	PRBool did_find;
	rv = finder->FindNext(&did_find);

	return NS_SUCCEEDED(rv) && did_find ? TRUE : FALSE;
}

static gboolean
kz_moz_embed_incremental_search (KzEmbed *kzembed, const char *keyword,
				 gboolean backward)
{
	nsresult rv;
	g_return_val_if_fail(KZ_IS_MOZ_EMBED(kzembed), FALSE);
	g_return_val_if_fail(keyword, FALSE);

	if (strlen(keyword) == 0)
		return FALSE;

	nsCOMPtr<nsIWebBrowser> web;
	gtk_moz_embed_get_nsIWebBrowser(GTK_MOZ_EMBED(kzembed),
					getter_AddRefs(web));
	if (!web) return FALSE;

	nsCOMPtr<nsIWebBrowserFind> finder(do_GetInterface(web));
#if USE_MIGEMO
	KzMozEmbed *mozembed = KZ_MOZ_EMBED(kzembed);
	gboolean use_migemo;
	KZ_CONF_GET("Global", "use_migemo", use_migemo, BOOL);

	nsCOMPtr<nsISelection> selection;
	rv = mozembed->priv->wrapper->GetSelection(getter_AddRefs(selection));
	if (!selection) return FALSE;

	selection->RemoveAllRanges();

	if (use_migemo)
	{
		nsAutoString text;
		gchar *body_string;

		rv = mozembed->priv->wrapper->GetBodyString(text);
		if (NS_FAILED(rv))
			goto START_SEARCH;
		body_string = g_strdup(NS_ConvertUCS2toUTF8(text).get());

		if (mozembed->priv->migemo_keyword)
			g_free(mozembed->priv->migemo_keyword);
		mozembed->priv->migemo_keyword =
			migemo_get_matched_text(body_string, keyword);

		if (mozembed->priv->migemo_keyword) 
		{
			finder->SetSearchString(NS_ConvertUTF8toUCS2(mozembed->priv->migemo_keyword).get());
		}
		else 
		{
			finder->SetSearchString(NS_ConvertUTF8toUCS2(keyword).get());
		}
		g_free(body_string);
	}
	else
	{
		finder->SetSearchString(NS_ConvertUTF8toUCS2(keyword).get());
	}
START_SEARCH:
#else
	finder->SetSearchString(NS_ConvertUTF8toUCS2(keyword).get());
#endif
	finder->SetFindBackwards(backward);
	finder->SetWrapFind(TRUE);
	finder->SetEntireWord(TRUE);
	finder->SetSearchFrames(TRUE);
	finder->SetMatchCase(FALSE);
	PRBool did_find;
	rv = finder->FindNext(&did_find);

	return NS_SUCCEEDED(rv) && did_find ? TRUE : FALSE;
}

static gboolean
kz_moz_embed_selection_is_collapsed (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_MOZ_EMBED(kzembed), TRUE);

	KzMozEmbed *mozembed = KZ_MOZ_EMBED(kzembed);
	if (!mozembed->priv->wrapper) return TRUE;

	nsresult rv;

	nsCOMPtr<nsISelection> selection;
	rv = mozembed->priv->wrapper->GetSelection(getter_AddRefs(selection));
	if (!selection) return TRUE;

	PRBool collapsed;
	rv = selection->GetIsCollapsed(&collapsed);
	if (NS_FAILED(rv)) return TRUE;

	return collapsed;
}


static gboolean
kz_moz_embed_get_links (KzEmbed *kzembed, GList **list,
			gboolean selected_only)
{
	g_return_val_if_fail(KZ_IS_MOZ_EMBED(kzembed), FALSE);
	KzMozEmbed *mozembed = KZ_MOZ_EMBED(kzembed);
	g_return_val_if_fail(mozembed->priv->wrapper, FALSE);
	g_return_val_if_fail(list, FALSE);

	// get selection
	nsresult rv;
	nsCOMPtr<nsISelection> selection;
	rv = mozembed->priv->wrapper->GetSelection(getter_AddRefs(selection));
	if (NS_FAILED(rv)) return FALSE;

	// get all anchor nodes in the document.
	nsCOMPtr<nsIDOMDocument> mainDoc;
        rv = mozembed->priv->wrapper->GetMainDomDocument(getter_AddRefs(mainDoc));
        if (NS_FAILED(rv) || !mainDoc) return FALSE;

        // get main DOMWindow
	nsCOMPtr<nsIDOMWindow> mainDOMWindow;
	rv = mozembed->priv->wrapper->GetDOMWindow(getter_AddRefs(mainDOMWindow));
	if (NS_FAILED(rv)) return FALSE;

	rv = mozembed->priv->wrapper->GetLinksFromWindow(mainDOMWindow,
							 list,
							 selection,
							 selected_only);

	return NS_FAILED(rv) ? FALSE : TRUE;
}


glong
kz_moz_embed_get_key_event_info(KzMozEmbed *kzembed, gpointer event,
				KzEmbedEventKey **info_ret)
{
	KzEmbedEventKey *info;
	info = (KzEmbedEventKey *) kz_embed_event_new(KZ_EMBED_EVENT_KEY);
	*info_ret = info;

	nsresult result;

	nsIDOMKeyEvent *aKeyEvent = (nsIDOMKeyEvent*) event;

     	nsCOMPtr<nsIDOMEventTarget> OriginalTarget;

     	nsCOMPtr<nsIDOMNSEvent> aEvent = do_QueryInterface(aKeyEvent);
     	if (!aEvent) return KZ_CONTEXT_NONE;

	PRUint32 code;
	aKeyEvent->GetKeyCode(&code);
	code = info->key;

	aKeyEvent->GetCharCode(&code);
	code = info->char_code;

	PRBool mod_key;
	info->modifier = 0;
	aKeyEvent->GetAltKey(&mod_key);
        if (mod_key) info->modifier |= KZ_ALT_KEY;

	aKeyEvent->GetShiftKey(&mod_key);
        if (mod_key) info->modifier |= KZ_SHIFT_KEY;

	aKeyEvent->GetMetaKey(&mod_key);
        if (mod_key) info->modifier |= KZ_META_KEY;

	aKeyEvent->GetCtrlKey(&mod_key);
        if (mod_key) info->modifier |= KZ_CTRL_KEY;

     	result = aEvent->GetOriginalTarget(getter_AddRefs(OriginalTarget));

     	if (NS_FAILED(result) || !OriginalTarget) return KZ_CONTEXT_NONE;

     	nsCOMPtr<nsIDOMNode> OriginalNode = do_QueryInterface(OriginalTarget);
     	if (!OriginalNode) return KZ_CONTEXT_NONE;

     	nsString nodename;
     	OriginalNode->GetNodeName(nodename);

     	if (nodename.EqualsIgnoreCase("xul:thumb") ||
	    nodename.EqualsIgnoreCase("xul:slider"))
	{
       		return KZ_CONTEXT_NONE;
	}

     	nsCOMPtr<nsIDOMEventTarget> target;
     	result = aKeyEvent->GetTarget(getter_AddRefs(target));
     	if (NS_FAILED(result) || !target) return KZ_CONTEXT_NONE;

	return mozilla_set_event_context(kzembed, target, (KzEmbedEvent *) info);
}


glong
kz_moz_embed_get_mouse_event_info(KzMozEmbed *kzembed, gpointer event,
				  KzEmbedEventMouse **info_ret)
{
	KzEmbedEventMouse *info;
	info = (KzEmbedEventMouse *) kz_embed_event_new(KZ_EMBED_EVENT_MOUSE);
	*info_ret = info;

	nsresult result;

	nsIDOMMouseEvent *aMouseEvent = (nsIDOMMouseEvent*)event;

     	nsCOMPtr<nsIDOMEventTarget> OriginalTarget;

     	nsCOMPtr<nsIDOMNSEvent> aEvent = do_QueryInterface(aMouseEvent);
     	if (!aEvent) return KZ_CONTEXT_NONE;

	PRUint16 button;
	aMouseEvent->GetButton(&button);
	info->button = button;

	PRBool mod_key;
	info->modifier = 0;
	aMouseEvent->GetAltKey(&mod_key);
        if (mod_key) info->modifier |= KZ_ALT_KEY;

	aMouseEvent->GetShiftKey(&mod_key);
        if (mod_key) info->modifier |= KZ_SHIFT_KEY;

	aMouseEvent->GetMetaKey(&mod_key);
        if (mod_key) info->modifier |= KZ_META_KEY;

	aMouseEvent->GetCtrlKey(&mod_key);
        if (mod_key) info->modifier |= KZ_CTRL_KEY;

	PRInt32 pos;
	aMouseEvent->GetClientX(&pos);
	info->x = pos;
	aMouseEvent->GetClientY(&pos);
	info->y = pos;

     	result = aEvent->GetOriginalTarget(getter_AddRefs(OriginalTarget));

     	if (NS_FAILED(result) || !OriginalTarget) return KZ_CONTEXT_NONE;

     	nsCOMPtr<nsIDOMNode> OriginalNode = do_QueryInterface(OriginalTarget);
     	if (!OriginalNode) return KZ_CONTEXT_NONE;

     	nsString nodename;
     	OriginalNode->GetNodeName(nodename);

     	if (nodename.EqualsIgnoreCase("xul:thumb") ||
	    nodename.EqualsIgnoreCase("xul:slider"))
	{
       		return KZ_CONTEXT_NONE;
	}

     	nsCOMPtr<nsIDOMEventTarget> target;
     	result = aMouseEvent->GetTarget(getter_AddRefs(target));
     	if (NS_FAILED(result) || !target) return KZ_CONTEXT_NONE;

	return mozilla_set_event_context(kzembed, target, (KzEmbedEvent *) info);
}


static glong
mozilla_set_event_context (KzMozEmbed *kzembed,
			   nsIDOMEventTarget *target,
			   KzEmbedEvent *info)
{
	nsresult result;
	KzMozWrapper *wrapper = kzembed->priv->wrapper;
	g_return_val_if_fail(kzembed->priv->wrapper, KZ_CONTEXT_NONE);

	nsCOMPtr<nsIDOMNode> node = do_QueryInterface(target);
	if (!node) return KZ_CONTEXT_NONE;

     	nsCOMPtr<nsIDOMDocument> domDoc;
     	result = node->GetOwnerDocument(getter_AddRefs(domDoc));
     	if (!NS_SUCCEEDED (result) || !domDoc) return KZ_CONTEXT_NONE;

     	nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
     	if(!doc) return KZ_CONTEXT_NONE;

     	nsCOMPtr<nsIDOMNSDocument> nsDoc = do_QueryInterface(domDoc);
     	if (!nsDoc) return KZ_CONTEXT_NONE;

	nsIURI *baseURI;
#if MOZILLA_SNAPSHOT > 12
	baseURI = doc->GetBaseURI();
#elif MOZILLA_SNAPSHOT > 11
	baseURI = doc->GetBaseURL();
#elif MOZILLA_SNAPSHOT > 9
	result = doc->GetBaseURL(&baseURI);
#else
	result = doc->GetBaseURL(baseURI);
#endif
	if (NS_FAILED(result) || !baseURI) return KZ_CONTEXT_NONE;

     	nsString mime;
     	nsDoc->GetContentType(mime);
     	if (mime.EqualsIgnoreCase("text/xul"))  return KZ_CONTEXT_NONE;

	PRUint32 flags = KZ_CONTEXT_NONE;

	// check framed page
	nsCOMPtr<nsIDOMDocument> mainDocument;
	result = kzembed->priv->wrapper->GetMainDomDocument (getter_AddRefs(mainDocument));
	if (domDoc != mainDocument)
	{
		flags |= KZ_CONTEXT_FRAME;
		nsCAutoString url;
		baseURI->GetSpec(url);		
		info->frame_src = g_strdup(url.get());
	}
	
	// check whether the node is in the selection or not
	nsCOMPtr<nsISelection> selection;
	result = kzembed->priv->wrapper->GetSelection(getter_AddRefs(selection));
	if (selection)
	{
		PRBool contains;
		selection->ContainsNode(node, PR_TRUE, &contains);
		if (contains)
			flags |= KZ_CONTEXT_SELECTION;
	}

	// Get other context
	nsCOMPtr<nsIDOMHTMLElement> element;

     	do {
		PRUint16 type;
		node->GetNodeType(&type);

		element = do_QueryInterface(node);
		if (element)
		{
			nsAutoString tag;
			gchar *utf8_tag;
			element->GetTagName(tag);
			utf8_tag = g_strdup(NS_ConvertUCS2toUTF8(tag).get());

			if (!g_ascii_strcasecmp(utf8_tag, "input"))
			{
				flags |= KZ_CONTEXT_INPUT;
			}
			else if (!g_ascii_strcasecmp(utf8_tag, "textarea"))
			{
				flags |= KZ_CONTEXT_INPUT | KZ_CONTEXT_TEXTAREA;
				info->element = (void*)element;
			}
			else if (!g_ascii_strcasecmp(utf8_tag, "img"))
			{
				flags |= KZ_CONTEXT_IMAGE;

				char *src = NULL;
				wrapper->GetAttributeFromNode(node, NS_LITERAL_STRING("src"), &src);
				if (!src)  return KZ_CONTEXT_NONE;

			     	nsAutoString srca;
			     	srca.AssignWithConversion(src);

			     	nsCString srcc,imgc;
			     	srcc.AssignWithConversion(srca);

			     	result = baseURI->Resolve(srcc, imgc);
			     	g_free(src);

			     	info->img = ToNewCString(imgc);

			     	if (!info->img) return KZ_CONTEXT_NONE;
			}
			else
			{
				flags |= KZ_CONTEXT_OTHER;
			}
			g_free(utf8_tag);

			nsCOMPtr<nsIDOMNamedNodeMap> attributes;
			node->GetAttributes(getter_AddRefs(attributes));
			if (attributes)
			{
				nsCOMPtr<nsIDOMNode> hrefNode;
				attributes->GetNamedItem(NS_LITERAL_STRING("href"), getter_AddRefs(hrefNode));
				if (hrefNode)
				{
					flags |= KZ_CONTEXT_LINK;

					wrapper->GetLinkAndTitleFromNode(domDoc,
								 node,
								 &info->link,
								 &info->linktext);
					if (!info->link)
					{
						g_free(info->linktext);
						return KZ_CONTEXT_NONE;
					}
					break;
				}
			}
		}

		nsCOMPtr<nsIDOMNode> parentNode;
		node->GetParentNode(getter_AddRefs(parentNode));

		if (!parentNode)
		{
			node = nsnull;
			flags |= KZ_CONTEXT_DOCUMENT;
			break;
		}
		node = parentNode;
	} while (node);

	info->context = flags;

	return flags;
}

static gchar *
kz_moz_embed_get_up_location(KzMozEmbed *kzembed)
{
	const gchar *location;
	gchar *up_location = NULL;
	gchar *pos, *dummy;
	int len; 

	location = kz_moz_embed_get_location(KZ_EMBED(kzembed));
	if (!location)
		return NULL;

	len = strlen(location);
	if (location[len - 1] == '/')
		dummy = g_strndup(location, len - 1);
	else 
		dummy = g_strndup(location, len);
	pos =  strrchr(dummy, '/');
	if (pos)
		up_location = g_strndup(dummy, pos - dummy + 1);
	g_free(dummy);
	return up_location;
}

static void
kz_moz_embed_reload (KzEmbed *kzembed, gint32 flags)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));
	gtk_moz_embed_reload(GTK_MOZ_EMBED(kzembed), flags);
}


static void
kz_moz_embed_stop_load (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));
	gtk_moz_embed_stop_load(GTK_MOZ_EMBED(kzembed));
}


static void
kz_moz_embed_go_back (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));
	gtk_moz_embed_go_back(GTK_MOZ_EMBED(kzembed));
}


static void
kz_moz_embed_go_up (KzEmbed *kzembed)
{
	gchar *location;
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));

	location = kz_moz_embed_get_up_location(KZ_MOZ_EMBED(kzembed));
	kz_moz_embed_load_url(kzembed, location);
	g_free(location);
}

static void
kz_moz_embed_go_forward (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));
	gtk_moz_embed_go_forward(GTK_MOZ_EMBED(kzembed));
}


static gboolean
kz_moz_embed_can_go_back (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_MOZ_EMBED(kzembed), FALSE);
	return gtk_moz_embed_can_go_back(GTK_MOZ_EMBED(kzembed));
}

static gboolean
kz_moz_embed_can_go_forward (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_MOZ_EMBED(kzembed), FALSE);
	return gtk_moz_embed_can_go_forward(GTK_MOZ_EMBED(kzembed));
}

static gboolean
kz_moz_embed_can_go_up (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_MOZ_EMBED(kzembed), FALSE);

	gboolean ret;
	gchar *location;

	location = kz_moz_embed_get_up_location(KZ_MOZ_EMBED(kzembed));

	if (!location)
		return FALSE;

	/* stupid! */
	if (strcmp(location, "http://") &&
	    strcmp(location, "ftp://")  &&
	    strcmp(location, "file://"))
		ret = TRUE;
	else
		ret = FALSE;
	g_free(location);

	return ret;
}

static gboolean
kz_moz_embed_can_go_nav_link (KzEmbed *kzembed,
			      KzEmbedNavLink link)
{
	g_return_val_if_fail(KZ_IS_MOZ_EMBED(kzembed), FALSE);

	return (KZ_MOZ_EMBED(kzembed)->priv->nav_links[link]) ? TRUE : FALSE;
}

static void
kz_moz_embed_go_nav_link (KzEmbed *kzembed,
			  KzEmbedNavLink link)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));
	g_return_if_fail(KZ_MOZ_EMBED(kzembed)->priv->nav_links[link]);

	kz_moz_embed_load_url(kzembed,
			      KZ_MOZ_EMBED(kzembed)->priv->nav_links[link]);
}

static void
kz_moz_embed_set_nav_link (KzEmbed *kzembed,
			   const gchar *name,
			   const gchar *link)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));
	g_return_if_fail(name);
	g_return_if_fail(link);

	KzMozEmbed *mozembed = KZ_MOZ_EMBED(kzembed);
	
	for (int j = 0; j < N_LINKS; j++)
	{
		if (!strcasecmp(name, nav_names[j]))
		{
			if (mozembed->priv->nav_links[j])
				g_free(mozembed->priv->nav_links[j]);
			mozembed->priv->nav_links[j] = g_strdup(link);
			break;
		}
	}
}


static void
kz_moz_embed_go_history_index (KzEmbed *kzembed, gint index)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));
	
	KzMozWrapper *wrapper = KZ_MOZ_EMBED(kzembed)->priv->wrapper;
	g_return_if_fail(wrapper);
	
	wrapper->GoHistoryIndex(index);
}

static void
kz_moz_embed_copy_page (KzEmbed *kzembed, KzEmbed *dkzembed)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));
	g_return_if_fail(KZ_IS_MOZ_EMBED(dkzembed));

	KzMozWrapper *dWrapper = KZ_MOZ_EMBED(dkzembed)->priv->wrapper;;
	KzMozWrapper *sWrapper = KZ_MOZ_EMBED(kzembed)->priv->wrapper;;

        nsresult rv;

        nsCOMPtr<nsISupports> pageDescriptor;
        rv = sWrapper->GetPageDescriptor(getter_AddRefs(pageDescriptor));
        if (!pageDescriptor || NS_FAILED(rv)) return;

        rv = dWrapper->LoadDocument(pageDescriptor, 
				    nsIWebPageDescriptor::DISPLAY_NORMAL);
}


static gboolean
kz_moz_embed_shistory_copy (KzEmbed *source,
			    KzEmbed *dest,
			    gboolean back_history,
			    gboolean forward_history,
			    gboolean set_current)
{
	g_return_val_if_fail(KZ_IS_MOZ_EMBED(source), FALSE);
	g_return_val_if_fail(KZ_IS_MOZ_EMBED(dest), FALSE);

	nsresult rv;
	KzMozWrapper *s_wrapper = KZ_MOZ_EMBED(source)->priv->wrapper;
	KzMozWrapper *d_wrapper = KZ_MOZ_EMBED(dest)->priv->wrapper;
	
	rv = s_wrapper->CopyHistoryTo (d_wrapper, back_history, forward_history, set_current);

	return NS_SUCCEEDED(rv) ? TRUE : FALSE;
}


/* picked from galeon-1.3.11a */
static gboolean
kz_moz_embed_shistory_get_pos (KzEmbed *kzembed,
			       int *pos, int *count)
{
	g_return_val_if_fail(KZ_IS_MOZ_EMBED(kzembed), FALSE);

	KzMozWrapper *wrapper = KZ_MOZ_EMBED(kzembed)->priv->wrapper;
	nsresult rv;
	int total, index;

	rv = wrapper->GetSHInfo (&total, &index);

	*pos = index;
	*count = total;

	return NS_SUCCEEDED(rv) ? TRUE : FALSE;
}

/* picked from galeon-1.3.11a */
static void
kz_moz_embed_shistory_get_nth (KzEmbed *kzembed, 
			       int nth,
			       gboolean is_relative,
			       char **aUrl,
			       char **aTitle)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));

	KzMozEmbed *mozembed = KZ_MOZ_EMBED(kzembed);
	KzMozWrapper *wrapper = mozembed->priv->wrapper;
	nsresult rv;

	if (is_relative)
	{
		int pos, count;
		if(kz_moz_embed_shistory_get_pos(kzembed, &pos, &count))
			pos += nth;
		else
			return;
		nth = pos;
	}
	
        nsCAutoString url;
        rv = wrapper->GetSHUrlAtIndex(nth, url);
        *aUrl = (NS_SUCCEEDED (rv) && !url.IsEmpty()) ? g_strdup(url.get()) : NULL;

	PRUnichar *title;
	rv = wrapper->GetSHTitleAtIndex(nth, &title);
	*aTitle = g_strdup (NS_ConvertUCS2toUTF8(title).get());
	nsMemory::Free(title);
}


static gboolean
kz_moz_embed_get_lock (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_MOZ_EMBED(kzembed), FALSE);
	return KZ_MOZ_EMBED(kzembed)->priv->lock;
}


static void
kz_moz_embed_set_lock (KzEmbed *kzembed, gboolean lock)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));
	KZ_MOZ_EMBED(kzembed)->priv->lock = lock;
}


static gchar *
kz_moz_embed_get_body_text(KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_MOZ_EMBED(kzembed), FALSE);
	g_return_val_if_fail(KZ_MOZ_EMBED(kzembed)->priv->wrapper, FALSE);

	nsAutoString text;
	KZ_MOZ_EMBED(kzembed)->priv->wrapper->GetBodyString(text);
	return g_strdup(NS_ConvertUCS2toUTF8(text).get());
}


static void
kz_moz_embed_set_encoding (KzEmbed *kzembed, const char *encoding)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));
	g_return_if_fail(KZ_MOZ_EMBED(kzembed)->priv->wrapper);

	KZ_MOZ_EMBED(kzembed)->priv->wrapper->ForceEncoding(encoding);
}

static void
kz_moz_embed_get_encoding (KzEmbed *kzembed, char **encoding, gboolean *forced)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));
	g_return_if_fail(KZ_MOZ_EMBED(kzembed)->priv->wrapper);

	KZ_MOZ_EMBED(kzembed)->priv->wrapper->GetEncoding(encoding, *forced);
}

static gboolean 
kz_moz_embed_save_with_content (KzEmbed *kzembed, const char *rawfilename)
{
	nsresult rv;
	KzMozWrapper *wrapper = NULL;
	PRUint32 persistFlags = 0;

	nsCOMPtr<nsIWebBrowserPersist> bpersist = 
		do_CreateInstance(NS_WEBBROWSERPERSIST_CONTRACTID);
	if (!bpersist) return FALSE;

	nsCOMPtr<nsIURI> linkURI;
	linkURI = nsnull;

	nsCAutoString filename(rawfilename);
        nsCOMPtr<nsILocalFile> file;
       	NS_NewNativeLocalFile(filename, PR_TRUE, getter_AddRefs(file)); 
        if (!file) return FALSE;

	nsCOMPtr<nsILocalFile> path;
	char *datapath;
	datapath = g_strconcat (rawfilename, ".content", NULL);
	NS_NewLocalFile(NS_ConvertUTF8toUCS2(datapath), PR_TRUE, getter_AddRefs(path));
	g_free (datapath);

	wrapper = KZ_MOZ_EMBED(kzembed)->priv->wrapper;
	g_return_val_if_fail (wrapper != NULL, FALSE);	

	persistFlags = nsIWebBrowserPersist::PERSIST_FLAGS_REPLACE_EXISTING_FILES;

	size_t len = strlen(rawfilename);
	if((rawfilename[len-1] == 'z' && rawfilename[len-2] == 'g') ||
	   (rawfilename[len-1] == 'Z' && rawfilename[len-2] == 'G'))
	{
                persistFlags |= nsIWebBrowserPersist::PERSIST_FLAGS_NO_CONVERSION;
	}

	persistFlags |= nsIWebBrowserPersist::PERSIST_FLAGS_BYPASS_CACHE;
	bpersist->SetPersistFlags (persistFlags);

	g_return_val_if_fail (wrapper != NULL, FALSE);

	nsCOMPtr<nsIDOMDocument> DOMDocument;

	rv = wrapper->GetMainDomDocument (getter_AddRefs(DOMDocument));
	if (NS_FAILED(rv) || !DOMDocument) return FALSE;

	nsCOMPtr<nsIDocument> document =
		do_QueryInterface (DOMDocument, &rv);
	if (NS_FAILED(rv) || !document) return FALSE;

	nsCOMPtr<nsIURI> inURI;
	nsCAutoString sURI;

	rv = wrapper->GetDocumentUrl(sURI);
      	rv = NS_NewURI(getter_AddRefs(inURI), sURI);

	// FIXME! Use ProgressListener. 
	// KzMozProgressListener *aProgress = new KzMozProgressListener ();
	// aProgress->Init(inURI, path, 
	//		nsnull, nsnull, 0, bpersist);

	rv = bpersist->SaveDocument (DOMDocument, file, path, nsnull, 0, 0);
	if (NS_FAILED(rv)) return FALSE;

	return TRUE;
}


static void
kz_moz_embed_print (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));

	KzMozWrapper *wrapper = KZ_MOZ_EMBED(kzembed)->priv->wrapper;
	g_return_if_fail (wrapper != NULL);

	wrapper->Print();
}


static void
kz_moz_embed_print_preview (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));

	KzMozWrapper *wrapper = KZ_MOZ_EMBED(kzembed)->priv->wrapper;
	g_return_if_fail (wrapper != NULL);
	
	wrapper->PrintPreview();
}


static gchar *
kz_moz_embed_get_text_from_textarea (KzEmbed *kzembed,
				     gpointer element)
{
	g_return_val_if_fail(KZ_IS_MOZ_EMBED(kzembed), NULL);

	nsIDOMHTMLElement *htmlElement = (nsIDOMHTMLElement*)element;

	nsCOMPtr<nsIDOMHTMLTextAreaElement> tElement = do_QueryInterface(htmlElement);

	g_return_val_if_fail(tElement, NULL);

	nsAutoString string;
	tElement->GetValue(string);

	return g_strdup(NS_ConvertUCS2toUTF8(string).get());
}


static gboolean
kz_moz_embed_set_text_into_textarea (KzEmbed *kzembed,
				     gpointer element,
				     const gchar *text)
{
	g_return_val_if_fail(KZ_IS_MOZ_EMBED(kzembed), FALSE);

	nsIDOMHTMLElement *htmlElement = (nsIDOMHTMLElement*)element;

	nsCOMPtr<nsIDOMHTMLTextAreaElement> tElement = do_QueryInterface(htmlElement);

	if (!tElement) return FALSE;

	nsAutoString string = NS_ConvertUTF8toUCS2(text);
	tElement->SetValue(string);

	return TRUE;
}


static gchar *
mozilla_store_history_file(KzMozEmbed *kzembed)
{
	nsresult rv;

	g_return_val_if_fail(KZ_IS_MOZ_EMBED(kzembed), NULL);

	KzMozWrapper *wrapper = kzembed->priv->wrapper;
	g_return_val_if_fail (wrapper != NULL, NULL);

	PRUint32 persistFlags = 0;
	
	nsCOMPtr<nsIWebBrowserPersist> bpersist = 
		do_CreateInstance(NS_WEBBROWSERPERSIST_CONTRACTID);
	if (!bpersist) return NULL;

	persistFlags = nsIWebBrowserPersist::PERSIST_FLAGS_REPLACE_EXISTING_FILES;

	persistFlags |= nsIWebBrowserPersist::PERSIST_FLAGS_FROM_CACHE;
	bpersist->SetPersistFlags (persistFlags);

	nsCOMPtr<nsIURI> inURI;
	nsCAutoString sURI;

	rv = wrapper->GetDocumentUrl(sURI);
      	rv = NS_NewURI(getter_AddRefs(inURI), sURI);

	gchar *dir, *filename;
	gchar *uri = ToNewCString(sURI);

	filename = create_filename_with_path_from_uri(uri);
		
	dir = g_build_filename(g_get_home_dir(),
			       HISTORY_DIR,
			       filename,
			       NULL);
	g_free(filename);
	g_free(uri);

	nsCOMPtr<nsILocalFile> localFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
	rv = localFile->InitWithPath(NS_ConvertUTF8toUCS2(dir));

	if (NS_FAILED(rv))
		return NULL;

	PRBool exists;
	localFile->Exists(&exists);
	if (!exists)
	{
		rv = localFile->Create(nsIFile::NORMAL_FILE_TYPE, 0600);
		if (NS_FAILED(rv))
			return NULL;
	}

	nsCOMPtr<nsISupports> pageDescriptor;

	wrapper->GetPageDescriptor(getter_AddRefs(pageDescriptor));
	
	rv = bpersist->SaveURI (inURI, pageDescriptor, nsnull,
				nsnull, nsnull, localFile);
	
	return dir;
}


#if 1 /* FIXME! */
static KzMozThumbnailCreator *
kz_window_create_thumbnail_creator (KzWindow *kz)
{
	KzMozThumbnailCreator *creator;

	creator	= KZ_MOZ_THUMBNAIL_CREATOR(g_object_get_data(G_OBJECT(kz),
							     "KzMozEmbed::ThumbnailCreator"));
	if (!creator)
	{
		creator = kz_moz_thumbnail_creator_new();
		gtk_widget_set_size_request(GTK_WIDGET(creator), 0, 0);
		gtk_widget_show(GTK_WIDGET(creator));

		gtk_box_pack_start(GTK_BOX(kz->statusbar_area),
				   GTK_WIDGET(creator),
				   FALSE, FALSE, 0);
		g_object_set_data(G_OBJECT(kz), 
				  "KzMozEmbed::ThumbnailCreator", 
				  creator);
	}

	return creator;
}
#endif /* FIXME! */
static void
kz_moz_embed_create_thumbnail (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));

	KzMozEmbed *mozembed = KZ_MOZ_EMBED(kzembed);
	KzMozWrapper *wrapper = NULL;
	wrapper = mozembed->priv->wrapper;
	g_return_if_fail (wrapper != NULL);

	nsresult rv;
	int total, index;
	rv = wrapper->GetSHInfo (&total, &index);

	nsCOMPtr<nsIHistoryEntry> he;
	rv = wrapper->GetHistoryEntry(index, getter_AddRefs(he));
	if (NS_FAILED(rv)) return;

	GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(kzembed));

	if (!KZ_IS_WINDOW(window)) return;

	KzWindow *kz = KZ_WINDOW(window);

	gboolean create_thumbnail = FALSE;
	KZ_CONF_GET("Global", "create_thumbnail", create_thumbnail, BOOL);
	if (create_thumbnail)
	{
		KzMozThumbnailCreator *creator;
		creator = kz_window_create_thumbnail_creator(kz);
		kz_moz_thumbnail_creator_append_queue(creator, he);
	}
}


void
kz_moz_embed_do_command (KzEmbed *kzembed, const char *command)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));

	KzMozEmbed *mozembed = KZ_MOZ_EMBED(kzembed);
	nsCOMPtr<nsICommandManager> commandManager;
	commandManager = do_GetInterface(mozembed->priv->wrapper->mWebBrowser);
	if (!commandManager) return;
	
	commandManager->DoCommand(command, nsnull, nsnull);

}

static gboolean
kz_moz_embed_can_do_command (KzEmbed *kzembed, const char *command)
{
	g_return_val_if_fail(KZ_IS_MOZ_EMBED(kzembed), FALSE);
	
	KzMozEmbed *mozembed = KZ_MOZ_EMBED(kzembed);
	nsCOMPtr<nsICommandManager> commandManager;
	commandManager = do_GetInterface(mozembed->priv->wrapper->mWebBrowser);
	if (!commandManager) return FALSE;
	
	PRBool enabled;
	commandManager->IsCommandEnabled(command, nsnull, &enabled);

	return (enabled == PR_TRUE);
}

static void
kz_moz_embed_zoom_set (KzEmbed *kzembed, int zoom, gboolean reflow)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));

	KzMozWrapper *wrapper = KZ_MOZ_EMBED(kzembed)->priv->wrapper;

	wrapper->SetImageZoom ((float)(zoom) / 100);
		
	kz_moz_embed_set_text_size(kzembed, zoom, reflow);
}

static int
kz_moz_embed_zoom_get (KzEmbed *kzembed)
{
	return kz_moz_embed_get_text_size(kzembed);
}


static void
kz_moz_embed_set_text_size (KzEmbed *kzembed,  int zoom, gboolean reflow)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));

	KzMozWrapper *wrapper = KZ_MOZ_EMBED(kzembed)->priv->wrapper;

	wrapper->SetZoom ((float)(zoom) / 100, reflow);
}

static int 
kz_moz_embed_get_text_size (KzEmbed *kzembed)
{
	float f;
	int zoom;

	g_return_val_if_fail(KZ_IS_MOZ_EMBED(kzembed), 100);

	KzMozWrapper *wrapper = KZ_MOZ_EMBED(kzembed)->priv->wrapper;

	if (!wrapper) return 100;

	nsresult result = wrapper->GetZoom (&f);
	if (NS_FAILED (result)) return 100;

	zoom = (int) rint (f * 100);

	return zoom;
}

static void
kz_moz_embed_set_history (KzEmbed *kzembed, KzBookmark *history)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));
	g_return_if_fail(KZ_IS_BOOKMARK(history));

	if (!kz_bookmark_is_folder(history)) return;

	KzMozEmbed *mozembed = KZ_MOZ_EMBED(kzembed);
	KzMozWrapper *wrapper = mozembed->priv->wrapper;
	if (!wrapper) return;

	nsCOMPtr<nsISHistory> sHistory;
	nsresult rv = wrapper->GetSHistory(getter_AddRefs(sHistory));
	if (NS_FAILED(rv) || !sHistory) return;

	nsCOMPtr<nsISHistoryInternal> sHistoryInternal;
	sHistoryInternal = do_QueryInterface(sHistory);

	PRInt32 n;
	sHistory->GetCount(&n);
	sHistory->PurgeHistory(n);

	GList *children, *node;
	children = kz_bookmark_get_children(history);
	for (node = children; node; node = g_list_next (node))
	{
		KzBookmark *child = KZ_BOOKMARK(node->data);
		const gchar *title, *uri;

		title = kz_bookmark_get_title(child);
		uri   = kz_bookmark_get_link(child);

		nsCOMPtr<nsISHEntry> entry;
		entry = do_CreateInstance(NS_SHENTRY_CONTRACTID);

		nsCOMPtr<nsIURI> aURI;
		NS_NewURI(getter_AddRefs(aURI), uri, nsnull, nsnull);		
		/* FIXME! set correct contentType */
		nsCAutoString contentType;
		entry->Create(aURI,
			      nsnull,
			      nsnull,
			      nsnull,
			      nsnull,
			      nsnull,
			      nsDependentCString(""));
		sHistoryInternal->AddEntry(entry, PR_TRUE);
	}
	g_list_free(children);

	/* set current */
	gint cur = kz_bookmark_get_current(history);
	kz_moz_embed_go_history_index(kzembed, cur);
}

static void
kz_moz_embed_get_history (KzEmbed *kzembed, KzBookmark *history)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));
	g_return_if_fail(KZ_IS_BOOKMARK(history));

	if (!kz_bookmark_is_folder(history)) return;

	KzMozEmbed *mozembed = KZ_MOZ_EMBED(kzembed);
	KzMozWrapper *wrapper = mozembed->priv->wrapper;
	if (!wrapper) return;

	nsCOMPtr<nsISHistory> sHistory;
	nsresult rv = wrapper->GetSHistory(getter_AddRefs(sHistory));

	if (NS_FAILED(rv) || !sHistory) return;

	GList *children, *tab;
	children = kz_bookmark_get_children(history);
	tab = children;

	PRInt32 count;
	sHistory->GetCount(&count);

	PRInt32 index;
	sHistory->GetIndex(&index);
	for (PRInt32 i = 0; i < count; i++)
	{
		gchar *title, *uri;
		KzBookmark *bookmark = NULL;
		
		kz_moz_embed_shistory_get_nth (kzembed,
					       i, FALSE,
					       &uri,
					       &title);
		if (tab)
		{
			bookmark = KZ_BOOKMARK(tab->data);
			tab = g_list_next(tab);
		}

		/* if there's no children of bookmarks, create a new bookmark */
		if (!bookmark)
		{
			bookmark = kz_bookmark_new_with_attrs(title, uri, NULL);
			kz_bookmark_append(history, bookmark);
			g_object_unref(bookmark);
		}
		else if (!strcmp(uri, kz_bookmark_get_link(bookmark)))
		{
			continue;
		}
		else
		{
			kz_bookmark_set_link(bookmark, uri);
			kz_bookmark_set_title(bookmark, title);
			kz_bookmark_set_last_visited(bookmark, 0);
		}

		if (title)
			g_free(title);
		if (uri)
			g_free(uri);
	}

	if (tab)
		tab = g_list_last(tab);
	GList *prev;

	while (tab)
	{
		KzBookmark *child = KZ_BOOKMARK(tab->data);
		prev = g_list_previous(tab);
		kz_bookmark_remove (history, child);
		tab = prev;
	}

	if (children)
		g_list_free(children);

	kz_bookmark_set_current(history, (gint)index);
}


static guint
kz_moz_embed_get_last_modified (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_MOZ_EMBED(kzembed), 0);

	KzMozEmbed *mozembed = KZ_MOZ_EMBED(kzembed);

	if (!mozembed->priv->wrapper) return 0;

	nsresult result;

	nsCOMPtr<nsIDOMDocument> DOMDocument;

	result = mozembed->priv->wrapper->GetDocument (getter_AddRefs(DOMDocument));
	if (NS_FAILED(result) || !DOMDocument) return 0;

	nsCOMPtr<nsIDOMNSDocument> doc = do_QueryInterface(DOMDocument);
	if(!doc) return 0;
	
	nsAutoString value;

	doc->GetLastModified(value);

	guint mod_time = 0;
	nsTime last_modified (NS_ConvertUCS2toUTF8(value).get(), PR_TRUE);
	LL_DIV (mod_time,
		NS_STATIC_CAST(PRTime, last_modified), PR_USEC_PER_SEC);
	return mod_time;
}


#if 0
static void
kz_moz_embed_set_edit_mode (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));

	KzMozEmbed *mozembed = KZ_MOZ_EMBED(kzembed);

	nsCOMPtr<nsIDOMWindow> domWindow;
	mozembed->priv->wrapper->GetDOMWindow(getter_AddRefs(domWindow));
	
	nsCOMPtr<nsIEditingSession> edit;
	edit = do_GetInterface(mozembed->priv->wrapper->mWebBrowser);
	if (edit)
	{
		edit->MakeWindowEditable(domWindow, "html", PR_FALSE);
	}
}

static void
kz_moz_embed_set_view_mode (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_MOZ_EMBED(kzembed));

	KzMozEmbed *mozembed = KZ_MOZ_EMBED(kzembed);
	
	nsCOMPtr<nsIDOMWindow> domWindow;
	mozembed->priv->wrapper->GetDOMWindow(getter_AddRefs(domWindow));
	
	nsCOMPtr<nsIEditingSession> edit;
	edit = do_GetInterface(mozembed->priv->wrapper->mWebBrowser);
	if (edit)
	{
		edit->TearDownEditorOnWindow(domWindow);
	}
}
#endif

