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

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};

static gchar *kz_embed_get_up_location(KzEmbed *kzembed);

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,
						  G_TYPE_OBJECT);
	}
	return type;
}

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

	if (initialized) return;

	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__VOID,
				G_TYPE_NONE, 0);

	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__VOID,
				G_TYPE_NONE, 0);

	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__VOID,
				G_TYPE_NONE, 0);

	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__VOID,
				G_TYPE_NONE, 0);

	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_INT__POINTER,
				G_TYPE_INT, 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_INT__POINTER,
				G_TYPE_INT, 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_INT__POINTER,
				G_TYPE_INT, 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_INT__POINTER,
				G_TYPE_INT, 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_INT__POINTER,
				G_TYPE_INT, 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_INT__POINTER,
				G_TYPE_INT, 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_INT__POINTER,
				G_TYPE_INT, 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_INT__POINTER,
				G_TYPE_INT, 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_INT__POINTER,
				G_TYPE_INT, 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);


	initialized = TRUE;
}


void
kz_embed_load_url (KzEmbed *kzembed, const gchar *url)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));

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


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

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


gboolean
kz_embed_is_loading (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), FALSE);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->is_loading, FALSE);

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


const gchar *
kz_embed_get_title (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), NULL);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->get_title, NULL);

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


const gchar *
kz_embed_get_location (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), NULL);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->get_location, NULL);

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


gchar *
kz_embed_ensure_title (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), NULL);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->ensure_title, NULL);

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


gchar *
kz_embed_get_link_message (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), NULL);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->get_link_message, NULL);

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


gdouble
kz_embed_get_progress (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), 0.0);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->get_progress, 0.0);

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


gboolean
kz_embed_can_cut_selection (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), FALSE);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->can_cut_selection, 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);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->can_copy_selection, 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);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->can_paste, 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));
	g_return_if_fail(KZ_EMBED_GET_IFACE(kzembed)->cut_selection);

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


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

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


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

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


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

	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);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->get_selection_string, FALSE);

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


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

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


gboolean
kz_embed_incremental_search (KzEmbed *kzembed,
			     const char *keyword,
			     gboolean backward)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), FALSE);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->incremental_search, 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);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->selection_is_collapsed, 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);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->get_links, 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);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->get_links, FALSE);

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


void
kz_embed_copy_page (KzEmbed *kzembed, KzEmbed *dkzembed, KzEmbedCopyType type)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	g_return_if_fail(KZ_EMBED_GET_IFACE(kzembed)->copy_page);

	KZ_EMBED_GET_IFACE(kzembed)->copy_page(kzembed, dkzembed, type);
}


gboolean
kz_embed_shistory_copy (KzEmbed *source,
			KzEmbed *dest,
			gboolean back_history,
			gboolean forward_history,
			gboolean set_current)
{
	g_return_val_if_fail(KZ_IS_EMBED(source), FALSE);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(source)->shistory_copy, FALSE);

	return KZ_EMBED_GET_IFACE(source)->shistory_copy(source, dest,
							 back_history,
							 forward_history,
							 set_current);
}


gboolean
kz_embed_shistory_get_pos (KzEmbed *kzembed,
			   gint *pos, gint *count)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), 0);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->shistory_get_pos, 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));
	g_return_if_fail(KZ_EMBED_GET_IFACE(kzembed)->shistory_get_nth);

	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);
}


void
kz_embed_go_up (KzEmbed *kzembed)
{
	gchar *location;
	g_return_if_fail(KZ_IS_EMBED(kzembed));

	location = kz_embed_get_up_location(kzembed);
	kz_embed_load_url(kzembed, location);
	g_free(location);
}


gboolean
kz_embed_can_go_back (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), FALSE);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->can_go_back, 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);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->can_go_forward, FALSE);

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


gboolean
kz_embed_can_go_up (KzEmbed *kzembed)
{
	gboolean ret;
	gchar *location;

	g_return_val_if_fail(KZ_IS_EMBED(kzembed), FALSE);

	location = kz_embed_get_up_location(kzembed);

	if (!location) return FALSE;

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

	return ret;
}


gboolean
kz_embed_can_go_nav_link (KzEmbed *kzembed, KzEmbedNavLink link)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), FALSE);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->can_go_nav_link, 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));
	g_return_if_fail(KZ_EMBED_GET_IFACE(kzembed)->go_nav_link);

	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));
	g_return_if_fail(KZ_EMBED_GET_IFACE(kzembed)->append_nav_link);

	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));
	g_return_if_fail(KZ_EMBED_GET_IFACE(kzembed)->set_nth_nav_link);

	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);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->get_nth_nav_link, 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);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->get_nav_links, 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));
	g_return_if_fail(KZ_EMBED_GET_IFACE(kzembed)->go_history_index);

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


void
kz_embed_do_command (KzEmbed *kzembed, const char *command)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	g_return_if_fail(KZ_EMBED_GET_IFACE(kzembed)->do_command);

	KZ_EMBED_GET_IFACE(kzembed)->do_command(kzembed, command);
}


gboolean
kz_embed_can_do_command (KzEmbed *kzembed, const char *command)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), FALSE);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->can_do_command, FALSE);

	return KZ_EMBED_GET_IFACE(kzembed)->can_do_command(kzembed, command);
}


gboolean
kz_embed_get_lock (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), FALSE);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->get_lock, FALSE);

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


void
kz_embed_set_lock (KzEmbed *kzembed, gboolean lock)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	g_return_if_fail(KZ_EMBED_GET_IFACE(kzembed)->set_lock);

	KZ_EMBED_GET_IFACE(kzembed)->set_lock(kzembed, lock);
}


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

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


#if 0
gchar *
kz_embed_get_selection_source (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), NULL);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->get_selection_source, NULL);

	return KZ_EMBED_GET_IFACE(kzembed)->get_selection_source(kzembed);
}
#endif


void
kz_embed_set_encoding (KzEmbed *kzembed, const char *encoding)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	g_return_if_fail(KZ_EMBED_GET_IFACE(kzembed)->set_encoding);

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


void
kz_embed_get_encoding (KzEmbed *kzembed, char **encoding, gboolean *forced)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	g_return_if_fail(KZ_EMBED_GET_IFACE(kzembed)->get_encoding);

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


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

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


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

	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);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->get_printer_list, NULL);

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


void
kz_embed_create_thumbnail (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	g_return_if_fail(KZ_EMBED_GET_IFACE(kzembed)->create_thumbnail);

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


gboolean
kz_embed_save_with_content (KzEmbed *kzembed, const char *rawfilename)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), FALSE);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->save_with_content, 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);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->set_text_into_textarea, 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);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->get_text_from_textarea, NULL);

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


void
kz_embed_zoom_set (KzEmbed *kzembed, gint zoom, gboolean reflow)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	g_return_if_fail(KZ_EMBED_GET_IFACE(kzembed)->zoom_set);

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


gint
kz_embed_zoom_get (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), 100);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->zoom_set, 100);

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


void
kz_embed_set_text_size (KzEmbed *kzembed, gint zoom, gboolean reflow)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	g_return_if_fail(KZ_EMBED_GET_IFACE(kzembed)->set_text_size);

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


gint
kz_embed_get_text_size (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), 100);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->get_text_size, 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);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->get_html_with_contents, NULL);

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


void
kz_embed_set_history (KzEmbed *kzembed, KzBookmark *history)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	g_return_if_fail(KZ_EMBED_GET_IFACE(kzembed)->set_history);

	KZ_EMBED_GET_IFACE(kzembed)->set_history(kzembed, history);
}


void
kz_embed_get_history (KzEmbed *kzembed, KzBookmark *history)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	g_return_if_fail(KZ_EMBED_GET_IFACE(kzembed)->get_history);

	KZ_EMBED_GET_IFACE(kzembed)->get_history(kzembed, history);
}


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

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


#if 0
void
kz_embed_set_edit_mode (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	g_return_if_fail(KZ_EMBED_GET_IFACE(kzembed)->set_edit_mode);

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


void
kz_embed_set_view_mode (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_EMBED(kzembed));
	g_return_if_fail(KZ_EMBED_GET_IFACE(kzembed)->set_view_mode);

	KZ_EMBED_GET_IFACE(kzembed)->set_view_mode(kzembed);
}
#endif


void
kz_embed_fine_scroll (KzEmbed *kzembed, 
		      int horiz, int 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));
	g_return_if_fail(KZ_EMBED_GET_IFACE(kzembed)->page_down);

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


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

	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));
	g_return_if_fail(KZ_EMBED_GET_IFACE(kzembed)->set_allow_javascript);

	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);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->get_allow_javascript, 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));
	g_return_if_fail(KZ_EMBED_GET_IFACE(kzembed)->set_allow_images);

	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);
	g_return_val_if_fail(KZ_EMBED_GET_IFACE(kzembed)->get_allow_images, 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));
	g_return_if_fail(KZ_EMBED_GET_IFACE(kzembed)->show_page_certificate);

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

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

	location = kz_embed_get_location(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;
}
