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

/*
 *  Copyright (C) 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 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.
 *
 *  $Id: kz-khtml.c 2874 2007-03-16 01:18:48Z ikezoe $
 */

#include <glib/gi18n.h>
#include <math.h>

#include "kz-khtml.h"
#include "gobject-utils.h"

typedef struct _KzKHTMLPrivate	KzKHTMLPrivate;
struct _KzKHTMLPrivate
{
	gint cur_requests;
	gint total_requests;
	gchar *link_message;
};
#define KZ_KHTML_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), KZ_TYPE_KHTML, KzKHTMLPrivate))

static void kz_khtml_class_init   (KzKHTMLClass *klass);
static void kz_khtml_iface_init   (KzEmbedIFace *iface);
static void kz_khtml_init         (KzKHTML      *khtml);
static void kz_khtml_dispose      (GObject      *object);

#if 0
/* widget class */
static gboolean button_press      (GtkWidget        *widget,
                                   GdkEventButton   *event);
static gboolean button_release    (GtkWidget        *widget,
                                   GdkEventButton   *event);
#endif

/* khtml class */
static void         kz_khtml_status           (Webi *khtml,
					       WebiLoadStatus *status);
static void         kz_khtml_load_start       (Webi     *khtml);
static void         kz_khtml_load_stop        (Webi     *khtml);
static void         kz_khtml_location         (Webi     *khtml);
static void         kz_khtml_title            (Webi     *khtml);
static void         kz_khtml_req_js_prompt    (Webi     *khtml,
					       WebiPromptArgs* args);
static void         kz_khtml_req_auth_prompt  (Webi     *khtml,
					       WebiAuthArgs* args);
static gboolean     kz_khtml_req_new_window   (Webi     *khtml,
					       Webi     *newkhtml);
static void         kz_khtml_mouse_over       (Webi        *khtml,
					       const gchar *link_title,
					       const gchar *link_label,
					       const gchar *link_url,
					       const gchar *link_target);

/* embed iface */
static void         kz_khtml_load_url         (KzEmbed      *kzembed,
					       const gchar  *url);
static gboolean     kz_khtml_is_loading       (KzEmbed      *kzembed);
static const gchar *kz_khtml_get_title        (KzEmbed      *kzembed);
static const gchar *kz_khtml_get_location     (KzEmbed      *kzembed);
static gchar       *kz_khtml_ensure_title     (KzEmbed      *kzembed);
static gchar       *kz_khtml_get_link_message (KzEmbed      *kzembed);

static void         kz_khtml_reload           (KzEmbed      *kzembed,
					       KzEmbedReloadFlag flags);
static void         kz_khtml_stop_load        (KzEmbed      *kzembed);
static void         kz_khtml_go_back          (KzEmbed      *kzembed);
static void         kz_khtml_go_forward       (KzEmbed      *kzembed);
static gboolean     kz_khtml_can_go_back      (KzEmbed      *kzembed);
static gboolean     kz_khtml_can_go_forward   (KzEmbed      *kzembed);
static gboolean     kz_khtml_can_go_nav_link  (KzEmbed      *kzembed,
					       KzEmbedNavLink link);
static void         kz_khtml_go_nav_link      (KzEmbed      *kzembed,
					       KzEmbedNavLink link);
static void         kz_khtml_set_nth_nav_link (KzEmbed      *kzembed,
					       KzEmbedNavLink link,
					       KzNavi       *navi,
					       guint         n);
static KzNavi      *kz_khtml_get_nth_nav_link (KzEmbed      *kzembed,
					       KzEmbedNavLink link,
					       guint         n);
static GList       *kz_khtml_get_nav_links    (KzEmbed      *kzembed,
					       KzEmbedNavLink link);

static gboolean     kz_khtml_can_cut_selection  (KzEmbed      *kzembed);
static gboolean     kz_khtml_can_copy_selection (KzEmbed      *kzembed);
static gboolean     kz_khtml_can_paste          (KzEmbed      *kzembed);
static void         kz_khtml_cut_selection      (KzEmbed      *kzembed);
static void         kz_khtml_copy_selection     (KzEmbed      *kzembed);
static void         kz_khtml_paste              (KzEmbed      *kzembed);
static void         kz_khtml_select_all         (KzEmbed      *kzembed);

static gdouble      kz_khtml_get_progress     (KzEmbed      *kzembed);

static gint         kz_khtml_get_text_size    (KzEmbed      *kzembed);
static void         kz_khtml_set_text_size    (KzEmbed      *kzembed,
		                               gint         zoom,
					       gboolean     reflow);

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

G_DEFINE_TYPE_WITH_CODE(KzKHTML, kz_khtml, WEBI_TYPE_WEBI,
                        G_IMPLEMENT_INTERFACE (KZ_TYPE_EMBED,
					       kz_khtml_iface_init))

static void
kz_khtml_class_init (KzKHTMLClass *klass)
{
	GObjectClass *object_class;
	GtkWidgetClass *widget_class;
	WebiClass *khtml_class;

	kz_khtml_parent_class = g_type_class_peek_parent (klass);
	object_class = (GObjectClass *) klass;
	widget_class = (GtkWidgetClass *) klass;
	khtml_class  = (WebiClass *) klass;

	object_class->dispose   = kz_khtml_dispose;
#if 0
	widget_class->button_press_event   = button_press;
	widget_class->button_release_event = button_release;
#endif
	khtml_class->status     = kz_khtml_status;
	khtml_class->load_start = kz_khtml_load_start;
	khtml_class->load_stop  = kz_khtml_load_stop;
	khtml_class->location   = kz_khtml_location;
	khtml_class->title      = kz_khtml_title;
#if 0	
	khtml_class->progress   = kz_khtml_progress;
#endif	
	khtml_class->req_js_prompt   = kz_khtml_req_js_prompt;
	khtml_class->req_auth_prompt = kz_khtml_req_auth_prompt;
	khtml_class->req_new_window  = kz_khtml_req_new_window;
	khtml_class->mouse_over      = kz_khtml_mouse_over;
	
	g_type_class_add_private (object_class, sizeof(KzKHTMLPrivate));
}


static void
kz_khtml_iface_init (KzEmbedIFace *iface)
{
	iface->load_url               = kz_khtml_load_url;
	iface->view_source            = NULL;
	iface->is_loading             = kz_khtml_is_loading;
	iface->get_title              = kz_khtml_get_title;
	iface->get_location           = kz_khtml_get_location;
	iface->ensure_title           = kz_khtml_ensure_title;
	iface->get_link_message       = kz_khtml_get_link_message;
	iface->get_progress           = kz_khtml_get_progress;
	iface->can_cut_selection      = kz_khtml_can_cut_selection;
	iface->can_copy_selection     = kz_khtml_can_copy_selection;
	iface->can_paste              = kz_khtml_can_paste;
	iface->cut_selection          = kz_khtml_cut_selection;
	iface->copy_selection         = kz_khtml_copy_selection;
	iface->paste                  = kz_khtml_paste;
	iface->select_all             = kz_khtml_select_all;
	iface->get_selection_string   = NULL;
	iface->find                   = kz_khtml_find;
	iface->incremental_search     = kz_khtml_find; /* tentavie */
	iface->selection_is_collapsed = NULL;
	iface->get_links              = NULL;
	iface->copy_page              = NULL;
	iface->shistory_copy          = NULL;
	iface->shistory_get_pos       = NULL;
	iface->shistory_get_nth       = NULL;
	iface->reload                 = kz_khtml_reload;
	iface->stop_load              = kz_khtml_stop_load;
	iface->go_back                = kz_khtml_go_back;
	iface->go_forward             = kz_khtml_go_forward;
	iface->can_go_back            = kz_khtml_can_go_back;
	iface->can_go_forward         = kz_khtml_can_go_forward;
	iface->can_go_nav_link        = kz_khtml_can_go_nav_link;
	iface->go_nav_link            = kz_khtml_go_nav_link;
	iface->append_nav_link        = NULL;
	iface->set_nav_link           = NULL;
	iface->set_nth_nav_link       = kz_khtml_set_nth_nav_link;
	iface->get_nav_link           = NULL;
	iface->get_nth_nav_link       = kz_khtml_get_nth_nav_link;
	iface->get_nav_links          = kz_khtml_get_nav_links;
	iface->go_history_index       = NULL;
	iface->do_command             = NULL;
	iface->can_do_command         = NULL;
	iface->get_lock               = NULL;
	iface->set_lock               = NULL;
	iface->get_body_text          = NULL;
#if 0
	iface->get_selection_source   = NULL;
#endif
	iface->set_encoding           = NULL;
	iface->get_encoding           = NULL;
	iface->print                  = NULL;
	iface->print_preview          = NULL;
	iface->get_printer_list       = NULL;
	iface->create_thumbnail       = NULL;
	iface->save_with_content      = NULL;
	iface->set_text_into_textarea = NULL;
	iface->get_text_from_textarea = NULL;
	iface->zoom_set               = kz_khtml_set_text_size; /* tentative */
	iface->zoom_get               = kz_khtml_get_text_size; /* tentative */
	iface->set_text_size          = kz_khtml_set_text_size;
	iface->get_text_size          = kz_khtml_get_text_size;
	iface->get_html_with_contents = NULL;
	iface->set_history            = NULL;
	iface->get_history            = NULL;
	iface->get_last_modified      = NULL;
	iface->fine_scroll            = NULL;
	iface->page_up                = NULL;
	iface->page_down              = NULL; 
	iface->get_allow_javascript   = NULL; 
	iface->set_allow_javascript   = NULL; 
	iface->get_allow_images       = NULL; 
	iface->set_allow_images       = NULL; 
#if 0
	iface->set_edit_mode          = NULL;
	iface->set_view_mode          = NULL;
#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;
}


static void
kz_khtml_init (KzKHTML *khtml)
{
	KzKHTMLPrivate *priv = KZ_KHTML_GET_PRIVATE (khtml);

	khtml->is_loading = FALSE;
	priv->cur_requests   = 0;
	priv->total_requests = 0;
	priv->link_message   = NULL;

	gtk_widget_show_all(GTK_WIDGET(khtml));
}

static void
kz_khtml_dispose (GObject *object)
{
	KzKHTMLPrivate *priv = KZ_KHTML_GET_PRIVATE(object);

	if (priv->link_message)
		g_free(priv->link_message);
	priv->link_message = NULL;

	if (G_OBJECT_CLASS(kz_khtml_parent_class)->dispose)
		G_OBJECT_CLASS(kz_khtml_parent_class)->dispose(object);
}

#if 0
static gboolean
button_press (GtkWidget *widget, GdkEventButton *event)
{
	if (GTK_WIDGET_CLASS(kz_khtml_parent_class)->button_press_event)
		return  GTK_WIDGET_CLASS(kz_khtml_parent_class)->button_press_event(widget, event);

	return FALSE;
}

static gboolean
button_release (GtkWidget *widget, GdkEventButton *event)
{
	if (GTK_WIDGET_CLASS(kz_khtml_parent_class)->button_press_event)
		return GTK_WIDGET_CLASS(kz_khtml_parent_class)->button_press_event(widget, event);
	return FALSE;
}
#endif

GtkWidget *
kz_khtml_new (const gchar *url)
{
	KzKHTML *kzhtml = KZ_KHTML(g_object_new(KZ_TYPE_KHTML, NULL));

	kz_khtml_load_url(KZ_EMBED(kzhtml), url);

	return GTK_WIDGET(kzhtml);
}


static void
kz_khtml_status (Webi *khtml, WebiLoadStatus *status)
{
	KzKHTMLPrivate *priv;
	g_return_if_fail(KZ_IS_KHTML(khtml));
	g_return_if_fail(status);

	priv = KZ_KHTML_GET_PRIVATE (khtml);

	switch(status->status) {
	case WEBI_LOADING_START:
		KZ_KHTML(khtml)->is_loading = TRUE;
		priv->cur_requests = 0;
		priv->total_requests = 0;
		g_signal_emit_by_name(khtml, "kz-net-start");
		break;
	case WEBI_LOADING:
		priv->cur_requests = status->totalReceived;
		priv->total_requests = status->totalSize;
		g_signal_emit_by_name(khtml, "kz-progress");
		break;
	case WEBI_LOADING_COMPLETE:
	case WEBI_LOADING_ERROR:
		KZ_KHTML(khtml)->is_loading = FALSE;
		priv->cur_requests = status->totalReceived;
		priv->total_requests = status->totalSize;
		g_signal_emit_by_name(khtml, "kz-net-stop");
		break;
	default:
		break;
	}

	/* call parent method */
}


static void
kz_khtml_load_start (Webi *khtml)
{
	g_return_if_fail(KZ_IS_KHTML(khtml));

	KZ_KHTML(khtml)->is_loading = TRUE;

	g_signal_emit_by_name(khtml, "kz-net-start");

	/* call parent method */
}


static void
kz_khtml_load_stop (Webi *khtml)
{
	g_return_if_fail(KZ_IS_KHTML(khtml));

	KZ_KHTML(khtml)->is_loading = FALSE;

	g_signal_emit_by_name(khtml, "kz-net-stop");

	/* call parent method */
}


static void
kz_khtml_location (Webi *khtml)
{
	g_return_if_fail(KZ_IS_KHTML(khtml));

	g_signal_emit_by_name(khtml, "kz-location");

	/* call parent method */
}


static void
kz_khtml_title (Webi *khtml)
{
	g_return_if_fail(KZ_IS_KHTML(khtml));

	g_signal_emit_by_name(khtml, "kz-title");

	/* call parent method */
}


static void
kz_khtml_req_js_prompt (Webi *khtml, WebiPromptArgs* args)
{
	g_return_if_fail(KZ_IS_KHTML(khtml));
}


static void
kz_khtml_req_auth_prompt (Webi *khtml, WebiAuthArgs* args)
{
	g_return_if_fail(KZ_IS_KHTML(khtml));
}


static gboolean
kz_khtml_req_new_window (Webi *khtml, Webi *newkhtml)
{
	g_return_val_if_fail(KZ_IS_KHTML(khtml), FALSE);
	
	g_signal_emit_by_name(khtml, "kz-new-window", newkhtml);
	return TRUE;
}

static void
kz_khtml_mouse_over (Webi *khtml,
		     const gchar *link_title,
		     const gchar *link_label,
		     const gchar *link_url,
		     const gchar *link_target)
{
	KzEmbedEventMouse *kzevent;
	gint ret = FALSE;
	GdkModifierType state = (GdkModifierType)0;
	gint x, y;
	KzKHTMLPrivate *priv;
	g_return_if_fail(KZ_IS_KHTML(khtml));

	priv = KZ_KHTML_GET_PRIVATE(khtml);
	kzevent = (KzEmbedEventMouse *) kz_embed_event_new(KZ_EMBED_EVENT_MOUSE);
	gdk_window_get_pointer(NULL, &x, &y, &state);
	kzevent->x = x;
	kzevent->y = y;
	if (state & GDK_SHIFT_MASK)
        	kzevent->modifier |= KZ_SHIFT_KEY;
	if (state & GDK_CONTROL_MASK)
        	kzevent->modifier |= KZ_CTRL_KEY;
	if (state & GDK_MOD1_MASK)
        	kzevent->modifier |= KZ_ALT_KEY;
	if (state & GDK_META_MASK)
        	kzevent->modifier |= KZ_META_KEY;


	if (!link_url)
	{
		if (priv->link_message)
		{
			g_free(priv->link_message);
			priv->link_message = NULL;
			g_signal_emit_by_name(khtml, "kz-link-message");
		}
	}
	else	
	{
		KzEmbedEvent *info = (KzEmbedEvent *) kzevent;
		info->context = KZ_CONTEXT_LINK;
		info->link = g_strdup(link_url);
		info->linktext = g_strdup(link_label);

		if (priv->link_message)
			g_free(priv->link_message);

		priv->link_message = g_strdup(link_url);

		g_signal_emit_by_name(khtml, "kz-link-message");
	}

	g_signal_emit_by_name(khtml, "kz-dom-mouse-over",
			      kzevent, &ret);
	kz_embed_event_free((KzEmbedEvent *) kzevent);
}

static gboolean
kz_khtml_is_loading (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_KHTML(kzembed), FALSE);

	return KZ_KHTML(kzembed)->is_loading;
}


static void
kz_khtml_load_url (KzEmbed *kzembed, const gchar *url)
{
	g_return_if_fail(KZ_IS_KHTML(kzembed));

	webi_load_url(WEBI(kzembed), url);
}


static const gchar *
kz_khtml_get_title (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_KHTML(kzembed), NULL);

	return webi_get_title(WEBI(kzembed));
}


static const gchar *
kz_khtml_get_location (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_KHTML(kzembed), NULL);

	return webi_get_location(WEBI(kzembed));
}

static gchar *
kz_khtml_get_link_message (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_KHTML(kzembed), NULL);

	return g_strdup(KZ_KHTML_GET_PRIVATE(kzembed)->link_message);
}

static gchar *
kz_khtml_ensure_title (KzEmbed *kzembed)
{
	const gchar *title;

	title = kz_khtml_get_title(kzembed);
	if (title)
		return g_strdup(title);

	title = kz_khtml_get_location(kzembed);
	if (title)
		return g_strdup(title);

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

static void
kz_khtml_reload (KzEmbed *kzembed, KzEmbedReloadFlag flags)
{
	g_return_if_fail(KZ_IS_KHTML(kzembed));

	webi_refresh (WEBI(kzembed));
}


static void
kz_khtml_stop_load (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_KHTML(kzembed));

	webi_stop_load (WEBI(kzembed));
}


static void
kz_khtml_go_back (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_KHTML(kzembed));

	return webi_go_back (WEBI(kzembed));
}


static void
kz_khtml_go_forward (KzEmbed *kzembed)
{
	g_return_if_fail(KZ_IS_KHTML(kzembed));

	return webi_go_forward (WEBI(kzembed));
}


static gboolean
kz_khtml_can_go_back (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_KHTML(kzembed), FALSE);

	return webi_can_go_back (WEBI(kzembed));
}


static gboolean
kz_khtml_can_go_forward (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_KHTML(kzembed), FALSE);

	return webi_can_go_forward (WEBI(kzembed));
}


static gboolean
kz_khtml_can_go_nav_link (KzEmbed *kzembed, KzEmbedNavLink link)
{
	g_return_val_if_fail(KZ_IS_KHTML(kzembed), FALSE);

	return FALSE;
}

static void
kz_khtml_go_nav_link (KzEmbed *kzembed, KzEmbedNavLink link)
{
	g_return_if_fail(KZ_IS_KHTML(kzembed));

	return;
}

static void
kz_khtml_set_nth_nav_link (KzEmbed *kzembed,
			   KzEmbedNavLink link,
			   KzNavi *navi,
			   guint n)
{
	g_return_if_fail(KZ_IS_KHTML(kzembed));

	return;
}

static KzNavi *
kz_khtml_get_nth_nav_link (KzEmbed *kzembed,
			   KzEmbedNavLink link,
			   guint n)
{
	g_return_val_if_fail(KZ_IS_KHTML(kzembed), NULL);

	return NULL;
}

static GList *
kz_khtml_get_nav_links (KzEmbed *kzembed,
			KzEmbedNavLink link)
{
	g_return_val_if_fail(KZ_IS_KHTML(kzembed), NULL);

	return NULL;
}

static gdouble
kz_khtml_get_progress (KzEmbed *kzembed)
{
	gdouble progress;
	KzKHTML *khtml;
	KzKHTMLPrivate *priv;

	g_return_val_if_fail(KZ_IS_KHTML(kzembed), 0.0);

	priv = KZ_KHTML_GET_PRIVATE (kzembed);

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

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

	if (progress > 1.0)
		return 1.0;

	return progress;
}


static gint
kz_khtml_get_text_size (KzEmbed *kzembed)
{
	gfloat multiplier;

	g_return_val_if_fail(KZ_IS_KHTML(kzembed), 100);

	multiplier = webi_get_text_multiplier (WEBI(kzembed));
	
	if (multiplier == -1.0) return 100;

	return (gint) rint(multiplier * 100);
}


static void
kz_khtml_set_text_size (KzEmbed *kzembed, gint zoom, gboolean reflow)
{
	gfloat multiplier;

	g_return_if_fail(KZ_IS_KHTML(kzembed));

	multiplier = (gfloat)(zoom) / 100;

	webi_set_text_multiplier (WEBI(kzembed),
			               multiplier);
}


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

	return webi_find(WEBI(kzembed), keyword, FALSE, backward); 
}

static gboolean
kz_khtml_can_cut_selection (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_KHTML(kzembed), FALSE);

	/* not implemented yet */
	return FALSE;
}

static gboolean
kz_khtml_can_copy_selection (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_KHTML(kzembed), FALSE);
	/* not implemented yet */
	return FALSE;
}

static gboolean
kz_khtml_can_paste (KzEmbed *kzembed)
{
	g_return_val_if_fail(KZ_IS_KHTML(kzembed), FALSE);
	/* not implemented yet */
	return FALSE;
}

static void
kz_khtml_cut_selection (KzEmbed *kzembed)
{
	/* not implemented yet */
	return;
}

static void
kz_khtml_copy_selection (KzEmbed *kzembed)
{
	/* not implemented yet */
	return;
}

static void
kz_khtml_paste (KzEmbed *kzembed)
{
	/* not implemented yet */
	return;
}

static void
kz_khtml_select_all (KzEmbed *kzembed)
{
	/* not implemented yet */
	return;
}

