/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 * Copyright (C) 2002-2003 CodeFactory AB
 * Copyright (C) 2001-2003 Mikael Hallendal <micke@imendio.com>
 * Copyright (C) 2004-2005 Imendio hB
 *
 * 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 of the
 * License, 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.
 */

#include <stdio.h>
#include <string.h>
#include <gtkmozembed.h>

#include "dh-util.h"
#include "dh-marshal.h"
#include "dh-gecko-utils.h"
#include "dh-preferences.h"
#include "dh-html.h"

#define d(x)

struct _DhHtmlPriv {
	GtkMozEmbed *gecko;
	Yelper      *yelper;
};

static void     html_class_init  (DhHtmlClass *klass);
static void     html_init        (DhHtml      *html);
static void     html_title_cb    (GtkMozEmbed *embed,
				  DhHtml      *html);
static void     html_location_cb (GtkMozEmbed *embed,
				  DhHtml      *html);
static gboolean html_open_uri_cb (GtkMozEmbed *embed,
				  const gchar *uri,
				  DhHtml      *html);


enum {
	TITLE_CHANGED,
	LOCATION_CHANGED,
	OPEN_URI,
	OPEN_NEW_TAB,
	LAST_SIGNAL
};

static gint signals[LAST_SIGNAL] = { 0 };

/* Has the value of the URL under the mouse pointer, otherwise NULL */
static gchar *current_url = NULL;

GType
dh_html_get_type (void)
{
        static GType type = 0;

        if (!type) {
                static const GTypeInfo info =
                        {
                                sizeof (DhHtmlClass),
                                NULL,
                                NULL,
				(GClassInitFunc) html_class_init,
                                NULL,
                                NULL,
                                sizeof (DhHtml),
                                0,
                                (GInstanceInitFunc) html_init,
                        };

                type = g_type_register_static (G_TYPE_OBJECT,
					       "DhHtml",
					       &info, 0);
        }

        return type;
}

static void
html_class_init (DhHtmlClass *klass)
{
	signals[TITLE_CHANGED] =
		g_signal_new ("title-changed",
			      G_TYPE_FROM_CLASS (klass),
			      G_SIGNAL_RUN_LAST,
			      0,
			      NULL, NULL,
			      dh_marshal_VOID__STRING,
			      G_TYPE_NONE,
			      1, G_TYPE_STRING);

	signals[LOCATION_CHANGED] =
		g_signal_new ("location-changed",
			      G_TYPE_FROM_CLASS (klass),
			      G_SIGNAL_RUN_LAST,
			      0,
			      NULL, NULL,
			      dh_marshal_VOID__STRING,
			      G_TYPE_NONE,
			      1, G_TYPE_STRING);
	signals[OPEN_URI] =
		g_signal_new ("open-uri",
			      G_TYPE_FROM_CLASS (klass),
			      G_SIGNAL_RUN_LAST,
			      0,
			      NULL, NULL,
			      dh_marshal_BOOLEAN__STRING,
			      G_TYPE_BOOLEAN,
			      1, G_TYPE_STRING);
	signals[OPEN_NEW_TAB] =
		g_signal_new ("open-new-tab",
			      G_TYPE_FROM_CLASS (klass),
			      G_SIGNAL_RUN_LAST,
			      0,
			      NULL, NULL,
			      dh_marshal_VOID__STRING,
			      G_TYPE_NONE,
			      1, G_TYPE_STRING);
}

static gboolean
html_mouse_click_cb (GtkMozEmbed *widget, gpointer dom_event, DhHtml *html)
{
	gint button;
	gint mask;

	button = dh_gecko_utils_get_mouse_event_button (dom_event);
	mask = dh_gecko_utils_get_mouse_event_modifiers (dom_event);

	if (button == 2 || (button == 1 && mask & GDK_CONTROL_MASK)) {
		if (current_url) {
			g_signal_emit (html,
				       signals[OPEN_NEW_TAB], 0,
				       current_url);
			return TRUE;
		}
	}

	return FALSE;
}

/* I'd like to get rid of this hack, there should be a way to get the URI that
 * was clicked instead of tracking it like this.
 */
static gboolean
html_link_message_cb (GtkMozEmbed *widget)
{
	if (current_url) {
		g_free (current_url);
	}
	current_url = gtk_moz_embed_get_link_message (widget);

	if (current_url[0] == '\0') {
		g_free (current_url);
		current_url = NULL;
	}

	return FALSE;
}

static void
html_child_grab_focus_cb (GtkWidget *widget, DhHtml *html)
{
        GdkEvent *event;

        event = gtk_get_current_event ();

        if (!event) {
                g_signal_stop_emission_by_name (widget, "grab-focus");
        } else {
                gdk_event_free (event);
        }
}

static void
html_child_add_cb (GtkMozEmbed *embed, GtkWidget *child, DhHtml *html)
{
	g_signal_connect (child, "grab-focus",
			  G_CALLBACK (html_child_grab_focus_cb),
			  html);
}

static void
html_child_remove_cb (GtkMozEmbed *embed, GtkWidget *child, DhHtml *html)
{
	g_signal_handlers_disconnect_by_func (child, html_child_grab_focus_cb, html);
}

static void
html_init (DhHtml *html)
{
        DhHtmlPriv *priv;

	priv = g_new0 (DhHtmlPriv, 1);

	priv->gecko = GTK_MOZ_EMBED (gtk_moz_embed_new ());

	g_signal_connect (priv->gecko, "title",
			  G_CALLBACK (html_title_cb),
			  html);
	g_signal_connect (priv->gecko, "location",
			  G_CALLBACK (html_location_cb),
			  html);
	g_signal_connect (priv->gecko, "open-uri",
			  G_CALLBACK (html_open_uri_cb),
			  html);
	g_signal_connect (priv->gecko, "dom_mouse_click",
			  G_CALLBACK (html_mouse_click_cb),
			  html);
	g_signal_connect (priv->gecko, "link_message",
			  G_CALLBACK (html_link_message_cb),
			  html);
	g_signal_connect (priv->gecko, "add",
			  G_CALLBACK (html_child_add_cb),
			  html);
	g_signal_connect (priv->gecko, "remove",
			  G_CALLBACK (html_child_remove_cb),
			  html);

	gtk_moz_embed_load_url (GTK_MOZ_EMBED (priv->gecko), "about:blank");

	priv->yelper = dh_gecko_utils_create_yelper (priv->gecko);

	html->priv = priv;
}

static void
html_title_cb (GtkMozEmbed *embed, DhHtml *html)
{
	char *new_title;

	new_title = gtk_moz_embed_get_title (embed);
	g_signal_emit (html, signals[TITLE_CHANGED], 0, new_title);
	g_free (new_title);
}

static void
html_location_cb (GtkMozEmbed *embed, DhHtml *html)
{
	DhHtmlPriv *priv;
	char       *location;

	priv = html->priv;

	location = gtk_moz_embed_get_location (embed);
	g_signal_emit (html, signals[LOCATION_CHANGED], 0, location);
	g_free (location);
}

static gboolean
html_open_uri_cb (GtkMozEmbed *embed, const gchar *uri, DhHtml *html)
{
	DhHtmlPriv *priv;
	gboolean   retval;

	priv = html->priv;

	retval = TRUE;

	g_signal_emit (html, signals[OPEN_URI], 0, uri, &retval);

	return retval;
}

DhHtml *
dh_html_new (void)
{
        DhHtml *html;

        html = g_object_new (DH_TYPE_HTML, NULL);

        return html;
}

void
dh_html_clear (DhHtml *html)
{
	DhHtmlPriv        *priv;
	static const char *data = "<html><body bgcolor=\"white\"></body></html>";

	g_return_if_fail (DH_IS_HTML (html));

	priv = html->priv;

	gtk_moz_embed_render_data (priv->gecko, data, strlen (data),
				   "file:///", "text/html");
}

void
dh_html_open_uri (DhHtml *html, const gchar *str_uri)
{
        DhHtmlPriv *priv;
	gchar      *full_uri;

	g_return_if_fail (DH_IS_HTML (html));
	g_return_if_fail (str_uri != NULL);

        priv = html->priv;

	if (str_uri[0] == '/') {
		full_uri = g_strdup_printf ("file://%s", str_uri);
	} else {
		full_uri = (gchar *) str_uri;
	}

	gtk_moz_embed_load_url (priv->gecko, full_uri);

	if (full_uri != str_uri) {
		g_free (full_uri);
	}
}


GtkWidget *
dh_html_get_widget (DhHtml *html)
{
	DhHtmlPriv *priv;

	g_return_val_if_fail (DH_IS_HTML (html), NULL);

	priv = html->priv;

	return GTK_WIDGET (priv->gecko);
}

gboolean
dh_html_can_go_forward (DhHtml *html)
{
	DhHtmlPriv *priv;

	g_return_val_if_fail (DH_IS_HTML (html), FALSE);

	priv = html->priv;

	return gtk_moz_embed_can_go_forward (priv->gecko);
}

gboolean
dh_html_can_go_back (DhHtml *html)
{
	DhHtmlPriv *priv;

	g_return_val_if_fail (DH_IS_HTML (html), FALSE);

	priv = html->priv;

	return gtk_moz_embed_can_go_back (priv->gecko);
}

void
dh_html_go_forward (DhHtml *html)
{
	DhHtmlPriv *priv;

	g_return_if_fail (DH_IS_HTML (html));

	priv = html->priv;

	gtk_moz_embed_go_forward (priv->gecko);
}

void
dh_html_go_back (DhHtml *html)
{
	DhHtmlPriv *priv;

	g_return_if_fail (DH_IS_HTML (html));

	priv = html->priv;

	gtk_moz_embed_go_back (priv->gecko);
}

gchar *
dh_html_get_title (DhHtml *html)
{
	DhHtmlPriv *priv;

	g_return_val_if_fail (DH_IS_HTML (html), NULL);

	priv = html->priv;

	return gtk_moz_embed_get_title (priv->gecko);
}

gchar *
dh_html_get_location (DhHtml *html)
{
	DhHtmlPriv *priv;

	g_return_val_if_fail (DH_IS_HTML (html), NULL);

	priv = html->priv;

	return gtk_moz_embed_get_location (priv->gecko);
}

void
dh_html_copy_selection (DhHtml *html)
{
	DhHtmlPriv *priv;

	g_return_if_fail (DH_IS_HTML (html));

	priv = html->priv;

	dh_gecko_utils_copy_selection (priv->gecko);
}

void
dh_html_search_find (DhHtml      *html,
		     const gchar *text)
{
	DhHtmlPriv *priv;

	g_return_if_fail (DH_IS_HTML (html));

	priv = html->priv;

	dh_gecko_utils_search_find (priv->yelper, text);
}

gboolean
dh_html_search_find_again (DhHtml   *html,
			   gboolean  backwards)
{
	DhHtmlPriv *priv;

	g_return_val_if_fail (DH_IS_HTML (html), FALSE);

	priv = html->priv;

	return dh_gecko_utils_search_find_again (priv->yelper, backwards);
}

void
dh_html_search_set_case_sensitive (DhHtml   *html,
				   gboolean  case_sensitive)
{
	DhHtmlPriv *priv;

	g_return_if_fail (DH_IS_HTML (html));

	priv = html->priv;

	dh_gecko_utils_search_set_case_sensitive (priv->yelper, case_sensitive);
}


syntax highlighted by Code2HTML, v. 0.9.1