/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 *  Copyright (C) 2008  g新部 Hiroyuki Ikezoe
 *
 *  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 implwebkit_gtkd 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 <glib/gi18n.h>

#include "kz-webkit-gtk.h"

#include <webkit/webkit.h>

#include "kz-embed.h"

enum {
    PROP_0,
    PROP_ENGINE_NAME
};

typedef struct _KzWebKitGtkPrivate	KzWebKitGtkPrivate;
struct _KzWebKitGtkPrivate
{
    WebKitWebView *web_view;
    gchar *link_message;
};
#define KZ_WEBKIT_GTK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), KZ_TYPE_WEBKIT_GTK, KzWebKitGtkPrivate))

static GType           kz_type_webkit_gtk = 0;
static GtkScrolledWindowClass *kz_webkit_gtk_parent_class;

GtkWidget  *kz_webkit_gtk_new          (void);
static void kz_webkit_gtk_class_init   (KzWebKitGtkClass *klass);
static void kz_webkit_gtk_iface_init   (KzEmbedIFace     *iface);
static void kz_webkit_gtk_init         (KzWebKitGtk      *webkit_gtk);

static GObject *constructor  (GType type,
                              guint n_props,
                              GObjectConstructParam *props);
static void     set_property (GObject      *object,
                              guint         prop_id,
                              const GValue *value,
                              GParamSpec   *pspec);
static void     get_property (GObject      *object,
                              guint         prop_id,
                              GValue       *value,
                              GParamSpec   *pspec);
static void 	finalize     (GObject *object);

static void	    load_uri               (KzEmbed      *kzembed,
                                        const gchar  *uri);
static void	    stop_load              (KzEmbed      *kzembed);
static void	    reload                 (KzEmbed      *kzembed,
                                        KzEmbedReloadFlag flags);
static void	    go_back                (KzEmbed      *kzembed);
static void	    go_forward             (KzEmbed      *kzembed);
static gboolean	can_go_back            (KzEmbed      *kzembed);
static gboolean	can_go_forward         (KzEmbed      *kzembed);
static gboolean can_go_nav_link	       (KzEmbed      *kzembed,
                                        KzEmbedNavLink link);
static KzNavi  *get_nth_nav_link       (KzEmbed      *kzembed,
                                        KzEmbedNavLink link,
                                        guint         n);
static GList   *get_nav_links	       (KzEmbed      *kzembed,
                                        KzEmbedNavLink link);
static gboolean can_cut_selection      (KzEmbed      *kzembed);
static gboolean can_copy_selection     (KzEmbed      *kzembed);
static gboolean can_paste              (KzEmbed      *kzembed);
static void	    cut_selection          (KzEmbed      *kzembed);
static void	    copy_selection         (KzEmbed      *kzembed);
static void	    paste                  (KzEmbed      *kzembed);
static void	    select_all             (KzEmbed      *kzembed);
static gboolean selection_is_collapsed (KzEmbed      *kzembed);
static void     zoom                   (KzEmbed      *kzembed,
                                        gdouble       zoom);
static gdouble  get_zoom_ratio         (KzEmbed      *kzembed);
static void     set_text_size          (KzEmbed      *kzembed,
                                        gdouble       size);
static gboolean	get_allow_javascript   (KzEmbed      *kzembed);
static void	    set_allow_javascript   (KzEmbed      *kzembed,
                                        gboolean      allow);
static gboolean	get_allow_images	   (KzEmbed      *kzembed);
static void	    set_allow_images	   (KzEmbed      *kzembed,
                                        gboolean      allow);
static void	    set_history            (KzEmbed      *kzembed,
                                        const GList  *history,
                                        guint         current_position);
static void	    get_history            (KzEmbed      *kzembed,
                                        GList       **history,
                                        guint        *current_position);
static void     copy_page              (KzEmbed      *src_embed,
                                        KzEmbed      *dest_embed);
static gboolean shistory_get_pos       (KzEmbed      *kzembed,
                                        gint         *pos,
                                        gint         *count);
static void     shistory_get_nth       (KzEmbed      *kzembed,
                                        gint          nth,
                                        gboolean      is_relative,
                                        gchar       **uri,
                                        gchar       **title);
static gboolean	find                   (KzEmbed	 *kzembed,
                                        const char   *keyword,
                                        gboolean      backward);
static void	    cb_title_changed       (WebKitWebView* web_view,
                                        WebKitWebFrame* web_frame,
                                        const gchar* title,
                                        gpointer data);
static void	    cb_progress_changed    (WebKitWebView* web_view,
                                        gint progress,
                                        gpointer data);
static void	    cb_load_committed      (WebKitWebView* web_view,
                                        WebKitWebFrame* frame,
                                        gpointer data);
static void	    cb_load_started        (WebKitWebView* web_view,
                                        WebKitWebFrame* frame,
                                        gpointer data);
static void	    cb_load_finished       (WebKitWebView* web_view,
                                        WebKitWebFrame* frame,
                                        gpointer data);
static void	    cb_hover_link          (WebKitWebView* web_view,
                                        const gchar *title,
                                        const gchar *location,
                                        gpointer data);
static void     cb_populate_popup      (WebKitWebView* web_view,
                                        GtkMenu *menu,
                                        gpointer data);
static gboolean cb_navigation_policy_decision_requested
                                       (WebKitWebView* web_view,
                                        WebKitWebFrame *frame,
                                        WebKitNetworkRequest *request,
                                        WebKitWebNavigationAction *action,
                                        WebKitWebPolicyDecision *decision,
                                        gpointer data);
static gboolean cb_button_press_event  (GtkWidget *widget,
                                        GdkEventButton *event,
                                        gpointer data);
static gboolean cb_button_release_event(GtkWidget *widget,
                                        GdkEventButton *event,
                                        gpointer data);

static void     set_default_preferences(KzWebKitGtk *webkit);

void
kz_webkit_gtk_register_type (GTypeModule *module)
{
    static const GTypeInfo kz_webkit_gtk_info = {
        sizeof (KzWebKitGtkClass),
        NULL,		/* base_init */
        NULL,		/* base_finalize */
        (GClassInitFunc) kz_webkit_gtk_class_init,
        NULL,		/* class_finalize */
        NULL,		/* class_data */
        sizeof (KzWebKitGtk),
        0,		/* n_preallocs */
        (GInstanceInitFunc) kz_webkit_gtk_init,
    };

    const GInterfaceInfo kz_embed_info = {
        (GInterfaceInitFunc) kz_webkit_gtk_iface_init,
        NULL,
        NULL
    };

    kz_type_webkit_gtk = g_type_module_register_type(module,
                                                     GTK_TYPE_SCROLLED_WINDOW,
                                                     "KzWebKitGtk",
                                                     &kz_webkit_gtk_info,
                                                     (GTypeFlags)0);

    g_type_module_add_interface(module,
                                KZ_TYPE_WEBKIT_GTK,
                                KZ_TYPE_EMBED,
                                &kz_embed_info);
}

GType
kz_webkit_gtk_get_type (void)
{
    return kz_type_webkit_gtk;
}

static void
kz_webkit_gtk_class_init (KzWebKitGtkClass *klass)
{
    GObjectClass *object_class;

    kz_webkit_gtk_parent_class = GTK_SCROLLED_WINDOW_CLASS(g_type_class_peek_parent(klass));
    object_class = G_OBJECT_CLASS(klass);

    object_class->get_property = get_property;
    object_class->set_property = set_property;
    object_class->finalize = finalize;
    object_class->constructor = constructor;

    g_object_class_override_property(object_class, PROP_ENGINE_NAME, "engine-name");
    g_type_class_add_private(object_class, sizeof(KzWebKitGtkPrivate));
}

    static void
kz_webkit_gtk_iface_init (KzEmbedIFace *iface)
{
    iface->load_uri               = load_uri;
    iface->view_source            = NULL;
    iface->view_current_page_source_in_new
                                  = NULL;
    iface->can_cut_selection      = can_cut_selection;
    iface->can_copy_selection     = can_copy_selection;
    iface->can_paste              = can_paste;
    iface->cut_selection          = cut_selection;
    iface->copy_selection         = copy_selection;
    iface->paste                  = paste;
    iface->select_all             = select_all;
    iface->get_selection_string   = NULL;
    iface->find                   = find;
    iface->incremental_search     = find;
    iface->selection_is_collapsed = selection_is_collapsed;
    iface->get_links              = NULL;
    iface->copy_page              = copy_page;
    iface->shistory_get_pos       = shistory_get_pos;
    iface->shistory_get_nth       = shistory_get_nth;
    iface->reload                 = reload;
    iface->stop_load              = stop_load;
    iface->go_back                = go_back;
    iface->go_forward             = go_forward;
    iface->can_go_back            = can_go_back;
    iface->can_go_forward         = can_go_forward;
    iface->can_go_nav_link        = can_go_nav_link;
    iface->go_nav_link            = NULL;
    iface->append_nav_link        = NULL;
    iface->set_nav_link           = NULL;
    iface->set_nth_nav_link       = NULL;
    iface->get_nav_link           = NULL;
    iface->get_nth_nav_link       = get_nth_nav_link;
    iface->get_nav_links          = get_nav_links;
    iface->go_history_index       = NULL;
    iface->get_body_text          = NULL;
    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                   = zoom;
    iface->get_zoom_ratio         = get_zoom_ratio;
    iface->set_text_size          = set_text_size;
    iface->get_text_size          = get_zoom_ratio;
    iface->get_html_with_contents = NULL;
    iface->set_history            = set_history;
    iface->get_history            = get_history;
    iface->get_last_modified      = NULL;
    iface->fine_scroll            = NULL;
    iface->page_up                = NULL;
    iface->page_down              = NULL; 
    iface->get_allow_javascript   = get_allow_javascript;
    iface->set_allow_javascript   = set_allow_javascript; 
    iface->get_allow_images       = get_allow_images;
    iface->set_allow_images       = set_allow_images;
}

static void
setup_webkit_web_view (KzWebKitGtk *webkit)
{
    KzWebKitGtkPrivate *priv = KZ_WEBKIT_GTK_GET_PRIVATE(webkit);

    priv->web_view = WEBKIT_WEB_VIEW(webkit_web_view_new());
    gtk_container_add(GTK_CONTAINER(webkit), GTK_WIDGET(priv->web_view));

    g_signal_connect(priv->web_view, "title-changed",
            G_CALLBACK(cb_title_changed), webkit);
    g_signal_connect(priv->web_view, "load-progress-changed",
            G_CALLBACK(cb_progress_changed), webkit);
    g_signal_connect(priv->web_view, "load-committed",
            G_CALLBACK(cb_load_committed), webkit);
    g_signal_connect(priv->web_view, "load-started",
            G_CALLBACK(cb_load_started), webkit);
    g_signal_connect(priv->web_view, "load-finished",
            G_CALLBACK(cb_load_finished), webkit);
    g_signal_connect(priv->web_view, "hovering-over-link",
            G_CALLBACK(cb_hover_link), webkit);
    g_signal_connect(priv->web_view, "populate-popup",
            G_CALLBACK(cb_populate_popup), webkit);
    g_signal_connect(priv->web_view, "navigation-policy-decision-requested",
            G_CALLBACK(cb_navigation_policy_decision_requested), webkit);
    g_signal_connect(priv->web_view, "button-press-event",
            G_CALLBACK(cb_button_press_event), webkit);
    g_signal_connect(priv->web_view, "button-release-event",
            G_CALLBACK(cb_button_release_event), webkit);
    set_default_preferences(webkit);
}

static void
set_property (GObject         *object,
              guint            prop_id,
              const GValue    *value,
              GParamSpec      *pspec)
{
    switch (prop_id) {
    case PROP_ENGINE_NAME:
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
        break;
    }
}


static void
get_property (GObject         *object,
              guint            prop_id,
              GValue          *value,
              GParamSpec      *pspec)
{
    switch (prop_id) {
    case PROP_ENGINE_NAME:
        g_value_set_string(value, "webkit_gtk");
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
        break;
    }
}

static GObject*
constructor (GType                  type,
        guint                  n_props,
        GObjectConstructParam *props)
{
    GObject *object;
    GObjectClass *klass = G_OBJECT_CLASS(kz_webkit_gtk_parent_class);

    object = klass->constructor(type, n_props, props);
    setup_webkit_web_view(KZ_WEBKIT_GTK(object));

    return object;
}

static void
kz_webkit_gtk_init (KzWebKitGtk *webkit)
{
    KzWebKitGtkPrivate *priv = KZ_WEBKIT_GTK_GET_PRIVATE(webkit);

    priv->link_message = NULL;
}

static void
finalize (GObject *object)
{
    KzWebKitGtkPrivate *priv = KZ_WEBKIT_GTK_GET_PRIVATE(object);
    g_free(priv->link_message);

    if (G_OBJECT_CLASS(kz_webkit_gtk_parent_class)->finalize)
        G_OBJECT_CLASS(kz_webkit_gtk_parent_class)->finalize(object);
}

GtkWidget *
kz_webkit_gtk_new (void)
{
    return GTK_WIDGET(g_object_new(KZ_TYPE_WEBKIT_GTK,
                                   "hadjustment", NULL,
                                   "vadjustment", NULL,
                                   "hscrollbar-policy", GTK_POLICY_AUTOMATIC,
                                   "vscrollbar-policy", GTK_POLICY_AUTOMATIC,
                                   NULL));
}

static void
load_uri (KzEmbed *kzembed, const gchar  *uri)
{
    webkit_web_view_open(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view, uri);
}

static void
reload (KzEmbed *kzembed, KzEmbedReloadFlag flags)
{
    if (flags > 0)
        webkit_web_view_reload_bypass_cache(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view);
    else
        webkit_web_view_reload(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view);
}

static void
stop_load (KzEmbed *kzembed)
{
    webkit_web_view_stop_loading(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view);
}

static void
go_back (KzEmbed *kzembed)
{
    webkit_web_view_go_back(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view);
}

static void
go_forward (KzEmbed *kzembed)
{
    webkit_web_view_go_forward(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view);
}

static gboolean
can_go_back (KzEmbed *kzembed)
{
    return webkit_web_view_can_go_back(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view);
}

static gboolean
can_go_forward (KzEmbed *kzembed)
{
    return webkit_web_view_can_go_forward(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view);
}

static gboolean
can_cut_selection (KzEmbed *kzembed)
{
    return webkit_web_view_can_cut_clipboard(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view);
}

static gboolean
can_copy_selection (KzEmbed *kzembed)
{
    return webkit_web_view_can_copy_clipboard(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view);
}

    static gboolean
can_paste (KzEmbed *kzembed)
{
    return webkit_web_view_can_paste_clipboard(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view);
}

static void
cut_selection (KzEmbed *kzembed)
{
    webkit_web_view_cut_clipboard(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view);
}

static void
copy_selection (KzEmbed *kzembed)
{
    webkit_web_view_copy_clipboard(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view);
}

static void
paste (KzEmbed *kzembed)
{
    webkit_web_view_paste_clipboard(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view);
}

static void
select_all (KzEmbed *kzembed)
{
    webkit_web_view_select_all(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view);
}

static gboolean
selection_is_collapsed (KzEmbed *kzembed)
{
    return webkit_web_view_has_selection(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view);
}

static void
zoom (KzEmbed *kzembed, gdouble zoom)
{
    webkit_web_view_set_full_content_zoom(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view, TRUE);
    webkit_web_view_set_zoom_level(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view,
                                   zoom);
}

static gdouble
get_zoom_ratio (KzEmbed *kzembed)
{
    return webkit_web_view_get_zoom_level(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view);
}

static void
set_text_size (KzEmbed *kzembed, gdouble text_size)
{
    webkit_web_view_set_full_content_zoom(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view, FALSE);
    webkit_web_view_set_zoom_level(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view,
                                   text_size);
}

static gboolean
get_allow_javascript (KzEmbed *kzembed)
{
    WebKitWebSettings *settings;
    gboolean allow;

    settings = webkit_web_view_get_settings(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view);
    if (!settings)
        return FALSE;

    g_object_get(settings, "enable-scripts", &allow, NULL);

    return allow;
}

static void
set_allow_javascript (KzEmbed *kzembed, gboolean allow)
{
    WebKitWebSettings *settings;

    settings = webkit_web_view_get_settings(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view);
    if (!settings)
        return;

    g_object_set(settings, "enable-scripts", allow, NULL);
}

static gboolean
get_allow_images (KzEmbed *kzembed)
{
    WebKitWebSettings *settings;
    gboolean allow;

    settings = webkit_web_view_get_settings(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view);
    if (!settings)
        return FALSE;

    g_object_get(settings, "auto-load-images", &allow, NULL);

    return allow;
}

    static void
set_allow_images (KzEmbed *kzembed, gboolean allow)
{
    WebKitWebSettings *settings;

    settings = webkit_web_view_get_settings(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view);
    if (!settings)
        return;

    g_object_set(settings, "auto-load-images", allow, NULL);
}

static gboolean
can_go_nav_link (KzEmbed *kzembed, KzEmbedNavLink link)
{
    return FALSE;
}

static KzNavi *
get_nth_nav_link (KzEmbed *kzembed, KzEmbedNavLink link,
        guint n)
{
    return NULL;
}

static GList *
get_nav_links (KzEmbed *kzembed, KzEmbedNavLink link)
{
    return NULL;
}

static void
merge_item_to_history (GList **history, WebKitWebHistoryItem *item)
{
    KzSite *site;
    site = kz_site_new(webkit_web_history_item_get_title(item),
                       webkit_web_history_item_get_uri(item));
    *history = g_list_append(*history, site);
}

static void
merge_history_items_to_history (GList **history, GList *items)
{
    GList *node;
    for (node = items; node; node = g_list_next(node)) {
        if (!node->data)
            continue;
        merge_item_to_history(history, WEBKIT_WEB_HISTORY_ITEM(node->data));
    }
}

static WebKitWebHistoryItem *
ensure_current_item (KzEmbed *kzembed)
{
    WebKitWebBackForwardList *list;
    WebKitWebHistoryItem *current_item = NULL;
    KzWebKitGtkPrivate *priv = KZ_WEBKIT_GTK_GET_PRIVATE(kzembed);

    list = webkit_web_view_get_back_forward_list(priv->web_view);
    if (list)
        current_item = webkit_web_back_forward_list_get_current_item(list);

    if (!current_item) {
        current_item = webkit_web_history_item_new_with_data(webkit_web_view_get_uri(priv->web_view),
                                                             webkit_web_view_get_title(priv->web_view));
    }

    return current_item;
}

static void
get_history (KzEmbed *kzembed, GList **history, guint *current_position)
{
    GList *backward_items, *forward_items;
    WebKitWebBackForwardList *list;
    WebKitWebHistoryItem *current_item;

    list = webkit_web_view_get_back_forward_list(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view);
    if (!list)
        return;

    backward_items = webkit_web_back_forward_list_get_back_list_with_limit(list, 99);
    forward_items = webkit_web_back_forward_list_get_forward_list_with_limit(list, 99);
    current_item = ensure_current_item(kzembed);

    merge_history_items_to_history(history, backward_items);
    merge_item_to_history(history, current_item);
    merge_history_items_to_history(history, forward_items);
    *current_position = g_list_length(backward_items);

    g_list_free(backward_items);
    g_list_free(forward_items);
}

static void
set_history (KzEmbed *kzembed, const GList *history, guint current_position)
{
    WebKitWebBackForwardList *list;
    WebKitWebHistoryItem *item;
    GList *node;
    gint total = 0;

    list = webkit_web_view_get_back_forward_list(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view);
    if (!list)
        return;

    for (node = g_list_first((GList*)history); node; node = g_list_next (node)) {
        KzSite *site = (KzSite*)node->data;

        item = webkit_web_history_item_new_with_data(site->uri, site->title);
        webkit_web_back_forward_list_add_item(list, item);
        total++;
    }

    item  = webkit_web_back_forward_list_get_nth_item(list, current_position - total + 1);
    webkit_web_view_go_to_back_forward_item(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view, item);
}

static void
copy_page (KzEmbed *src_embed, KzEmbed *dest_embed)
{
    WebKitWebBackForwardList *src_list, *dest_list;
    WebKitWebHistoryItem *current_item = NULL;
    gint length, i, current_position;

    src_list = webkit_web_view_get_back_forward_list(KZ_WEBKIT_GTK_GET_PRIVATE(src_embed)->web_view);
    if (!src_list)
        return;
    dest_list = webkit_web_view_get_back_forward_list(KZ_WEBKIT_GTK_GET_PRIVATE(dest_embed)->web_view);
    if (!dest_list)
        return;

    /* Remove all items in dest list. */
    webkit_web_back_forward_list_set_limit(dest_list, 0);

    length = webkit_web_back_forward_list_get_back_length(src_list);
    current_position = length;
    length += webkit_web_back_forward_list_get_forward_length(src_list);
    length++;

    webkit_web_back_forward_list_set_limit(dest_list, 100);
    for (i = 0; i < length; i++) {
        WebKitWebHistoryItem *item;
        item = webkit_web_back_forward_list_get_nth_item(src_list, i);
        webkit_web_back_forward_list_add_item(dest_list, item);
        if (i == current_position)
            current_item = item;
    }
    if (current_item) {
        webkit_web_view_go_to_back_forward_item(KZ_WEBKIT_GTK_GET_PRIVATE(dest_embed)->web_view,
                current_item);
    }

}

static gboolean
shistory_get_pos (KzEmbed *kzembed, gint *pos, gint *count)
{
    WebKitWebBackForwardList *list;

    list = webkit_web_view_get_back_forward_list(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view);
    if (!list)
        return FALSE;

    *pos = webkit_web_back_forward_list_get_back_length(list);
    *count = *pos + webkit_web_back_forward_list_get_forward_length(list);

    return TRUE;
}

static void
shistory_get_nth (KzEmbed *kzembed, 
                  gint nth,
                  gboolean is_relative,
                  gchar **uri,
                  gchar **title)
{
    WebKitWebBackForwardList *list;
    WebKitWebHistoryItem *item;
    gint back_length;

    list = webkit_web_view_get_back_forward_list(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view);
    if (!list)
        return;
    back_length = webkit_web_back_forward_list_get_back_length(list);
    if (!is_relative)
        nth -= back_length;

    item = webkit_web_back_forward_list_get_nth_item(list, nth);
    if (!item)
        return;

    *uri = g_strdup(webkit_web_history_item_get_uri(item));
    *title = g_strdup(webkit_web_history_item_get_title(item));
}

static gboolean
find (KzEmbed *kzembed, const char *keyword, gboolean backward)
{
    return webkit_web_view_search_text(KZ_WEBKIT_GTK_GET_PRIVATE(kzembed)->web_view,
                                       keyword,
                                       FALSE,
                                       !backward,
                                       TRUE);
}

static void
cb_title_changed (WebKitWebView* web_view,
                  WebKitWebFrame* web_frame,
                  const gchar* title,
                  gpointer data)
{
    g_signal_emit_by_name(data, "kz-title", title);
}

static void
cb_progress_changed (WebKitWebView* web_view,
                     gint progress,
                     gpointer data)
{
    g_signal_emit_by_name(data, "kz-progress", progress / 100);
}

static void
cb_load_committed (WebKitWebView* web_view,
                   WebKitWebFrame* frame,
                   gpointer data)
{
    const gchar* location = webkit_web_frame_get_uri(frame);
    g_signal_emit_by_name(data, "kz-location", location);
}

static void
cb_load_started (WebKitWebView* web_view,
                 WebKitWebFrame* frame,
                 gpointer data)
{
    g_signal_emit_by_name(data, "kz-net-start");
}

static void
cb_load_finished (WebKitWebView* web_view,
                  WebKitWebFrame* frame,
                  gpointer data)
{
    g_signal_emit_by_name(data, "kz-net-stop");
}

static void
cb_hover_link (WebKitWebView* web_view,
               const gchar *title,
               const gchar *location,
               gpointer data)
{
    KzWebKitGtkPrivate *priv = KZ_WEBKIT_GTK_GET_PRIVATE(data);

    g_free(priv->link_message);
    priv->link_message = g_strdup(location);

    g_signal_emit_by_name(data, "kz-link-message", priv->link_message);
}

static gboolean
cb_navigation_policy_decision_requested (WebKitWebView* web_view,
                                         WebKitWebFrame *frame,
                                         WebKitNetworkRequest *request,
                                         WebKitWebNavigationAction *action,
                                         WebKitWebPolicyDecision *decision,
        gpointer data)
{
    WebKitWebNavigationReason reason;
    gint button;

    reason = webkit_web_navigation_action_get_reason(action);
    button = webkit_web_navigation_action_get_button(action);

    if (reason == WEBKIT_WEB_NAVIGATION_REASON_LINK_CLICKED &&
        button == 2) {
        const char *uri;
        KzEmbed *embed = NULL;

        g_signal_emit_by_name(data, "kz-new-window", &embed);
        uri = webkit_network_request_get_uri(request);
        kz_embed_load_uri(embed, uri);

        return TRUE;
    }

    return FALSE;
}

static KzEmbedEventMouse *
create_kz_embed_event_mouse (GdkEventButton *event,
                             KzEmbedEventContext context)
{
    KzEmbedEventMouse *kzevent;

    kzevent = (KzEmbedEventMouse *) kz_embed_event_new(KZ_EMBED_EVENT_MOUSE);
    if (event->state & GDK_SHIFT_MASK)
        kzevent->modifier |= KZ_SHIFT_KEY;
    if (event->state & GDK_CONTROL_MASK)
        kzevent->modifier |= KZ_CTRL_KEY;
    if (event->state & GDK_MOD1_MASK)
        kzevent->modifier |= KZ_ALT_KEY;
    if (event->state & GDK_META_MASK)
        kzevent->modifier |= KZ_META_KEY;
    kzevent->x = event->x;
    kzevent->y = event->y;
    switch (event->button) {
    case 1:
        kzevent->button = 1;
        break;
    case 2:
        kzevent->button = 3;
        break;
    case 3:
        kzevent->button = 2;
        break;
    }
    kzevent->cinfo.context = context;

    return kzevent;
}

static gboolean
cb_button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer data)
{
    KzEmbedEventMouse *kzevent;
    gint ret = FALSE;

    kzevent = create_kz_embed_event_mouse(event, KZ_CONTEXT_NONE);
    g_signal_emit_by_name(data, "kz-dom-mouse-down", kzevent, &ret);
    kz_embed_event_free((KzEmbedEvent *) kzevent);

    return ret;
}

static gboolean
cb_button_release_event (GtkWidget *widget, GdkEventButton *event, gpointer data)
{
    KzEmbedEventMouse *kzevent;
    gint ret = FALSE;

    kzevent = create_kz_embed_event_mouse(event, KZ_CONTEXT_NONE);
    g_signal_emit_by_name(data, "kz-dom-mouse-up", kzevent, &ret);
    kz_embed_event_free((KzEmbedEvent *) kzevent);

    return ret;
}

static void
cb_remove_menu_item (GtkWidget *menu_item, gpointer data)
{
    GtkContainer *container = GTK_CONTAINER(data);
    gtk_container_remove(container, menu_item);
}

static KzEmbedEventContext
get_event_context_from_menu (GtkMenu *menu)
{
    GList *menu_items;
    GtkWidget *first_item;
    GtkWidget *label;
    const gchar *label_text;

    menu_items = gtk_container_get_children(GTK_CONTAINER(menu));
    if (!menu_items)
        return KZ_CONTEXT_NONE;
    first_item = GTK_WIDGET(menu_items->data);
    g_list_free(menu_items);

    label = gtk_bin_get_child(GTK_BIN(first_item));
    label_text = gtk_label_get_text(GTK_LABEL(label));

    if (g_str_equal(label_text, "Open Image in New Window")) {
        return KZ_CONTEXT_IMAGE;
    } else if (g_str_equal(label_text, "Open Link")) {
        return KZ_CONTEXT_LINK;
    }
    return KZ_CONTEXT_NONE;
}

static void
cb_populate_popup (WebKitWebView* web_view,
                   GtkMenu *menu,
                   gpointer data)
{
    KzEmbedEventMouse *kzevent;
    KzEmbedEventContext context;
    GdkEventButton *gdk_event;
    gboolean ret;
    gint x, y;

    context = get_event_context_from_menu(menu);

    gtk_container_forall(GTK_CONTAINER(menu),
                         cb_remove_menu_item, menu);

    gdk_event = ((GdkEventButton*)gdk_event_new(GDK_BUTTON_RELEASE));
    gtk_widget_get_pointer(GTK_WIDGET(web_view),
                           &x, &y);
    gdk_event->x = (gdouble)x;
    gdk_event->y = (gdouble)y;
    gdk_event->button = 3;
    kzevent = create_kz_embed_event_mouse(gdk_event, context);
    if (context & KZ_CONTEXT_LINK) {
        KzWebKitGtkPrivate *priv = KZ_WEBKIT_GTK_GET_PRIVATE(data);
        kzevent->cinfo.link = g_strdup(priv->link_message);
    }

    g_signal_emit_by_name(data, "kz-dom-mouse-down", kzevent, &ret);
    g_signal_emit_by_name(data, "kz-dom-mouse-up", kzevent, &ret);
    kz_embed_event_free((KzEmbedEvent *) kzevent);
    gdk_event_free((GdkEvent*)gdk_event);
}

static void
set_font_preferences (KzProfile *profile, WebKitWebSettings *settings)
{
    /* font settings */
    GList *list, *node;
    gint size_variable = -1, size_fixed = -1;
    gint min_size_variable = -1, min_size_fixed = -1;
    gchar langs[1024], *lang = NULL;
    gchar *serif_font, *sans_font, *mono_font;
    double dpi_pixel_ratio = 72.0 / 96.0;

    /* workaround */
    if (kz_profile_get_value(profile, "Language", "accept_languages", 
                             &langs, G_N_ELEMENTS(langs),
                             KZ_PROFILE_VALUE_TYPE_STRING)) {
        gchar **split_str;
        split_str = g_strsplit(langs, ",", 1);

        if (split_str[0]) {
            lang = g_strdup(split_str[0]);
            g_strfreev(split_str);
        }
    }
    if (!lang)
        lang = g_strdup("");

    serif_font = g_strdup_printf("name_serif_%s", lang);
    sans_font = g_strdup_printf("name_sans-serif_%s", lang);
    mono_font = g_strdup_printf("name_monospace_%s", lang);

    list = kz_profile_enum_key(profile, "Font", TRUE);
    for (node = list; node; node = g_list_next(node)) {
        const gchar *key = (const gchar*)node->data;

        if (!key || !*key)
            continue;
        if (g_str_has_prefix(key, "size_variable_")) {
            gint value;
            kz_profile_get_value(profile, "Font", key,
                                 &value, sizeof(value),
                                 KZ_PROFILE_VALUE_TYPE_INT);
            if (value > size_variable)
                size_variable = value;
        } else if (g_str_has_prefix(key, "size_fixed_")) {
            gint value;
            kz_profile_get_value(profile, "Font", key,
                                 &value, sizeof(value),
                                 KZ_PROFILE_VALUE_TYPE_INT);
            if (value > size_fixed)
                size_fixed = value;
        } else if (g_str_has_prefix(key, "min-size_variable_")) {
            gint value;
            kz_profile_get_value(profile, "Font", key,
                                 &value, sizeof(value),
                                 KZ_PROFILE_VALUE_TYPE_INT);
            if (value > min_size_variable)
                min_size_variable = value;
        } else if (g_str_has_prefix(key, "min-size_fixed_")) {
            gint value;
            kz_profile_get_value(profile, "Font", key,
                                 &value, sizeof(value),
                                 KZ_PROFILE_VALUE_TYPE_INT);
            if (value > min_size_fixed)
                min_size_fixed = value;
        } else if (!strcmp(key, serif_font)) {
            gchar value[1024];
            kz_profile_get_value(profile, "Font", key,
                                 &value, strlen(value)+1,
                                 KZ_PROFILE_VALUE_TYPE_STRING);
            g_object_set(settings,
                         "serif-font-family", value,
                         "default-font-family", value,
                         NULL);
        } else if (!strcmp(key, sans_font)) {
            gchar value[1024];
            kz_profile_get_value(profile, "Font", key,
                                 &value, strlen(value)+1,
                                 KZ_PROFILE_VALUE_TYPE_STRING);
            g_object_set(settings,
                         "sans-serif-font-family", value,
                         NULL);
        } else if (!strcmp(key, mono_font)) {
            gchar value[1024];
            kz_profile_get_value(profile, "Font", key,
                                 &value, strlen(value)+1,
                                 KZ_PROFILE_VALUE_TYPE_STRING);
            g_object_set(settings,
                         "monospace-font-family", value,
                         NULL);
        }
    }
    g_list_free(list);
    g_free(serif_font);
    g_free(sans_font);
    g_free(mono_font);

    if (size_variable >= 0)
        g_object_set(settings, "default-font-size", (gint)(size_variable * dpi_pixel_ratio), NULL);
    if (size_fixed >= 0)
        g_object_set(settings, "default-monospace-font-size", (gint)(size_fixed * dpi_pixel_ratio), NULL);
    if (min_size_variable >= 0)
        g_object_set(settings, "minimum-font-size", (gint)(min_size_variable * dpi_pixel_ratio), NULL);
    if (min_size_fixed >= 0)
        g_object_set(settings, "minimum-logical-font-size", (gint)(min_size_fixed * dpi_pixel_ratio), NULL);
}

    static void
set_default_preferences (KzWebKitGtk *webkit)
{
    KzProfile *profile = KZ_GET_GLOBAL_PROFILE;
    gchar value[1024];

    WebKitWebSettings *settings;
    settings = webkit_web_view_get_settings(KZ_WEBKIT_GTK_GET_PRIVATE(webkit)->web_view);
    if (!settings)
        return;

    if (kz_profile_get_value(profile, "Language", "charset_default",
                             &value, G_N_ELEMENTS(value),
                             KZ_PROFILE_VALUE_TYPE_STRING)) {
        g_object_set(settings, "default-encoding", value, NULL);
    }

    set_font_preferences (profile, settings);

    g_object_set(settings,
                 "enable-plugins", TRUE,
                 "enable-scripts", TRUE,
                 "auto-load-images", TRUE,
                 NULL);
}

/*
vi:ts=4:nowrap:ai:expandtab:sw=4
 */
