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

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

#include "kz-tab-label.h"

#include <stdlib.h>
#include <string.h>
#include <glib/gstdio.h>
#include <glib/gi18n.h>
#include "gtk-utils.h"
#include "kazehakase.h"
#include "kz-actions.h"
#include "kz-actions-tab.h"
#include "kz-icons.h"
#include "kz-favicon.h"
#include "kz-bookmark-file.h"
#include "kz-notebook.h"

#include "utils.h"

enum {
	PROP_0,
	PROP_KZ_WINDOW,
	PROP_KZ_EMBED
};


typedef struct _KzTabLabelPrivate       KzTabLabelPrivate;
struct _KzTabLabelPrivate
{
	gint width;
	gint start_x, start_y;
	gboolean moved;
	gboolean lock;
	gboolean auto_refresh;
	gboolean javascript;
	gboolean show_favicon;
	gboolean create_thumbnail;
	guint auto_refresh_id;
	gint icon_width;
	gint icon_height;
};
#define KZ_TAB_LABEL_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), KZ_TYPE_TAB_LABEL, KzTabLabelPrivate))

static gchar *label_color[KZ_TAB_LABEL_N_STATE];

#define DEFAULT_AUTO_REFRESH_INTERVAL_SEC 300

/* object class */
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);
/* widget class */
static void     realize        (GtkWidget        *widget);
static gboolean button_press   (GtkWidget        *widget,
                                GdkEventButton   *event);
static gboolean button_release (GtkWidget        *widget,
                                GdkEventButton   *event);
static gboolean scroll_event   (GtkWidget        *widget,
                                GdkEventScroll   *event);
static void     drag_data_received (GtkWidget        *widget,
                                    GdkDragContext   *drag_context,
                                    gint              x, 
                                    gint              y,
                                    GtkSelectionData *data,
                                    guint             info,
                                    guint             time);

static void     kz_tab_label_sync_to_profile    (KzTabLabel *kztab);

static void	kz_tab_label_set_visited        (KzTabLabel *kztab);

static void     cb_close_button_clicked         (GtkWidget *button,
						 KzTabLabel *kztab);

static void     cb_profile_changed              (KzProfile *profile,
						 const gchar *section,
						 const gchar *key,
						 const gchar *old_value,
						 KzTabLabel *kztab);

static void     cb_global_profile_changed       (KzProfile *profile,
						 const gchar *section,
						 const gchar *key,
						 const gchar *old_value,
						 KzTabLabel *kztab);

/* callbacks for embed */
static void cb_title_changed (KzEmbed *embed, const gchar *title, KzTabLabel *kztab);
static void cb_location_changed (KzEmbed *embed, const gchar *location, KzTabLabel *kztab);
static void cb_net_start     (KzEmbed *embed, KzTabLabel *kztab);
static void cb_net_stop      (KzEmbed *embed, KzTabLabel *kztab);
static void cb_progress      (KzEmbed *embed, gdouble ratio, KzTabLabel *kztab);

static void make_progress_circle (GtkWidget *widget);

enum {
	TARGET_NETSCAPE_URL,
	TARGET_TEXT_URI_LIST,
	TARGET_TEXT_PLAIN,
	TARGET_STRING
};

static GtkTargetEntry url_drag_types [] = 
{
        { "_NETSCAPE_URL", 0, TARGET_NETSCAPE_URL},
	{ "text/uri-list", 0, TARGET_TEXT_URI_LIST},
	{ "text/plain",    0, TARGET_TEXT_PLAIN},
	{ "STRING",        0, TARGET_STRING}
};
static guint n_url_drag_types = G_N_ELEMENTS (url_drag_types);

static GdkColor red = { 0, 0xffff, 0x0000, 0x0000 };

G_DEFINE_TYPE(KzTabLabel, kz_tab_label, GTK_TYPE_HBOX)

static void
kz_tab_label_class_init (KzTabLabelClass *klass)
{
	GObjectClass *gobject_class;
	GtkWidgetClass *widget_class;

	gobject_class = G_OBJECT_CLASS(klass);
	widget_class  = GTK_WIDGET_CLASS(klass);

	/* GtkObject signals */
	gobject_class->constructor  = constructor;
	gobject_class->dispose      = dispose;
	gobject_class->set_property = set_property;
	gobject_class->get_property = get_property;

	/* GtkWidget signales */
	widget_class->realize       = realize;
	widget_class->button_press_event   = button_press;
	widget_class->button_release_event = button_release;
	widget_class->scroll_event         = scroll_event;

	widget_class->drag_data_received   = drag_data_received;

	g_object_class_install_property
		(gobject_class,
		 PROP_KZ_WINDOW,
		 g_param_spec_object ("kz-window",
				      _("KzWindow"),
				      _("The parent kazehakase window"),
				      KZ_TYPE_WINDOW,
				      G_PARAM_READWRITE |
				      G_PARAM_CONSTRUCT_ONLY));

	g_object_class_install_property
		(gobject_class,
		 PROP_KZ_EMBED,
		 g_param_spec_object ("kz-embed",
				      _("KzEmbed"),
				      _("The KzEmbed object to observe"),
				      KZ_TYPE_EMBED,
				      G_PARAM_READWRITE |
				      G_PARAM_CONSTRUCT));
	g_type_class_add_private (gobject_class, sizeof(KzTabLabelPrivate));
}

static void
kz_tab_label_init (KzTabLabel *kztab)
{
	GtkWidget *close_image, *hbox;
	GtkRcStyle *style;
	GtkRequisition size;
	KzTabLabelPrivate *priv = KZ_TAB_LABEL_GET_PRIVATE (kztab);

	kztab->kz           = NULL;
	kztab->kzembed      = NULL;
	kztab->state        = KZ_TAB_LABEL_STATE_NORMAL;
	kztab->favicon      = gtk_image_new();
	kztab->eventbox     = gtk_event_box_new();
	gtk_event_box_set_visible_window(GTK_EVENT_BOX(kztab->eventbox), FALSE);
	kztab->label        = gtk_label_new(NULL);
	kztab->close_button = gtk_button_new();
	kztab->lock_button  = gtk_image_new_from_stock(KZ_STOCK_ANCHOR,
						       GTK_ICON_SIZE_MENU);

	priv->width             = 80;
	priv->start_x           = 0;
	priv->start_y           = 0;
	priv->moved             = FALSE;
	priv->lock              = FALSE;
	priv->auto_refresh      = FALSE;
	priv->auto_refresh_id   = 0;
	
	priv->show_favicon      = TRUE;
	priv->create_thumbnail  = FALSE;

	KZ_CONF_GET("Tab", "show_favicon", priv->show_favicon, BOOL);
	KZ_CONF_GET("Global", "create_thumbnail", priv->create_thumbnail, BOOL);

	kztab->circle           = NULL;
	kztab->mask             = NULL;

	kztab->history    = KZ_BOOKMARK_FOLDER(kz_bookmark_folder_new(_("Tab")));

	hbox = gtk_hbox_new(FALSE, 0);
	gtk_container_add(GTK_CONTAINER(kztab->eventbox), hbox);
	gtk_widget_show(hbox);
	/* 
	 * input only event box 
	 * this widget have a effect widget background display correctly.
	 * See http://bugzilla.gnome.org/show_bug.cgi?id=103206
	 */
	gtk_container_add (GTK_CONTAINER(kztab), kztab->eventbox);
	gtk_widget_show(kztab->eventbox);

	/* label */
	gtk_widget_set_size_request(kztab->label, -1, -1);
	gtk_widget_show (kztab->label);

	/* favicon */
	gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &priv->icon_width, &priv->icon_height);
	gtk_widget_set_size_request(kztab->favicon, priv->icon_width, priv->icon_height);

	/* close button */
	gtk_button_set_relief(GTK_BUTTON(kztab->close_button), GTK_RELIEF_NONE);
	g_signal_connect(kztab->close_button, "clicked", 
			 G_CALLBACK(cb_close_button_clicked), kztab);

	close_image = gtk_image_new_from_stock(GTK_STOCK_CLOSE,
					       GTK_ICON_SIZE_MENU);
	gtk_widget_size_request(close_image, &size);
	gtk_widget_set_size_request(kztab->close_button,
				    size.width, size.height);
	gtk_container_add(GTK_CONTAINER(kztab->close_button), close_image);
	gtk_widget_show(close_image);

	style = gtk_rc_style_new ();
	style->xthickness = style->ythickness = 0;
	gtk_widget_modify_style (kztab->close_button, style);
	gtk_widget_modify_style (kztab->lock_button, style);
	g_object_unref (style),

	gtk_box_pack_start(GTK_BOX(hbox), kztab->favicon,
			   FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(hbox), kztab->label,
			   TRUE, TRUE, 0);
	/* 
	 * close button (and other widget want to accept event signals)
	 * must be outside the eel-input-event-box
	 */ 
	gtk_box_pack_start(GTK_BOX(kztab), kztab->close_button,
			   FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(kztab), kztab->lock_button,
			   FALSE, FALSE, 0);

	gtk_widget_show (kztab->close_button);

	gtk_drag_dest_set(GTK_WIDGET(kztab), 
			  GTK_DEST_DEFAULT_ALL,
                          url_drag_types,n_url_drag_types,
			  GDK_ACTION_MOVE);

	g_signal_connect(KZ_GET_GLOBAL_PROFILE, "changed::Tab",
			 G_CALLBACK(cb_profile_changed), kztab);
	g_signal_connect(KZ_GET_GLOBAL_PROFILE, "changed::Global",
			 G_CALLBACK(cb_global_profile_changed), kztab);
	kz_tab_label_sync_to_profile(kztab);
	kz_tab_label_set_text(kztab, NULL);
}

static void
connect_embed_signals (KzTabLabel *kztab)
{
	g_signal_connect(kztab->kzembed, "kz-title",
			 G_CALLBACK(cb_title_changed), kztab);
	g_signal_connect(kztab->kzembed, "kz-location",
			 G_CALLBACK(cb_location_changed), kztab);
	g_signal_connect(kztab->kzembed, "kz-net-start",
			 G_CALLBACK(cb_net_start), kztab);
	g_signal_connect(kztab->kzembed, "kz-net-stop",
			 G_CALLBACK(cb_net_stop), kztab);
	g_signal_connect(kztab->kzembed, "kz-progress",
			 G_CALLBACK(cb_progress), kztab);
}

static void
disconnect_embed_signals (KzTabLabel *kztab)
{
	g_signal_handlers_disconnect_by_func(kztab->kzembed,
					     cb_net_start, kztab);
	g_signal_handlers_disconnect_by_func(kztab->kzembed,
					     cb_net_stop, kztab);
	g_signal_handlers_disconnect_by_func(kztab->kzembed,
					     cb_title_changed, kztab);
	g_signal_handlers_disconnect_by_func(kztab->kzembed,
					     cb_location_changed, kztab);
	g_signal_handlers_disconnect_by_func(kztab->kzembed,
					     cb_progress, kztab);
}

static GObject*
constructor (GType                  type,
             guint                  n_props,
             GObjectConstructParam *props)
{
	KzTabLabel *kztab;
	GObject *object;
	GObjectClass *klass = G_OBJECT_CLASS(kz_tab_label_parent_class);
	gchar *title;

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

	kztab = KZ_TAB_LABEL(object);

	connect_embed_signals(kztab);

	/* set label text */
	title = kz_embed_ensure_title(kztab->kzembed);
	kz_tab_label_set_text(kztab, title);
	g_free(title);

	return object;
}


static void
dispose (GObject *object)
{
	KzTabLabel *kztab;
	KzTabLabelPrivate *priv;

	kztab = KZ_TAB_LABEL(object);
	priv = KZ_TAB_LABEL_GET_PRIVATE (kztab);

	g_signal_handlers_disconnect_by_func(KZ_GET_GLOBAL_PROFILE,
					     G_CALLBACK(cb_profile_changed),
					     kztab);
	g_signal_handlers_disconnect_by_func(KZ_GET_GLOBAL_PROFILE,
					     G_CALLBACK(cb_global_profile_changed),
					     kztab);
	if (kztab->kzembed)
		kz_tab_label_set_embed(kztab, NULL);

	if (kztab->history)
	{
		kz_bookmark_folder_set_javascript(kztab->history, priv->javascript);
		kz_bookmark_folder_remove(KZ_BOOKMARK_FOLDER(kztab->kz->tabs), KZ_BOOKMARK(kztab->history));
		kz_window_append_closed_tab(kztab->kz, kztab->history);
		g_object_unref(kztab->history);
		kztab->history = NULL;
	}

	if (kztab->kz)
	{
		g_object_unref(kztab->kz);
		kztab->kz = NULL;
	}

	if (kztab->circle)
	{
		g_object_unref(kztab->circle);
		kztab->circle = NULL;
	}
	if (kztab->mask)
	{
		g_object_unref(kztab->mask);
		kztab->mask = NULL;
	}

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


static void
set_property (GObject         *object,
              guint            prop_id,
              const GValue    *value,
              GParamSpec      *pspec)
{
	KzTabLabel *tablabel = KZ_TAB_LABEL(object);
  
	switch (prop_id)
	{
	case PROP_KZ_WINDOW:
		tablabel->kz = g_object_ref(g_value_get_object(value));
		break;
	case PROP_KZ_EMBED:
		kz_tab_label_set_embed(tablabel, 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)
{
	KzTabLabel *tablabel = KZ_TAB_LABEL(object);

	switch (prop_id)
	{
	case PROP_KZ_WINDOW:
		g_value_set_object(value, tablabel->kz);
		break;
	case PROP_KZ_EMBED:
		g_value_set_object(value, tablabel->kzembed);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
		break;
	}
}


GtkWidget *
kz_tab_label_new (KzWindow *kz, KzEmbed *kzembed)
{
	KzTabLabel *kztab;

	g_return_val_if_fail(KZ_IS_WINDOW(kz), NULL);
	g_return_val_if_fail(KZ_IS_EMBED(kzembed), NULL);

	kztab = g_object_new(KZ_TYPE_TAB_LABEL,
			     "kz-window", kz,
			     "kz-embed",  kzembed,
			     NULL);

	return GTK_WIDGET(kztab);
}


void
kz_tab_label_set_text(KzTabLabel *kztab, const gchar *text)
{
	gchar *escaped, *markup;
	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));

	if (!text || !*text) text = _("No title");
	
	escaped = g_markup_escape_text(text, strlen(text));
	markup = g_strdup_printf("<span foreground=\"%s\">%s</span>",
				 label_color[kztab->state],
				 escaped);

	gtk_label_set_markup(GTK_LABEL(kztab->label), markup);
	gtk_widget_set_tooltip_text(GTK_WIDGET(kztab->eventbox), text);
	g_free(markup);
	g_free(escaped);
}

static gboolean
idle_create_thumbnail (gpointer data)
{
	KzTabLabel *kztab;
	KzEmbed *embed;
	EggPixbufThumbnailSize size = EGG_PIXBUF_THUMBNAIL_LARGE;
	const gchar *uri;
	guint last_modified;

	kztab = data;
	g_return_val_if_fail(KZ_IS_TAB_LABEL(kztab), FALSE);

	embed = kztab->kzembed;
	uri = kz_embed_get_location(embed);
	if (!uri)
		return FALSE;

	if (uri[0] == '\0')
		return FALSE;

	last_modified = kz_embed_get_last_modified(embed);
	if (last_modified > 0)
	{
		GTime thumbnail_last_modified;

		thumbnail_last_modified = thumbnail_get_last_modified(uri, size);
		if ((unsigned int)thumbnail_last_modified >= last_modified)
			return FALSE;
	}

	kz_embed_create_thumbnail(embed, size);
	return FALSE;
}

void
kz_tab_label_set_state (KzTabLabel *kztab,
			KzTabLabelState state)
{
	gchar *title;
	KzTabLabelPrivate *priv;
	
	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));

	if (!GTK_WIDGET_REALIZED(kztab)) return;

	priv = KZ_TAB_LABEL_GET_PRIVATE (kztab);
	if (priv->create_thumbnail &&
	    kztab->state != KZ_TAB_LABEL_STATE_NORMAL &&
	    state == KZ_TAB_LABEL_STATE_NORMAL)
	{
		g_idle_add(idle_create_thumbnail, kztab);
	}

	kztab->state = state;
	if (state == KZ_TAB_LABEL_STATE_NORMAL)
	{
		kz_tab_label_set_visited(kztab);
	}

	title = kz_embed_ensure_title(kztab->kzembed);
	kz_tab_label_set_text(kztab, title);
	g_free(title);
}

KzTabLabelState
kz_tab_label_get_state (KzTabLabel *kztab)
{
	g_return_val_if_fail(KZ_IS_TAB_LABEL(kztab), KZ_TAB_LABEL_STATE_NORMAL);
	return kztab->state;
}

void
kz_tab_label_set_width (KzTabLabel *kztab, gint width)
{
	KzTabLabelPrivate *priv;
	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));

	priv = KZ_TAB_LABEL_GET_PRIVATE (kztab);

	gtk_widget_set_size_request(GTK_WIDGET(kztab), width, -1);
	if (width < 0)
	{
		gtk_widget_set_size_request(kztab->label, -1, -1);
		gtk_widget_queue_resize(GTK_WIDGET(kztab));
		gtk_widget_queue_resize(kztab->label);
	}
	priv->width = width;
}

void
kz_tab_label_set_show_close_button (KzTabLabel *kztab, gboolean show)
{
	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));

        g_object_set(kztab->close_button, "visible", show, NULL);
}


void
kz_tab_label_set_show_lock_button (KzTabLabel *kztab, gboolean show)
{
	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));

        g_object_set(kztab->lock_button, "visible", show, NULL);
}

static void
realize (GtkWidget *widget)
{
	KzTabLabel *kztab = KZ_TAB_LABEL(widget);
	KzTabLabelPrivate *priv = KZ_TAB_LABEL_GET_PRIVATE(widget);

	if (GTK_WIDGET_CLASS (kz_tab_label_parent_class)->realize)
		GTK_WIDGET_CLASS (kz_tab_label_parent_class)->realize(widget);

	widget->window = gtk_widget_get_parent_window (widget);
	g_object_ref (widget->window);

	make_progress_circle(widget);

	if (kz_embed_is_loading(kztab->kzembed))
		kz_tab_label_set_state (kztab, KZ_TAB_LABEL_STATE_LOADING);

	priv->javascript = kz_embed_get_allow_javascript(kztab->kzembed);
}

static gboolean
button_press (GtkWidget *widget, GdkEventButton *event)
{
	KzTabLabel *kztab = KZ_TAB_LABEL(widget);
	KzTabLabelPrivate *priv = KZ_TAB_LABEL_GET_PRIVATE (widget);

	priv->start_x = event->x;
	priv->start_y = event->y;
	priv->moved = FALSE;

#if 0
	if (event->button == 3)
	{
		kz_actions_tab_popup_menu_modal(kztab,
						event->button,
						event->time);
	}
#endif
	if (event->button == 2)
	{
		kz_window_close_tab(kztab->kz, kztab->kzembed);
	}
	if (event->type == GDK_2BUTTON_PRESS)
	{
		kz_embed_reload(kztab->kzembed,
				(event->state & GDK_SHIFT_MASK) ?
				KZ_EMBED_RELOAD_BYPASS_PROXY_AND_CACHE : 
				KZ_EMBED_RELOAD_NORMAL);
	}
	if (GTK_WIDGET_CLASS(kz_tab_label_parent_class)->button_press_event)
		GTK_WIDGET_CLASS(kz_tab_label_parent_class)->button_press_event(widget, event);
	return FALSE;
}

static gboolean
button_release (GtkWidget *widget, GdkEventButton *event)
{
	KzTabLabel *kztab = KZ_TAB_LABEL(widget);
	KzTabLabelPrivate *priv = KZ_TAB_LABEL_GET_PRIVATE (kztab);

	if (event->button == 2 && !priv->moved)
	{
		/* Load URL in clipboard */
		/* return TRUE; */
	}
	else if (event->button == 3 && !priv->moved)
	{
		kz_actions_tab_popup_menu_modal(kztab,
						event->button,
						event->time);
		return TRUE;
	}

	priv->start_x = 0;
	priv->start_y = 0;
	priv->moved = FALSE;

	if (GTK_WIDGET_CLASS(kz_tab_label_parent_class)->button_release_event)
		return GTK_WIDGET_CLASS(kz_tab_label_parent_class)->button_release_event(widget, event);
	return FALSE;
}


static gboolean
scroll_event (GtkWidget *widget, GdkEventScroll *event)
{
	KzWindow *kz;
	gboolean retval = FALSE;

	kz = KZ_TAB_LABEL(widget)->kz;

	retval = kz_notebook_scroll_tab(KZ_NOTEBOOK(kz->notebook), event->direction);

	if (GTK_WIDGET_CLASS(kz_tab_label_parent_class)->scroll_event)
		return GTK_WIDGET_CLASS(kz_tab_label_parent_class)->scroll_event(widget, event)
			|| retval;
	return retval;
}


static void
drag_data_received (GtkWidget *widget,
                    GdkDragContext *drag_context,
                    gint x, gint y,
                    GtkSelectionData *data,
                    guint info,
                    guint time)
{
	KzTabLabel *kztab;

	kztab = KZ_TAB_LABEL(widget);

	g_return_if_fail (KZ_IS_EMBED(kztab->kzembed));

	switch (info)
	{
	case TARGET_NETSCAPE_URL:
	case TARGET_TEXT_URI_LIST:
	case TARGET_TEXT_PLAIN:
	case TARGET_STRING:
	{
		gchar **strings;

		if (data->length < 0) return;

		strings = g_strsplit((const gchar*)data->data, "\n", 2);
		kz_embed_load_url(kztab->kzembed,
				      strings[0]);
		g_strfreev(strings);
		break;
	}

	default:
		break;
	}
}

static void
kz_tab_label_sync_to_profile (KzTabLabel *kztab)
{
	gint width = 80;
	gboolean fix = TRUE;
	gboolean show_close = TRUE;
	gchar *color;
	KzTabLabelPrivate *priv = KZ_TAB_LABEL_GET_PRIVATE (kztab);

	/* width */
	KZ_CONF_GET("Tab", "fix_width", fix, BOOL);
	KZ_CONF_GET("Tab", "fixed_width", width, INT);

	if (fix)
		kz_tab_label_set_width(kztab, width);
	else
		kz_tab_label_set_width(kztab, -1);

	/* close button */
	KZ_CONF_GET("Tab", "show_close_button", show_close, BOOL);
	kz_tab_label_set_show_close_button(kztab, show_close && !priv->lock);

	/* lock button */
	kz_tab_label_set_show_lock_button(kztab, priv->lock);

	/* label color */
	color = KZ_CONF_GET_STR("Tab" , "normal_color");
	if (!color)
		color = g_strdup("#000000");

	if (label_color[KZ_TAB_LABEL_STATE_NORMAL])
		g_free(label_color[KZ_TAB_LABEL_STATE_NORMAL]);
	label_color[KZ_TAB_LABEL_STATE_NORMAL] = g_strdup(color);
	g_free(color);

	color = KZ_CONF_GET_STR("Tab" , "loading_color");
	if (!color)
		color = g_strdup("#ff0000");
	if (label_color[KZ_TAB_LABEL_STATE_LOADING])
		g_free(label_color[KZ_TAB_LABEL_STATE_LOADING]);
	label_color[KZ_TAB_LABEL_STATE_LOADING] = g_strdup(color);
	g_free(color);

	color = KZ_CONF_GET_STR("Tab" , "loaded_color");
	if (!color)
		color = g_strdup("#22aa44");
	if (label_color[KZ_TAB_LABEL_STATE_LOADED])
		g_free(label_color[KZ_TAB_LABEL_STATE_LOADED]);
	label_color[KZ_TAB_LABEL_STATE_LOADED] = g_strdup(color);
	g_free(color);
}

static void
make_progress_circle(GtkWidget *widget)
{
	GdkGC *gc;
	GdkColormap *colormap;
	KzTabLabel *kztab = KZ_TAB_LABEL(widget);
	KzTabLabelPrivate *priv = KZ_TAB_LABEL_GET_PRIVATE(kztab);

	kztab->circle = gdk_pixmap_new(widget->window,
				       priv->icon_width, priv->icon_height, -1);
	kztab->mask = gdk_pixmap_new(widget->window,
				     priv->icon_width, priv->icon_height, 1);
	gc = gdk_gc_new(kztab->mask);
	gdk_draw_rectangle(kztab->mask,
			   gc,
			   TRUE,
			   0, 0,
			   priv->icon_width, priv->icon_height);
	gdk_gc_set_function(gc, GDK_INVERT);
	gdk_draw_arc(kztab->mask,
		     gc,
		     TRUE,
		     0, 0,
		     priv->icon_width, priv->icon_height,
		     90 * 64, 360 * 64);
	g_object_unref(gc);

	gc = gdk_gc_new(kztab->circle);
	colormap = gdk_gc_get_colormap(gc);
	gdk_rgb_find_color(colormap, &red);
	gdk_gc_set_foreground(gc, &red);	
	gdk_draw_rectangle(kztab->circle,
			   widget->style->white_gc, 
			   TRUE,
			   0, 0,
			   priv->icon_width, priv->icon_height);
	gdk_draw_arc(kztab->circle,
		     gc, 
		     TRUE,
		     0, 0,
		     priv->icon_width, priv->icon_height,
		     90 * 64, 360 * 64);
	g_object_unref(colormap);
	g_object_unref(gc);
}

		
static void
cb_close_button_clicked (GtkWidget *button, KzTabLabel *kztab)
{
	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));
	kz_window_close_tab(kztab->kz, kztab->kzembed);
}

static void
cb_profile_changed (KzProfile *profile,
		    const gchar *section,
		    const gchar *key,
		    const gchar *old_value,
		    KzTabLabel *kztab)
{
	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));

	if (key && strcmp(key, "show_favicon"))
	{
		KzTabLabelPrivate *priv = KZ_TAB_LABEL_GET_PRIVATE(kztab);
		KZ_CONF_GET("Tab", "show_favicon", priv->show_favicon, BOOL);
		if (priv->show_favicon)
			gtk_widget_show(kztab->favicon);
		else
			gtk_widget_hide(kztab->favicon);
	}
	kz_tab_label_sync_to_profile(kztab);
}

static void
cb_global_profile_changed (KzProfile *profile,
			   const gchar *section,
			   const gchar *key,
			   const gchar *old_value,
			   KzTabLabel *kztab)
{
	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));

	if (key && strcmp(key, "create_thumbnail"))
	{
		KzTabLabelPrivate *priv = KZ_TAB_LABEL_GET_PRIVATE(kztab);
		KZ_CONF_GET("Global", "create_thumbnail", priv->create_thumbnail, BOOL);
	}
}

/* callbacks for embed */

static void
cb_title_changed (KzEmbed *embed, const gchar *title, KzTabLabel *kztab)
{
	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));

	kz_tab_label_set_text(kztab, title);
}

static void
cb_location_changed (KzEmbed *embed, const gchar *location, KzTabLabel *kztab)
{
	KzBookmark *bookmark;

	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));

	bookmark = kz_bookmark_folder_get_current_bookmark(kztab->history);
	if (bookmark)
		kz_bookmark_set_link(bookmark, location);
}

static void
cb_net_start (KzEmbed *embed, KzTabLabel *kztab)
{
	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));

	kz_tab_label_set_state(kztab, KZ_TAB_LABEL_STATE_LOADING);

	gtk_image_set_from_pixbuf(GTK_IMAGE(kztab->favicon), NULL);

	/* show favicon widget for progress maru. */
	gtk_widget_show(kztab->favicon);
}

static void
cb_net_stop (KzEmbed *embed, KzTabLabel *kztab)
{
	KzNotebook *note;
	KzTabLabelPrivate *priv = KZ_TAB_LABEL_GET_PRIVATE(kztab);

	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));

	kz_embed_get_history(KZ_EMBED(embed), 
			     kztab->history);

	note = KZ_NOTEBOOK(kztab->kz->notebook);
	if(kz_notebook_page_num(note, GTK_WIDGET(embed)) ==
	   kz_notebook_get_current_page(KZ_NOTEBOOK(note)))
	{
		kz_tab_label_set_state(kztab, KZ_TAB_LABEL_STATE_NORMAL);
	}
	else
	{
		KzBookmark *bookmark;
		guint last_modified, last_visited = 0;
	
		bookmark = kz_bookmark_folder_get_current_bookmark(kztab->history);
		if (bookmark)
			last_visited = kz_bookmark_get_last_visited(bookmark);
		last_modified = kz_embed_get_last_modified(embed);

		if (last_modified != 0 && last_visited > last_modified)
			kz_tab_label_set_state(kztab, KZ_TAB_LABEL_STATE_NORMAL);
		else
			kz_tab_label_set_state(kztab, KZ_TAB_LABEL_STATE_LOADED);
	}

	if (priv->show_favicon)
	{
		const gchar *uri;
		GdkPixbuf *favicon_pixbuf;

		uri = kz_embed_get_location(KZ_EMBED(kztab->kzembed));
		favicon_pixbuf = kz_favicon_get_pixbuf(KZ_GET_FAVICON, uri,
						       GTK_ICON_SIZE_MENU);
		gtk_image_set_from_pixbuf(GTK_IMAGE(kztab->favicon),
					  favicon_pixbuf);
		if (favicon_pixbuf)
			g_object_unref(favicon_pixbuf);
	}
}



static void
cb_progress (KzEmbed *embed, gdouble ratio, KzTabLabel *kztab)
{
	GtkWidget *widget;	       
	GdkGC *gc;

	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));

	widget = GTK_WIDGET(kztab);

	if(GTK_WIDGET_REALIZED(widget))
	{
		GdkBitmap *mask;
		KzTabLabelPrivate *priv = KZ_TAB_LABEL_GET_PRIVATE(kztab);

		mask = gdk_pixmap_new(widget->window,
				      priv->icon_width, priv->icon_height, 1);
		gc = gdk_gc_new(mask);
		gdk_draw_rectangle(mask,
				   gc,
				   TRUE,
				   0, 0,
				   priv->icon_width, priv->icon_height);
		gdk_gc_set_function(gc, GDK_INVERT);
		gdk_draw_rectangle(mask,
				   gc,
				   TRUE,
				   0, 0,
				   priv->icon_width, priv->icon_height);
		gdk_gc_set_function(gc, GDK_COPY);
		gdk_draw_arc(mask,
			     gc,
			     TRUE,
			     0, 0,
			     priv->icon_width, priv->icon_height,
			     90 * 64, 360 * 64 * ratio);
		gdk_gc_set_function(gc, GDK_AND);
		gdk_draw_drawable(mask,
				  gc,
				  kztab->mask,
				  0, 0,
				  0, 0,
				  -1, -1);
		gtk_image_set_from_pixmap(GTK_IMAGE(kztab->favicon), 
					  kztab->circle,
					  mask);
		g_object_unref(mask);
		g_object_unref(gc);
	}
}


gboolean
kz_tab_label_get_lock (KzTabLabel *kztab)
{
	KzTabLabelPrivate *priv;

	g_return_val_if_fail(KZ_IS_TAB_LABEL(kztab), FALSE);
	priv = KZ_TAB_LABEL_GET_PRIVATE (kztab);
	return priv->lock;
}


void
kz_tab_label_set_lock (KzTabLabel *kztab, gboolean lock)
{
	KzTabLabelPrivate *priv;

	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));
	priv = KZ_TAB_LABEL_GET_PRIVATE (kztab);
	priv->lock = lock;
	kz_embed_set_lock(kztab->kzembed, lock);
	kz_actions_set_sensitive(kztab->kz, kztab->kzembed);
	
	kz_bookmark_folder_set_lock(kztab->history, lock);
	kz_tab_label_sync_to_profile(kztab);
}

gboolean
kz_tab_label_get_javascript (KzTabLabel *kztab)
{
	KzTabLabelPrivate *priv;

	g_return_val_if_fail(KZ_IS_TAB_LABEL(kztab), FALSE);
	priv = KZ_TAB_LABEL_GET_PRIVATE (kztab);
	return priv->javascript;
}


void
kz_tab_label_set_javascript (KzTabLabel *kztab, gboolean javascript)
{
	KzTabLabelPrivate *priv;

	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));
	priv = KZ_TAB_LABEL_GET_PRIVATE (kztab);
	priv->javascript = javascript;
	kz_embed_set_allow_javascript(kztab->kzembed, javascript);
	kz_actions_set_sensitive(kztab->kz, kztab->kzembed);
	
	kz_bookmark_folder_set_javascript(kztab->history, javascript);
	kz_tab_label_sync_to_profile(kztab);
}

static gboolean
cb_auto_refresh(KzTabLabel* kztab)
{
	KzTabLabelPrivate *priv;
	gint auto_refresh_interval_sec = DEFAULT_AUTO_REFRESH_INTERVAL_SEC;

	g_return_val_if_fail(KZ_IS_TAB_LABEL(kztab), TRUE);

	priv = KZ_TAB_LABEL_GET_PRIVATE (kztab);
	KZ_CONF_GET("Tab", "auto_refresh_interval_sec", auto_refresh_interval_sec, INT);

	kz_embed_reload(KZ_EMBED(kztab->kzembed),
			KZ_EMBED_RELOAD_NORMAL);

	if (priv->auto_refresh_id != 0)
		g_source_remove(priv->auto_refresh_id);

	priv->auto_refresh_id
		= g_timeout_add(auto_refresh_interval_sec * 1000,
				(GSourceFunc)cb_auto_refresh, kztab);
	return FALSE;
}

gboolean
kz_tab_label_get_auto_refresh (KzTabLabel *kztab)
{
	KzTabLabelPrivate *priv;
	
	g_return_val_if_fail(KZ_IS_TAB_LABEL(kztab), FALSE);
	priv = KZ_TAB_LABEL_GET_PRIVATE (kztab);
	return priv->auto_refresh;

}
void
kz_tab_label_set_auto_refresh (KzTabLabel *kztab, gboolean auto_refresh)
{
	KzTabLabelPrivate *priv;

	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));
	priv = KZ_TAB_LABEL_GET_PRIVATE (kztab);
	if (auto_refresh)
	{
		gint auto_refresh_interval_sec = DEFAULT_AUTO_REFRESH_INTERVAL_SEC;
		KZ_CONF_GET("Tab", "auto_refresh_interval_sec", auto_refresh_interval_sec, INT);

		if (priv->auto_refresh_id != 0)
			g_source_remove(priv->auto_refresh_id);

		priv->auto_refresh_id 
			= g_timeout_add(auto_refresh_interval_sec * 1000,
					(GSourceFunc)cb_auto_refresh, kztab);
	}
	else
	{
		if (priv->auto_refresh_id != 0)
		{
			g_source_remove(priv->auto_refresh_id);
			priv->auto_refresh_id = 0;
		}
	}
	priv->auto_refresh = auto_refresh;
	kz_actions_set_sensitive(kztab->kz, kztab->kzembed);

	kz_bookmark_folder_set_auto_refresh(kztab->history, auto_refresh);
	kz_tab_label_sync_to_profile(kztab);
}

void
kz_tab_label_set_history (KzTabLabel *kztab, KzBookmarkFolder *history)
{	
        gboolean allow_javacript;

	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));

	g_object_unref(kztab->history);
	kztab->history = g_object_ref(history);

	if (kz_bookmark_folder_get_lock(history))
		kz_tab_label_set_lock(kztab, TRUE);

	if (kz_bookmark_folder_get_auto_refresh(history))
		kz_tab_label_set_auto_refresh(kztab, TRUE);
        
        allow_javacript = kz_bookmark_folder_get_javascript(history);
        kz_embed_set_allow_javascript(KZ_EMBED(kztab->kzembed), allow_javacript);
        kz_tab_label_set_javascript(kztab, allow_javacript);

	kz_embed_set_history(kztab->kzembed, kztab->history);
}
static void
kz_tab_label_set_visited (KzTabLabel *kztab)
{
	KzBookmark *bookmark;
	const gchar *uri;
	GTimeVal now;
	
	g_get_current_time(&now);

	bookmark = kz_bookmark_folder_get_current_bookmark(kztab->history);
	if (bookmark)
		kz_bookmark_set_last_visited(bookmark, now.tv_sec);

	/* find the bookmark which has the same uri from the system bookmark */
	uri = kz_embed_get_location(kztab->kzembed);
	bookmark = kz_bookmark_folder_find_bookmark_from_uri(KZ_BOOKMARK_FOLDER(KZ_GET_MENU_BOOKMARK),
						      	     uri);
	if (bookmark)
		kz_bookmark_set_last_visited(bookmark, now.tv_sec);
}

void
kz_tab_label_set_embed (KzTabLabel *kztab, KzEmbed *kzembed)
{
	if (kztab->kzembed)
	{
		disconnect_embed_signals(kztab);
		g_object_unref(kztab->kzembed);
		kztab->kzembed = NULL;
	}

	if (kzembed)
	{
		kztab->kzembed = g_object_ref(kzembed);
		connect_embed_signals(kztab);
	}
}

/*
vim:ts=8:nowrap:ai
*/
