/* -*- 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 1800 2004-11-25 06:25:09Z ikezoe $
 */

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

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


struct _KzKHTMLPriv
{
	gint cur_requests;
	gint total_requests;
};

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

/* khtml class */
static void         kz_khtml_status           (GtkKHTML *khtml,
					       GtkKHTMLLoadStatus *status);
static void         kz_khtml_load_start       (GtkKHTML     *khtml);
static void         kz_khtml_load_stop        (GtkKHTML     *khtml);
static void         kz_khtml_location         (GtkKHTML     *khtml);
static void         kz_khtml_title            (GtkKHTML     *khtml);
static void         kz_khtml_progress         (GtkKHTML     *khtml,
					       gint          curprogress,
					       gint          maxprogress);
static void         kz_khtml_req_js_prompt    (GtkKHTML     *khtml,
					       GtkKHTMLPromptArgs* args);
static void         kz_khtml_req_auth_prompt  (GtkKHTML     *khtml,
					       GtkKHTMLAuthArgs* args);
static gboolean     kz_khtml_req_new_window   (GtkKHTML     *khtml,
					       GtkKHTML     *newkhtml);

/* 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);
#if 0
static gchar       *kz_khtml_get_link_message (KzEmbed      *kzembed);
#endif
static void         kz_khtml_reload           (KzEmbed      *kzembed,
					       gint32        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 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);

static GtkKHTMLClass *parent_class = NULL;


KZ_OBJECT_GET_TYPE_IFACE(kz_khtml, "KzKHTML", KzKHTML,
			 kz_khtml_class_init, kz_khtml_init,
			 GTK_TYPE_KHTML,
			 kz_khtml_iface_init, KZ_TYPE_EMBED)
KZ_OBJECT_FINALIZE(kz_khtml, KzKHTML)


static void
kz_khtml_class_init (KzKHTMLClass *klass)
{
	GObjectClass *object_class;
	GtkKHTMLClass *khtml_class;

	parent_class = g_type_class_peek_parent (klass);
	object_class = (GObjectClass *) klass;
	khtml_class  = (GtkKHTMLClass *) klass;

	object_class->dispose   = kz_khtml_dispose;
	object_class->finalize  = kz_khtml_finalize;

	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;
	khtml_class->progress   = kz_khtml_progress;
	
	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;
}


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       = NULL;/*kz_khtml_get_link_message*/;
	iface->get_progress           = kz_khtml_get_progress;
	iface->can_cut_selection      = NULL;
	iface->can_copy_selection     = NULL;
	iface->can_paste              = NULL;
	iface->cut_selection          = NULL;
	iface->copy_selection         = NULL;
	iface->paste                  = NULL;
	iface->select_all             = NULL;
	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->go_up                  = NULL; */
	iface->can_go_back            = kz_khtml_can_go_back;
	iface->can_go_forward         = kz_khtml_can_go_forward;
/*	iface->can_go_up              = NULL; */
	iface->can_go_nav_link        = NULL;
	iface->go_nav_link            = NULL;
	iface->set_nav_link           = NULL;
	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->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; 
#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)
{
	khtml->is_loading = FALSE;
	khtml->priv = g_new0(KzKHTMLPriv, 1);
	khtml->priv->cur_requests   = 0;
	khtml->priv->total_requests = 0;
}

static void
kz_khtml_dispose (GObject *object)
{
	if (G_OBJECT_CLASS (parent_class)->dispose)
		G_OBJECT_CLASS (parent_class)->dispose(object);
}


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 (GtkKHTML *khtml, GtkKHTMLLoadStatus *status)
{
	g_return_if_fail(KZ_IS_KHTML(khtml));
	g_return_if_fail(status);

	switch(status->status) {
	case GTK_KHTML_LOADING_START:
		KZ_KHTML(khtml)->is_loading = TRUE;
		KZ_KHTML(khtml)->priv->cur_requests = 0;
		KZ_KHTML(khtml)->priv->total_requests = 0;
		g_signal_emit_by_name(G_OBJECT(khtml), "kz-net-start");
		break;
	case GTK_KHTML_LOADING_COMPLETE:
	case GTK_KHTML_LOADING_ERROR:
		KZ_KHTML(khtml)->is_loading = FALSE;
		KZ_KHTML(khtml)->priv->cur_requests = status->totalReceived;
		KZ_KHTML(khtml)->priv->total_requests = status->totalSize;
		g_signal_emit_by_name(G_OBJECT(khtml), "kz-net-stop");
		break;
	default:
		break;
	}

	/* call parent method */
}


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

	KZ_KHTML(khtml)->is_loading = TRUE;

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

	/* call parent method */
}


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

	KZ_KHTML(khtml)->is_loading = FALSE;

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

	/* call parent method */
}


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

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

	/* call parent method */
}


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

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

	/* call parent method */
}


static void
kz_khtml_progress (GtkKHTML *khtml, gint curprogress, gint maxprogress)
{
	g_return_if_fail(KZ_IS_KHTML(khtml));

	KZ_KHTML(khtml)->priv->cur_requests = curprogress;
	KZ_KHTML(khtml)->priv->total_requests = maxprogress;
	
	g_signal_emit_by_name(G_OBJECT(khtml), "kz-progress");
}


static void
kz_khtml_req_js_prompt (GtkKHTML *khtml, GtkKHTMLPromptArgs* args)
{
	g_return_if_fail(KZ_IS_KHTML(khtml));
}


static void
kz_khtml_req_auth_prompt (GtkKHTML *khtml, GtkKHTMLAuthArgs* args)
{
	g_return_if_fail(KZ_IS_KHTML(khtml));
}


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


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

	gtk_khtml_load_url(GTK_KHTML(kzembed), url);
}


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

	return gtk_khtml_get_title(GTK_KHTML(kzembed));
}


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

	return gtk_khtml_get_location(GTK_KHTML(kzembed));
}


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

	return g_strdup(gtk_khtml_get_status_text(GTK_KHTML(kzembed)));
}
#endif


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

#warning FIXME! use flags
static void
kz_khtml_reload (KzEmbed *kzembed, gint32 flags)
{
	g_return_if_fail(KZ_IS_KHTML(kzembed));

	gtk_khtml_refresh (GTK_KHTML(kzembed));
}


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

	gtk_khtml_stop_load (GTK_KHTML(kzembed));
}


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

	return gtk_khtml_go_back (GTK_KHTML(kzembed));
}


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

	return gtk_khtml_go_forward (GTK_KHTML(kzembed));
}


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

	return gtk_khtml_can_go_back (GTK_KHTML(kzembed));
}


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

	return gtk_khtml_can_go_forward (GTK_KHTML(kzembed));
}


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

	g_return_val_if_fail(KZ_IS_KHTML(kzembed), 0.0);

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

	progress = (gdouble) khtml->priv->cur_requests
		/ (gdouble) khtml->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 = gtk_khtml_get_text_multiplier (GTK_KHTML(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;

	gtk_khtml_set_text_multiplier (GTK_KHTML(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 gtk_khtml_find(GTK_KHTML(kzembed), keyword, FALSE, backward); 
}
