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

/*
 *  Copyright (C) 2003-2004 Hiroyuki Ikezoe
 *  Copyright (C) 2003-2004 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 copyED 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-embed.h"
#include "kz-module.h"
#include "kz-marshalers.h"
#include <glib/gi18n.h>

static GList *embeds = NULL;
static gboolean loaded = FALSE;

static const gchar *
_kz_embed_module_dir (void)
{
	const gchar *base_dir;
        base_dir = g_getenv("KZ_EMBED_MODULE_DIR");
	if (base_dir)
		return base_dir;
        return KZ_GET_SYSTEM_EMBED_MODULE_DIR;
}

void
kz_embed_load (const gchar *base_dir)
{
	GList *loaded_modules;
	gboolean local_loaded = loaded;

	loaded = TRUE;

	if (!base_dir)
		base_dir = _kz_embed_module_dir();

	if (local_loaded)
		loaded_modules = kz_module_load_modules(base_dir);
	else
		loaded_modules = kz_module_load_modules_unique(base_dir, embeds);

#warning FIXME: workaround for kz-gecko-embed.cpp.
	g_list_foreach(loaded_modules, (GFunc)g_type_module_use, NULL);
	embeds = g_list_concat(loaded_modules, embeds);
}

void
kz_embed_unload (void)
{
	g_list_foreach(embeds, (GFunc)kz_module_unload, NULL);
	g_list_free(embeds);
	embeds = NULL;
}

void
kz_embed_exit (void)
{
#warning FIXME: workaround for kz-gecko-embed.cpp.
	g_list_foreach(embeds, (GFunc)g_type_module_unuse, NULL);
	g_list_foreach(embeds, (GFunc)kz_module_exit, NULL);
}

GList *
kz_embed_engine_names (void)
{
	GList *node;
	GList *result = NULL;

	for (node = embeds; node; node = g_list_next(node))
	{
		KzModule *module = node->data;
		result = g_list_append(result,
				       g_strdup(kz_module_get_name(module)));
	}

	return result;
}

GList *
kz_embed_engine_ids (void)
{
	GList *node;
	GList *result = NULL;

	if (!loaded)
		kz_embed_load(NULL);

	for (node = embeds; node; node = g_list_next(node))
	{
		KzModule *module = node->data;
		result = g_list_append(result,
				       g_strdup(G_TYPE_MODULE(module)->name));
	}

	return result;
}

static GtkWidget *
_kz_embed_new (KzModule *module, const gchar *name,
	       const gchar *first_property, ...)
{
	GObject *embed;
	va_list var_args;

	va_start(var_args, first_property);
	embed = kz_module_instantiate(module, first_property, var_args);
	va_end(var_args);

	return GTK_WIDGET(embed);
}

GtkWidget *
kz_embed_new (const gchar *module_name, const gchar *engine_name)
{
	KzModule *module;

	module = kz_module_find(embeds, module_name);
	if (!module)
	{
		module = kz_module_load_module(_kz_embed_module_dir(), module_name);
		if (!module)
			return NULL;
#warning FIXME: workaround for kz-gecko-embed.cpp.
		g_type_module_use(G_TYPE_MODULE(module));
		embeds = g_list_prepend(embeds, module);
	}

	return _kz_embed_new(module, module_name,
			     "engine-name", engine_name,
			     NULL);
}


enum {
	LINK_MESSAGE_SIGNAL,
	JS_STATUS_SIGNAL,
	LOCATION_SIGNAL,
	TITLE_SIGNAL,
	PROGRESS_SIGNAL,
	NET_START_SIGNAL,
	NET_STOP_SIGNAL,
	NEW_WINDOW_SIGNAL,
	OPEN_URI_SIGNAL,
	SIZE_TO_SIGNAL,
	DOM_KEY_DOWN_SIGNAL,
	DOM_KEY_PRESS_SIGNAL,
	DOM_KEY_UP_SIGNAL,
	DOM_MOUSE_DOWN_SIGNAL,
	DOM_MOUSE_UP_SIGNAL,
	DOM_MOUSE_CLICK_SIGNAL,
	DOM_MOUSE_DBL_CLICK_SIGNAL,
	DOM_MOUSE_OVER_SIGNAL,
	DOM_MOUSE_OUT_SIGNAL,
	SELECTION_SIGNAL,
	LAST_SIGNAL
};

static void kz_embed_base_init (gpointer g_class);
static gint kz_embed_signals[LAST_SIGNAL] = {0};

GType
kz_embed_get_type (void)
{
	static GType type = 0;
	if (!type)
	{
		static const GTypeInfo info = {
			sizeof (KzEmbedIFace),
			kz_embed_base_init, /* base_init :*/
			NULL,               /* base_finalize */
			NULL,               /* class_init */
			NULL,               /* class_finalize */
			NULL,               /* class_data */
			0,
			0,                  /* n_preallocs */
			NULL,               /* instance_init */
		};
		type = g_type_register_static(G_TYPE_INTERFACE, "KzEmbed",
					      &info, 0);
		g_type_interface_add_prerequisite(type,
						  GTK_TYPE_WIDGET);
	}
	return type;
}

static void
kz_embed_base_init (gpointer g_iface)
{
	static gboolean initialized = FALSE;

	if (!initialized)
	{
		initialized = TRUE;

		kz_embed_signals[LINK_MESSAGE_SIGNAL]
			= g_signal_new ("kz-link-message",
					KZ_TYPE_EMBED,
					G_SIGNAL_RUN_FIRST,
					G_STRUCT_OFFSET(KzEmbedIFace, link_message),
					NULL, NULL,
					g_cclosure_marshal_VOID__STRING,
					G_TYPE_NONE, 1,
					G_TYPE_STRING);

		kz_embed_signals[JS_STATUS_SIGNAL]
			= g_signal_new ("kz-js-status",
					KZ_TYPE_EMBED,
					G_SIGNAL_RUN_FIRST,
					G_STRUCT_OFFSET(KzEmbedIFace, js_status),
					NULL, NULL,
					g_cclosure_marshal_VOID__VOID,
					G_TYPE_NONE, 0);

		kz_embed_signals[LOCATION_SIGNAL]
			= g_signal_new ("kz-location",
					KZ_TYPE_EMBED,
					G_SIGNAL_RUN_FIRST,
					G_STRUCT_OFFSET(KzEmbedIFace, location),
					NULL, NULL,
					g_cclosure_marshal_VOID__STRING,
					G_TYPE_NONE, 1,
					G_TYPE_STRING);

		kz_embed_signals[TITLE_SIGNAL]
			= g_signal_new ("kz-title",
					KZ_TYPE_EMBED,
					G_SIGNAL_RUN_FIRST,
					G_STRUCT_OFFSET(KzEmbedIFace, title),
					NULL, NULL,
					g_cclosure_marshal_VOID__STRING,
					G_TYPE_NONE, 1,
					G_TYPE_STRING);

		kz_embed_signals[PROGRESS_SIGNAL]
			= g_signal_new ("kz-progress",
					KZ_TYPE_EMBED,
					G_SIGNAL_RUN_FIRST,
					G_STRUCT_OFFSET(KzEmbedIFace, progress),
					NULL, NULL,
					g_cclosure_marshal_VOID__DOUBLE,
					G_TYPE_NONE, 1,
					G_TYPE_DOUBLE);

		kz_embed_signals[NET_START_SIGNAL]
			= g_signal_new ("kz-net-start",
					KZ_TYPE_EMBED,
					G_SIGNAL_RUN_FIRST,
					G_STRUCT_OFFSET(KzEmbedIFace, net_start),
					NULL, NULL,
					g_cclosure_marshal_VOID__VOID,
					G_TYPE_NONE, 0);

		kz_embed_signals[NET_STOP_SIGNAL]
			= g_signal_new ("kz-net-stop",
					KZ_TYPE_EMBED,
					G_SIGNAL_RUN_FIRST,
					G_STRUCT_OFFSET(KzEmbedIFace, net_stop),
					NULL, NULL,
					g_cclosure_marshal_VOID__VOID,
					G_TYPE_NONE, 0);

		kz_embed_signals[NEW_WINDOW_SIGNAL]
			= g_signal_new ("kz-new-window",
					KZ_TYPE_EMBED,
					G_SIGNAL_RUN_FIRST,
					G_STRUCT_OFFSET(KzEmbedIFace, new_window),
					NULL, NULL,
					g_cclosure_marshal_VOID__POINTER,
					G_TYPE_NONE, 1, G_TYPE_POINTER);

		kz_embed_signals[OPEN_URI_SIGNAL]
			= g_signal_new ("kz-open-uri",
					KZ_TYPE_EMBED,
					G_SIGNAL_RUN_LAST,
					G_STRUCT_OFFSET(KzEmbedIFace, open_uri),
					NULL, NULL,
					_kz_marshal_INT__STRING,
					G_TYPE_INT, 1, G_TYPE_STRING);

		kz_embed_signals[SIZE_TO_SIGNAL]
			= g_signal_new ("kz-size-to",
					KZ_TYPE_EMBED,
					G_SIGNAL_RUN_FIRST,
					G_STRUCT_OFFSET(KzEmbedIFace, size_to),
					NULL, NULL,
					_kz_marshal_VOID__INT_INT,
					G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);

		kz_embed_signals[DOM_KEY_DOWN_SIGNAL]
			= g_signal_new ("kz-dom-key-down",
					KZ_TYPE_EMBED,
					G_SIGNAL_RUN_LAST,
					G_STRUCT_OFFSET(KzEmbedIFace, dom_key_down),
					NULL, NULL,
					_kz_marshal_BOOLEAN__POINTER,
					G_TYPE_BOOLEAN, 1, G_TYPE_POINTER);

		kz_embed_signals[DOM_KEY_PRESS_SIGNAL]
			= g_signal_new ("kz-dom-key-press",
					KZ_TYPE_EMBED,
					G_SIGNAL_RUN_LAST,
					G_STRUCT_OFFSET(KzEmbedIFace, dom_key_press),
					NULL, NULL,
					_kz_marshal_BOOLEAN__POINTER,
					G_TYPE_BOOLEAN, 1, G_TYPE_POINTER);

		kz_embed_signals[DOM_KEY_UP_SIGNAL]
			= g_signal_new ("kz-dom-key-up",
					KZ_TYPE_EMBED,
					G_SIGNAL_RUN_LAST,
					G_STRUCT_OFFSET(KzEmbedIFace, dom_key_up),
					NULL, NULL,
					_kz_marshal_BOOLEAN__POINTER,
					G_TYPE_BOOLEAN, 1, G_TYPE_POINTER);

		kz_embed_signals[DOM_MOUSE_DOWN_SIGNAL]
			= g_signal_new ("kz-dom-mouse-down",
					KZ_TYPE_EMBED,
					G_SIGNAL_RUN_LAST,
					G_STRUCT_OFFSET(KzEmbedIFace, dom_mouse_down),
					NULL, NULL,
					_kz_marshal_BOOLEAN__POINTER,
					G_TYPE_BOOLEAN, 1, G_TYPE_POINTER);

		kz_embed_signals[DOM_MOUSE_UP_SIGNAL]
			= g_signal_new ("kz-dom-mouse-up",
					KZ_TYPE_EMBED,
					G_SIGNAL_RUN_LAST,
					G_STRUCT_OFFSET(KzEmbedIFace, dom_mouse_up),
					NULL, NULL,
					_kz_marshal_BOOLEAN__POINTER,
					G_TYPE_BOOLEAN, 1, G_TYPE_POINTER);

		kz_embed_signals[DOM_MOUSE_CLICK_SIGNAL]
			= g_signal_new ("kz-dom-mouse-click",
					KZ_TYPE_EMBED,
					G_SIGNAL_RUN_LAST,
					G_STRUCT_OFFSET(KzEmbedIFace, dom_mouse_click),
					NULL, NULL,
					_kz_marshal_BOOLEAN__POINTER,
					G_TYPE_BOOLEAN, 1, G_TYPE_POINTER);

		kz_embed_signals[DOM_MOUSE_DBL_CLICK_SIGNAL]
			= g_signal_new ("kz-dom-mouse-dbl-click",
					KZ_TYPE_EMBED,
					G_SIGNAL_RUN_LAST,
					G_STRUCT_OFFSET(KzEmbedIFace, dom_mouse_dbl_click),
					NULL, NULL,
					_kz_marshal_BOOLEAN__POINTER,
					G_TYPE_BOOLEAN, 1, G_TYPE_POINTER);

		kz_embed_signals[DOM_MOUSE_OVER_SIGNAL]
			= g_signal_new ("kz-dom-mouse-over",
					KZ_TYPE_EMBED,
					G_SIGNAL_RUN_LAST,
					G_STRUCT_OFFSET(KzEmbedIFace, dom_mouse_over),
					NULL, NULL,
					_kz_marshal_BOOLEAN__POINTER,
					G_TYPE_BOOLEAN, 1, G_TYPE_POINTER);

		kz_embed_signals[DOM_MOUSE_OUT_SIGNAL]
			= g_signal_new ("kz-dom-mouse-out",
					KZ_TYPE_EMBED,
					G_SIGNAL_RUN_LAST,
					G_STRUCT_OFFSET(KzEmbedIFace, dom_mouse_out),
					NULL, NULL,
					_kz_marshal_BOOLEAN__POINTER,
					G_TYPE_BOOLEAN, 1, G_TYPE_POINTER);

		kz_embed_signals[SELECTION_SIGNAL]
			= g_signal_new ("kz-selection",
					KZ_TYPE_EMBED,
					G_SIGNAL_RUN_FIRST,
					G_STRUCT_OFFSET(KzEmbedIFace, selection),
					NULL, NULL,
					g_cclosure_marshal_VOID__VOID,
					G_TYPE_NONE, 0);
		g_object_interface_install_property(
			g_iface,
			g_param_spec_string("engine-name",
					    _("Engine Name"),
					    _("Engine Name"),
					    NULL,
					    G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
	}
}


void
kz_embed_load_uri (KzEmbed *kzembed, const gchar *uri)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));

	KZ_EMBED_GET_IFACE(kzembed)->load_uri(kzembed, uri);
}


void
kz_embed_view_source (KzEmbed *kzembed, const gchar *url)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	if (!KZ_EMBED_GET_IFACE(kzembed)->view_source)
		return;

	KZ_EMBED_GET_IFACE(kzembed)->view_source(kzembed, url);
}


void
kz_embed_view_current_page_source_in_new (KzEmbed *kzembed, KzEmbed *new_embed)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	if (!KZ_EMBED_GET_IFACE(kzembed)->view_current_page_source_in_new)
		return;

	KZ_EMBED_GET_IFACE(kzembed)->view_current_page_source_in_new(kzembed, new_embed);
}


gboolean
kz_embed_can_cut_selection (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), FALSE);
	if (!KZ_EMBED_GET_IFACE(kzembed)->can_cut_selection)
		return FALSE;

	return KZ_EMBED_GET_IFACE(kzembed)->can_cut_selection(kzembed);
}


gboolean
kz_embed_can_copy_selection (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), FALSE);
	if (!KZ_EMBED_GET_IFACE(kzembed)->can_copy_selection)
		return FALSE;

	return KZ_EMBED_GET_IFACE(kzembed)->can_copy_selection(kzembed);
}


gboolean
kz_embed_can_paste (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), FALSE);
	if (!KZ_EMBED_GET_IFACE(kzembed)->can_paste)
		return FALSE;

	return KZ_EMBED_GET_IFACE(kzembed)->can_paste(kzembed);
}


void
kz_embed_cut_selection (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	if (!KZ_EMBED_GET_IFACE(kzembed)->cut_selection)
		return;

	KZ_EMBED_GET_IFACE(kzembed)->cut_selection(kzembed);
}


void
kz_embed_copy_selection (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	if (!KZ_EMBED_GET_IFACE(kzembed)->copy_selection)
		return;

	KZ_EMBED_GET_IFACE(kzembed)->copy_selection(kzembed);
}


void
kz_embed_paste (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	if (!KZ_EMBED_GET_IFACE(kzembed)->paste)
		return;

	KZ_EMBED_GET_IFACE(kzembed)->paste(kzembed);
}


void
kz_embed_select_all (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	if (!KZ_EMBED_GET_IFACE(kzembed)->select_all)
		return;

	KZ_EMBED_GET_IFACE(kzembed)->select_all(kzembed);
}


gchar *
kz_embed_get_selection_string (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), NULL);
	if (!KZ_EMBED_GET_IFACE(kzembed)->get_selection_string)
		return NULL;

	return KZ_EMBED_GET_IFACE(kzembed)->get_selection_string(kzembed);
}


gboolean
kz_embed_find (KzEmbed *kzembed, const gchar *keyword, gboolean backward)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), FALSE);
	if (!KZ_EMBED_GET_IFACE(kzembed)->find)
		return FALSE;

	return KZ_EMBED_GET_IFACE(kzembed)->find(kzembed, keyword, backward);
}


gboolean
kz_embed_incremental_search (KzEmbed *kzembed,
			     const gchar *keyword,
			     gboolean backward)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), FALSE);
	if (!KZ_EMBED_GET_IFACE(kzembed)->incremental_search)
		return FALSE;

	return KZ_EMBED_GET_IFACE(kzembed)->incremental_search(kzembed,
							       keyword,
							       backward);
}


gboolean
kz_embed_selection_is_collapsed (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), TRUE);
	if (!KZ_EMBED_GET_IFACE(kzembed)->selection_is_collapsed)
		return FALSE;

	return KZ_EMBED_GET_IFACE(kzembed)->selection_is_collapsed(kzembed);
}


gboolean
kz_embed_get_links (KzEmbed *kzembed,
		    GList **list,
		    gboolean selected_only)
{
	g_return_val_if_fail(list, FALSE);
	*list = NULL;
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), FALSE);
	if (!KZ_EMBED_GET_IFACE(kzembed)->get_links)
		return FALSE;

	return KZ_EMBED_GET_IFACE(kzembed)->get_links(kzembed,
						      list,
						      selected_only);
}


gboolean
kz_embed_get_dest_anchors (KzEmbed *kzembed,
			   GList **list)
{
	g_return_val_if_fail(list, FALSE);
	*list = NULL;
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), FALSE);
	if (!KZ_EMBED_GET_IFACE(kzembed)->get_dest_anchors)
		return FALSE;

	return KZ_EMBED_GET_IFACE(kzembed)->get_dest_anchors(kzembed,
							     list);
}


void
kz_embed_copy_page (KzEmbed *src_embed, KzEmbed *dest_embed)
{
	GList *history = NULL;
	guint current_position = 0;

	g_return_if_fail(KZ_IS_EMBED(src_embed));
	g_return_if_fail(KZ_IS_EMBED(dest_embed));

	if (G_OBJECT_TYPE(src_embed) == G_OBJECT_TYPE(dest_embed) &&
	    KZ_EMBED_GET_IFACE(src_embed)->copy_page)
	{
		KZ_EMBED_GET_IFACE(src_embed)->copy_page(src_embed, dest_embed);
		return;
	}

	if (!KZ_EMBED_GET_IFACE(src_embed)->get_history)
		return;
	if (!KZ_EMBED_GET_IFACE(dest_embed)->set_history)
		return;

	kz_embed_get_history(src_embed, &history, &current_position);
	kz_embed_set_history(dest_embed, history, current_position);
	kz_site_list_free(history);
}


gboolean
kz_embed_shistory_get_pos (KzEmbed *kzembed,
			   gint *pos, gint *count)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), 0);
	if (!KZ_EMBED_GET_IFACE(kzembed)->shistory_get_pos)
		return 0;

	return KZ_EMBED_GET_IFACE(kzembed)->shistory_get_pos(kzembed,
							     pos, count);
}


void
kz_embed_shistory_get_nth (KzEmbed *kzembed, 
			   gint nth,
			   gboolean is_relative,
			   gchar **aUrl,
			   gchar **aTitle)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	if (!KZ_EMBED_GET_IFACE(kzembed)->shistory_get_nth)
		return;

	KZ_EMBED_GET_IFACE(kzembed)->shistory_get_nth(kzembed, nth, is_relative,
						      aUrl, aTitle);
}


void
kz_embed_reload (KzEmbed *kzembed, KzEmbedReloadFlag flags)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	g_return_if_fail(KZ_EMBED_GET_IFACE(kzembed)->reload);
	g_return_if_fail(KZ_EMBED_RELOAD_NORMAL <= flags &&
			 flags <= KZ_EMBED_RELOAD_CHARSET_CHANGE);

	KZ_EMBED_GET_IFACE(kzembed)->reload(kzembed, flags);
}


void
kz_embed_stop_load (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	g_return_if_fail(KZ_EMBED_GET_IFACE(kzembed)->stop_load);

	KZ_EMBED_GET_IFACE(kzembed)->stop_load(kzembed);
}


void
kz_embed_go_back (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	g_return_if_fail(KZ_EMBED_GET_IFACE(kzembed)->go_back);

	KZ_EMBED_GET_IFACE(kzembed)->go_back(kzembed);
}

void
kz_embed_go_forward (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	g_return_if_fail(KZ_EMBED_GET_IFACE(kzembed)->go_forward);

	KZ_EMBED_GET_IFACE(kzembed)->go_forward(kzembed);
}

gboolean
kz_embed_can_go_back (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), FALSE);
	if (!KZ_EMBED_GET_IFACE(kzembed)->can_go_back)
                return FALSE;

	return KZ_EMBED_GET_IFACE(kzembed)->can_go_back(kzembed);
}

gboolean
kz_embed_can_go_forward (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), FALSE);
	if (!KZ_EMBED_GET_IFACE(kzembed)->can_go_forward)
                return FALSE;

	return KZ_EMBED_GET_IFACE(kzembed)->can_go_forward(kzembed);
}

gboolean
kz_embed_can_go_nav_link (KzEmbed *kzembed, KzEmbedNavLink link)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), FALSE);
	if (!KZ_EMBED_GET_IFACE(kzembed)->can_go_nav_link)
		return FALSE;

	return KZ_EMBED_GET_IFACE(kzembed)->can_go_nav_link(kzembed, link);
}


void
kz_embed_go_nav_link (KzEmbed *kzembed, KzEmbedNavLink link)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	if (!KZ_EMBED_GET_IFACE(kzembed)->go_nav_link)
		return;

	KZ_EMBED_GET_IFACE(kzembed)->go_nav_link(kzembed, link);
}


void
kz_embed_append_nav_link (KzEmbed *kzembed,
			  KzEmbedNavLink link,
			  KzNavi *navi)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	if (!KZ_EMBED_GET_IFACE(kzembed)->append_nav_link)
		return;

	KZ_EMBED_GET_IFACE(kzembed)->append_nav_link(kzembed, link, navi);
}

void
kz_embed_set_nav_link (KzEmbed *kzembed,
		       KzEmbedNavLink link,
		       KzNavi *navi)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));

	if (KZ_EMBED_GET_IFACE(kzembed)->set_nav_link)
		KZ_EMBED_GET_IFACE(kzembed)->set_nav_link(kzembed, link, navi);
	else
		kz_embed_set_nth_nav_link(kzembed, link, navi, 0);
}

void
kz_embed_set_nth_nav_link (KzEmbed *kzembed,
			   KzEmbedNavLink link,
			   KzNavi *navi,
			   guint n)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	if (!KZ_EMBED_GET_IFACE(kzembed)->set_nth_nav_link)
		return;

	KZ_EMBED_GET_IFACE(kzembed)->set_nth_nav_link(kzembed, link, navi, n);
}


KzNavi *
kz_embed_get_nav_link (KzEmbed *kzembed, KzEmbedNavLink link)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), NULL);

	if (KZ_EMBED_GET_IFACE(kzembed)->get_nav_link)
		return KZ_EMBED_GET_IFACE(kzembed)->get_nav_link(kzembed, link);
	else
		return kz_embed_get_nth_nav_link(kzembed, link, 0);
}

KzNavi *
kz_embed_get_nth_nav_link (KzEmbed *kzembed, KzEmbedNavLink link, guint n)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), NULL);
	if (!KZ_EMBED_GET_IFACE(kzembed)->get_nth_nav_link)
		return NULL;

	return KZ_EMBED_GET_IFACE(kzembed)->get_nth_nav_link(kzembed, link, n);
}


GList *
kz_embed_get_nav_links (KzEmbed *kzembed, KzEmbedNavLink link)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), NULL);
	if (!KZ_EMBED_GET_IFACE(kzembed)->get_nav_links)
		return NULL;

	return KZ_EMBED_GET_IFACE(kzembed)->get_nav_links(kzembed, link);
}


void
kz_embed_go_history_index (KzEmbed *kzembed, gint index)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	if (!KZ_EMBED_GET_IFACE(kzembed)->go_history_index)
		return;

	KZ_EMBED_GET_IFACE(kzembed)->go_history_index(kzembed, index);
}


gchar *
kz_embed_get_body_text (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), NULL);
	if (!KZ_EMBED_GET_IFACE(kzembed)->get_body_text)
		return NULL;

	return KZ_EMBED_GET_IFACE(kzembed)->get_body_text(kzembed);
}


void
kz_embed_set_encoding (KzEmbed *kzembed, const gchar *encoding)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	if (!KZ_EMBED_GET_IFACE(kzembed)->set_encoding)
		return;

	KZ_EMBED_GET_IFACE(kzembed)->set_encoding(kzembed, encoding);
}


void
kz_embed_get_encoding (KzEmbed *kzembed, gchar **encoding, gboolean *forced)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	if (!KZ_EMBED_GET_IFACE(kzembed)->get_encoding)
		return;

	KZ_EMBED_GET_IFACE(kzembed)->get_encoding(kzembed, encoding, forced);
}


void
kz_embed_print (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	if (!KZ_EMBED_GET_IFACE(kzembed)->print)
		return;

	KZ_EMBED_GET_IFACE(kzembed)->print(kzembed);
}


void
kz_embed_print_preview (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	if (!KZ_EMBED_GET_IFACE(kzembed)->print_preview)
		return;

	KZ_EMBED_GET_IFACE(kzembed)->print_preview(kzembed);
}


GList *
kz_embed_get_printer_list (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), NULL);
	if (!KZ_EMBED_GET_IFACE(kzembed)->get_printer_list)
		return NULL;

	return KZ_EMBED_GET_IFACE(kzembed)->get_printer_list(kzembed);
}


void
kz_embed_create_thumbnail (KzEmbed *kzembed, EggPixbufThumbnailSize size)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));

	if (KZ_EMBED_GET_IFACE(kzembed)->create_thumbnail)
		KZ_EMBED_GET_IFACE(kzembed)->create_thumbnail(kzembed, size);
}


gboolean
kz_embed_save_with_content (KzEmbed *kzembed, const gchar *rawfilename)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), FALSE);
	if (!KZ_EMBED_GET_IFACE(kzembed)->save_with_content)
		return FALSE;

	return KZ_EMBED_GET_IFACE(kzembed)->save_with_content(kzembed,
							      rawfilename);
}


gboolean
kz_embed_set_text_into_textarea	(KzEmbed *kzembed,
				 gpointer element,
				 const gchar *text)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), FALSE);
	if (!KZ_EMBED_GET_IFACE(kzembed)->set_text_into_textarea)
		return FALSE;

	return KZ_EMBED_GET_IFACE(kzembed)->set_text_into_textarea(kzembed,
								   element,
								   text);
}


gchar *
kz_embed_get_text_from_textarea (KzEmbed *kzembed, gpointer element)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), NULL);
	if (!KZ_EMBED_GET_IFACE(kzembed)->get_text_from_textarea)
		return NULL;

	return KZ_EMBED_GET_IFACE(kzembed)->get_text_from_textarea(kzembed,
								   element);
}


void
kz_embed_zoom (KzEmbed *kzembed, gdouble zoom)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	if (!KZ_EMBED_GET_IFACE(kzembed)->zoom)
		return;

	KZ_EMBED_GET_IFACE(kzembed)->zoom(kzembed, zoom);
}


gdouble
kz_embed_get_zoom_ratio (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), 1.0);
	if (!KZ_EMBED_GET_IFACE(kzembed)->get_zoom_ratio)
		return 1.0;

	return KZ_EMBED_GET_IFACE(kzembed)->get_zoom_ratio(kzembed);
}


void
kz_embed_set_text_size (KzEmbed *kzembed, gdouble zoom)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	if (!KZ_EMBED_GET_IFACE(kzembed)->set_text_size)
		return;

	KZ_EMBED_GET_IFACE(kzembed)->set_text_size(kzembed, zoom);
}


gdouble
kz_embed_get_text_size (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), 100);
	if (!KZ_EMBED_GET_IFACE(kzembed)->get_text_size)
		return 100;

	return KZ_EMBED_GET_IFACE(kzembed)->get_text_size(kzembed);
}


gchar *
kz_embed_get_html_with_contents (KzEmbed *kzembed, const gchar *storedir)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), NULL);
	if (!KZ_EMBED_GET_IFACE(kzembed)->get_html_with_contents)
		return NULL;

	return KZ_EMBED_GET_IFACE(kzembed)->get_html_with_contents(kzembed,
								   storedir);
}


void
kz_embed_set_history (KzEmbed *kzembed, const GList *history, guint current_position)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	if (KZ_EMBED_GET_IFACE(kzembed)->set_history)
		KZ_EMBED_GET_IFACE(kzembed)->set_history(kzembed, history, current_position);
}


void
kz_embed_get_history (KzEmbed *kzembed, GList **history, guint *current_position)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	
	if (KZ_EMBED_GET_IFACE(kzembed)->get_history)
		KZ_EMBED_GET_IFACE(kzembed)->get_history(kzembed, history, current_position);
}


guint
kz_embed_get_last_modified (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), 0);
	if (KZ_EMBED_GET_IFACE(kzembed)->get_last_modified)
		return KZ_EMBED_GET_IFACE(kzembed)->get_last_modified(kzembed);
	return 0;
}


void
kz_embed_fine_scroll (KzEmbed *kzembed, 
		      gint horiz, gint vert)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));

	KZ_EMBED_GET_IFACE(kzembed)->fine_scroll (kzembed, horiz, vert);
}


void
kz_embed_page_down (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	if (!KZ_EMBED_GET_IFACE(kzembed)->page_down)
		return;

	KZ_EMBED_GET_IFACE(kzembed)->page_down(kzembed);
}


void
kz_embed_page_up (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	if (!KZ_EMBED_GET_IFACE(kzembed)->page_up)
		return;

	KZ_EMBED_GET_IFACE(kzembed)->page_up(kzembed);
}


void
kz_embed_set_allow_javascript (KzEmbed *kzembed, gboolean allow)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	if (!KZ_EMBED_GET_IFACE(kzembed)->set_allow_javascript)
		return;

	KZ_EMBED_GET_IFACE(kzembed)->set_allow_javascript(kzembed, allow);
}


gboolean
kz_embed_get_allow_javascript (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), FALSE);
	if (!KZ_EMBED_GET_IFACE(kzembed)->get_allow_javascript)
		return FALSE;

	return KZ_EMBED_GET_IFACE(kzembed)->get_allow_javascript(kzembed);
}


void
kz_embed_set_allow_images (KzEmbed *kzembed, gboolean allow)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	if (!KZ_EMBED_GET_IFACE(kzembed)->set_allow_images)
		return;

	KZ_EMBED_GET_IFACE(kzembed)->set_allow_images(kzembed, allow);
}


gboolean
kz_embed_get_allow_images (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), FALSE);
	if (!KZ_EMBED_GET_IFACE(kzembed)->get_allow_images)
		return FALSE;

	return KZ_EMBED_GET_IFACE(kzembed)->get_allow_images(kzembed);
}

void
kz_embed_show_page_certificate (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	if (!KZ_EMBED_GET_IFACE(kzembed)->show_page_certificate)
		return;

	return KZ_EMBED_GET_IFACE(kzembed)->show_page_certificate(kzembed);
}

