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

//
//  Copyright (C) 2007 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 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.
//

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif /* HAVE_CONFIG_H */

#include <mozilla-config.h>
#include <glib/gi18n.h>
#include "kz-gecko-single.h"
#include "kz-app.h"
#include "mozilla.h"
#include "mozilla-prefs.h"
#include "utils/utils.h"

enum
{
	PROP_0,
	PROP_KZ_APP
};

typedef struct _KzGeckoSinglePrivate	KzGeckoSinglePrivate;
struct _KzGeckoSinglePrivate
{
	KzApp *kz_app;
};

#define KZ_GECKO_SINGLE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), KZ_TYPE_GECKO_SINGLE, KzGeckoSinglePrivate))

static GObject *constructor  (GType type,
                              guint n_props,
                              GObjectConstructParam *props);
static void     dispose      (GObject *object);
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 cb_global_profile_changed (KzProfile *profile,
				       const gchar *section,
				       const gchar *key,
				       const gchar *old_value,
				       gpointer data);
static void cb_font_profile_changed   (KzProfile *profile,
				       const gchar *section,
				       const gchar *key,
				       const gchar *old_value,
				       gpointer data);
static void cb_lang_profile_changed   (KzProfile *profile,
				       const gchar *section,
				       const gchar *key,
				       const gchar *old_value,
				       gpointer data);
static void cb_privacy_profile_changed(KzProfile *profile,
				       const gchar *section,
				       const gchar *key,
				       const gchar *old_value,
				       gpointer data);

static void set_user_agent (KzProfile *profile);

static KzGeckoSingle    *the_kz_gecko_single = NULL;

G_DEFINE_TYPE(KzGeckoSingle, kz_gecko_single, G_TYPE_OBJECT)

static void
kz_gecko_single_class_init (KzGeckoSingleClass *klass)
{
	GObjectClass *object_class;

	object_class = G_OBJECT_CLASS(klass);

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

	g_object_class_install_property(
		object_class,
		PROP_KZ_APP,
		g_param_spec_object ("kz-app",
				      _("KzApp"),
				      _("The KzApp object"),
				      KZ_TYPE_APP,
				     (GParamFlags)  (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
	g_type_class_add_private(object_class, sizeof(KzGeckoSinglePrivate));
}

static GObject *
constructor (GType                  type,
             guint                  n_props,
             GObjectConstructParam *props)
{
	GObject *object;
	GObjectClass *klass;
	KzGeckoSinglePrivate *priv;
	KzProfile *profile;

	if (the_kz_gecko_single) 
		return G_OBJECT(g_object_ref(the_kz_gecko_single));

	klass = G_OBJECT_CLASS(kz_gecko_single_parent_class);
	object = klass->constructor(type, n_props, props);

	the_kz_gecko_single = KZ_GECKO_SINGLE(object);

	priv = KZ_GECKO_SINGLE_GET_PRIVATE(object);

	mozilla_register_components();

	if (priv->kz_app)
	{
		profile = kz_app_get_profile(priv->kz_app);
		set_user_agent(profile);
		g_signal_connect(profile, "changed::Global",
				G_CALLBACK(cb_global_profile_changed), NULL);
		g_signal_connect(profile, "changed::Font",
				G_CALLBACK(cb_font_profile_changed), NULL);
		g_signal_connect(profile, "changed::Language",
				G_CALLBACK(cb_lang_profile_changed), NULL);
		g_signal_connect(profile, "changed::Privacy",
				G_CALLBACK(cb_privacy_profile_changed), NULL);
	}
	return object;
}

static void
set_property (GObject *object,
              guint prop_id,
              const GValue *value,
              GParamSpec *pspec)
{
	KzGeckoSinglePrivate *priv = KZ_GECKO_SINGLE_GET_PRIVATE(object);

	switch (prop_id)
	{
	case PROP_KZ_APP:
		if (g_value_get_object(value))
			priv->kz_app = KZ_APP(g_object_ref(g_value_get_object(value)));
		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)
{
	KzGeckoSinglePrivate *priv = KZ_GECKO_SINGLE_GET_PRIVATE(object);

	switch (prop_id)
	{
	case PROP_KZ_APP:
		g_value_set_object(value, priv->kz_app);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
		break;
	}
}


static void
kz_gecko_single_init (KzGeckoSingle *single)
{
	KzGeckoSinglePrivate *priv = KZ_GECKO_SINGLE_GET_PRIVATE(single);

	priv->kz_app = NULL;
}


static void
dispose (GObject *object)
{
	KzGeckoSinglePrivate *priv = KZ_GECKO_SINGLE_GET_PRIVATE(object);

	if (priv->kz_app)
	{
		gtk_moz_embed_pop_startup();
		g_object_unref(priv->kz_app);
	}

	priv->kz_app = NULL;
	
	if (G_OBJECT_CLASS (kz_gecko_single_parent_class)->dispose)
		G_OBJECT_CLASS (kz_gecko_single_parent_class)->dispose(object);
}


KzGeckoSingle *
kz_gecko_single_new (KzApp *kz_app)
{
	return KZ_GECKO_SINGLE(g_object_new(KZ_TYPE_GECKO_SINGLE,
			     		    "kz-app", kz_app,
					    NULL));
}


static gchar *
convert_preference_name (const gchar *prefix, const gchar *key)
{
	gchar *ret;

	ret = g_strdup_printf("%s.%s", prefix, key);

	kz_str_replace_char(ret, '_', '.');

	return ret;
}

static void
cb_font_profile_changed (KzProfile *profile,
			 const gchar *section,
			 const gchar *key,
			 const gchar *old_value,
			 gpointer data)
{
	gchar *converted_key;

	switch (key[0])
	{
	case 'd': // default font style. ie. Sans-serif or Serif or Monospace.
		if (!strcmp(key, "default"))
		{
			gchar value[1024];
			kz_profile_get_value(profile, "Font", key, 
				&value, G_N_ELEMENTS(value),
				KZ_PROFILE_VALUE_TYPE_STRING);
			mozilla_prefs_set_string("font.default", value);
		}
		break;
	case 'l': // language group
		if (!strcmp(key, "language_group"))
		{
			gchar value[1024];
			kz_profile_get_value(profile, "Font", key, 
				&value, G_N_ELEMENTS(value),
				KZ_PROFILE_VALUE_TYPE_STRING);
			mozilla_prefs_set_string("font.language.group", value);
		}
		break;
	case 'n': // name_XX
		if (g_str_has_prefix(key, "name_serif_") || 
		    g_str_has_prefix(key, "name_sans-serif_") ||
		    g_str_has_prefix(key, "name_monospace_"))
		{
			gchar value[1024];
			kz_profile_get_value(profile, "Font", key, 
				&value, G_N_ELEMENTS(value),
				KZ_PROFILE_VALUE_TYPE_STRING);
			converted_key = convert_preference_name("font", key);
			mozilla_prefs_set_string(converted_key, value);
			g_free(converted_key);
		}
		break;
	case 'm': // min_size
	case 's': // size
		if (g_str_has_prefix(key, "size_variable_") ||
		    g_str_has_prefix(key, "size_fixed_") ||
		    g_str_has_prefix(key, "minimum-size_"))
		{
			gint value;
			kz_profile_get_value(profile, "Font", key, 
				&value, sizeof(value),
				KZ_PROFILE_VALUE_TYPE_INT);
			converted_key = convert_preference_name("font", key);
			mozilla_prefs_set_int(converted_key, value);
			g_free(converted_key);
		}
		break;
	default:
		break;
	}
}

static void
set_user_agent (KzProfile *profile)
{
	gchar tmp_string[1024];
	gboolean value = FALSE;
	kz_profile_get_value(profile, "Global", "override_user_agent", 
			     &value, sizeof(gboolean),
			     KZ_PROFILE_VALUE_TYPE_BOOL);
	if (value)
	{
		value = kz_profile_get_value(profile, "Global", "user_agent", 
				&tmp_string, G_N_ELEMENTS(tmp_string),
				KZ_PROFILE_VALUE_TYPE_STRING);
		mozilla_prefs_set_string("general.useragent.override",
					 tmp_string);
		mozilla_prefs_clear("general.useragent.extra.kazehakase");
	}
	else /* set default */
	{
		mozilla_prefs_clear("general.useragent.override");
		mozilla_prefs_set_string("general.useragent.extra.kazehakase",
					 "Kazehakase/" VERSION);
	}
}

static void
cb_global_profile_changed (KzProfile *profile,
			   const gchar *section,
			   const gchar *key,
			   const gchar *old_value,
			   gpointer data)
{
	gchar tmp_string[1024];
	gboolean value = FALSE;

	switch (key[0])
	{
	case 'o': // override_user_agent
		if (strcmp(key, "override_user_agent") == 0)
		{
			set_user_agent(profile);
		}
		break;
	case 'p':
		if (strcmp(key, "proxy_name") == 0 &&
		    kz_profile_get_value(profile, "Global", key, 
				&tmp_string, G_N_ELEMENTS(tmp_string),
				KZ_PROFILE_VALUE_TYPE_STRING))
		{
			KzProxyItem *item = kz_proxy_find(tmp_string);
			if (item)
			{
				mozilla_prefs_set_proxy(item);
				g_object_unref(item);
			}
		}
		break;
	case 'u': // user_agent or use_proxy
		if (strcmp(key, "use_proxy") == 0 &&
		    kz_profile_get_value(profile, "Global", key, 
			     &value, sizeof(gboolean),
			     KZ_PROFILE_VALUE_TYPE_BOOL))
		{
			mozilla_prefs_set_use_proxy(value);
		}
		else if (strcmp(key, "user_agent") == 0)
		{
			set_user_agent(profile);
		}
		break;
	default:
		break;
	}
}

static void
cb_lang_profile_changed (KzProfile *profile,
			 const gchar *section,
			 const gchar *key,
			 const gchar *old_value,
			 gpointer data)
{
	gchar *converted_key;

	switch (key[0])
	{
	case 'a'://  accept_languages
		if (!strcmp(key, "accept_languages"))
		{
			gchar value[1024];
			kz_profile_get_value(profile, "Language", key, 
				&value, G_N_ELEMENTS(value),
				KZ_PROFILE_VALUE_TYPE_STRING);
			mozilla_prefs_set_string("intl.accept_languages", value);
		}
		break;
	case 'c': // charset
		if (!strcmp(key, "charset_default") ||
		    !strcmp(key, "charset_detector"))
		{
			gchar value[1024];
			kz_profile_get_value(profile, "Language", key, 
				&value, G_N_ELEMENTS(value),
				KZ_PROFILE_VALUE_TYPE_STRING);
			converted_key = convert_preference_name("intl" ,key);
			mozilla_prefs_set_string(converted_key, value);
			g_free(converted_key);
		}
		break;
	default:
		break;
	}
}

static void
cb_privacy_profile_changed (KzProfile *profile,
			    const gchar *section,
			    const gchar *key,
			    const gchar *old_value,
			    gpointer data)
{
	switch (key[0])
	{
	case 'c':// cookie
		if (!strcmp(key, "cookie_behaviour"))
		{
			gint value;
			kz_profile_get_value(profile, "Privacy", key, 
				&value, sizeof(value),
				KZ_PROFILE_VALUE_TYPE_INT);
			mozilla_prefs_set_int("network.cookie.cookieBehavior", value);
		}
		else if (!strcmp(key, "cookie_lifetime_policy"))
		{
			gint value;
			kz_profile_get_value(profile, "Privacy", key, 
				&value, sizeof(value),
				KZ_PROFILE_VALUE_TYPE_INT);
			mozilla_prefs_set_int("network.cookie.lifetimePolicy", value);
		}
		else if (!strcmp(key, "cookie_lifetime_days"))
		{
			gint value;
			kz_profile_get_value(profile, "Privacy", key, 
				&value, sizeof(value),
				KZ_PROFILE_VALUE_TYPE_INT);
			mozilla_prefs_set_int("network.cookie.lifetime.days", value);
		}
		else if (!strcmp(key, "cookie_always_accept_session_cookies"))
		{
			gboolean value;
			kz_profile_get_value(profile, "Privacy", key, 
				&value, sizeof(value),
				KZ_PROFILE_VALUE_TYPE_INT);
			mozilla_prefs_set_boolean("network.cookie.alwaysAcceptSessionCookies", value);
		}
		break;
	default:
		break;
	}
}

#if 0
static void 
destroy_browser_cb (GtkMozEmbed *embed, GtkWidget *transient_window)
{
	gtk_widget_destroy(GTK_WIDGET(transient_window));
}

static void
new_window_orphan_cb (GtkMozEmbedSingle *embed, GtkMozEmbed **retval,
		      guint chromemask, gpointer data)
{
	// FIXME! but I don't have any nice idea...
	GtkWidget *newWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	GtkMozEmbed *newBrowser = GTK_MOZ_EMBED(gtk_moz_embed_new());

	gtk_container_add(GTK_CONTAINER(newWindow), GTK_WIDGET(newBrowser));
	g_signal_connect(newBrowser,"destroy_browser",
			 G_CALLBACK(destroy_browser_cb),newWindow);
	*retval = GTK_MOZ_EMBED(newBrowser);
}
#endif
