/* -*- 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/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"

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;
	guint auto_refresh_id;
	gulong favicon_signal;
};
#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 motion_notify  (GtkWidget        *widget,
                                GdkEventMotion   *event);
static gboolean button_release (GtkWidget        *widget,
                                GdkEventButton   *event);
static gboolean scroll_event   (GtkWidget        *widget,
                                GdkEventScroll   *event);
static gboolean drag_motion    (GtkWidget        *widget,
                                GdkDragContext   *drag_context,
		   		gint              x,
                                gint              y,
		   		guint             time);
static void     drag_data_get  (GtkWidget        *widget,
                                GdkDragContext   *context,
                                GtkSelectionData *seldata,
                                guint             info,
                                guint             time);
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_move_page          (KzTabLabel *kztab,
						 KzTabLabel *dest_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);

/* callbacks for embed */
static void cb_title_changed (KzEmbed *embed, 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, KzTabLabel *kztab);
static void cb_destroy       (GtkObject *object,  KzTabLabel *kztab);

static void make_progress_circle (GtkWidget *widget);

enum {
	TARGET_KAZEHAKASE_TAB,
	TARGET_NETSCAPE_URL,
	TARGET_TEXT_URI_LIST,
	TARGET_TEXT_PLAIN,
	TARGET_STRING
};

static GtkTargetEntry url_drag_types [] = 
{
        { "_KAZEHAKASE_TAB", 0, TARGET_KAZEHAKASE_TAB},
        { "_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 = (GObjectClass *) klass;
	widget_class  = (GtkWidgetClass *) 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->motion_notify_event  = motion_notify;
	widget_class->drag_motion          = drag_motion;
	widget_class->drag_data_get        = drag_data_get;
	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_ONLY));
	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;
	gint width, height;
	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);
	kztab->tooltips     = gtk_tooltips_new();

	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->favicon_signal    = 0;
	
	kztab->favicon_pixbuf   = NULL;
	kztab->circle           = NULL;
	kztab->mask             = NULL;

	kztab->history    = kz_bookmark_pure_folder_new();
	kz_bookmark_set_title(kztab->history, _("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, &width, &height);
	gtk_widget_set_size_request(kztab->favicon, width, 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);
	gtk_rc_style_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_source_set(GTK_WIDGET(kztab),
			    GDK_BUTTON1_MASK |
			    GDK_BUTTON2_MASK |
			    GDK_BUTTON3_MASK,
			    url_drag_types, n_url_drag_types,
			    GDK_ACTION_ASK  | GDK_ACTION_COPY
			    | GDK_ACTION_MOVE | GDK_ACTION_LINK);
	gtk_drag_dest_set(GTK_WIDGET(kztab), 
			  GTK_DEST_DEFAULT_HIGHLIGHT |
			  GTK_DEST_DEFAULT_MOTION | 
			  GTK_DEST_DEFAULT_DROP,
                          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);
	kz_tab_label_sync_to_profile(kztab);
	kz_tab_label_set_text(kztab, NULL);
}


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

	/* set signals */
	g_signal_connect(kztab->kzembed, "kz-title",
			 G_CALLBACK(cb_title_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);
	g_signal_connect(kztab->kzembed, "destroy",
			 G_CALLBACK(cb_destroy), 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);
	if (kztab->kzembed)
	{
	
		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_progress, kztab);
		g_signal_handlers_disconnect_by_func(kztab->kzembed,
						     cb_destroy, kztab);
		g_object_unref(kztab->kzembed);
		kztab->kzembed = NULL;
	}


	/* if connected signal exists, disconnect it. */
	if (priv->favicon_signal)
	{
		g_signal_handler_disconnect(KZ_GET_FAVICON,
					    priv->favicon_signal);
		priv->favicon_signal = 0;
	}

	if (kztab->history)
	{
		kz_bookmark_remove(kztab->kz->tabs, 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->tooltips)
	{
		g_object_ref_sink(GTK_OBJECT(kztab->tooltips));
		kztab->tooltips = NULL;
	}
	
	if (kztab->favicon_pixbuf)
	{
		g_object_unref(kztab->favicon_pixbuf);
		kztab->favicon_pixbuf = 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:
		tablabel->kzembed = 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)
{
	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_tooltips_set_tip(kztab->tooltips, GTK_WIDGET(kztab->eventbox),
			     text, NULL);
	g_free(markup);
	g_free(escaped);
}

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

	if (!GTK_WIDGET_REALIZED(kztab)) return;

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


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

        g_object_set(kztab->favicon, "visible", show && kztab->favicon_pixbuf, NULL);
}


static void
realize (GtkWidget *widget)
{
	KzTabLabel *kztab = KZ_TAB_LABEL(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);
}

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, GTK_WIDGET(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
motion_notify (GtkWidget *widget, GdkEventMotion *event)
{
	KzTabLabel *kztab = KZ_TAB_LABEL(widget);
	KzTabLabelPrivate *priv = KZ_TAB_LABEL_GET_PRIVATE (kztab);

	if (abs(event->x - priv->start_x) > 2 ||
	    abs(event->y - priv->start_y) > 2)
	{
		priv->moved = TRUE;
	}

	if (GTK_WIDGET_CLASS(kz_tab_label_parent_class)->motion_notify_event)
		return GTK_WIDGET_CLASS(kz_tab_label_parent_class)->motion_notify_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 gboolean
drag_motion (GtkWidget *widget,
             GdkDragContext *drag_context,
             gint x, gint y,
             guint time)
{
	KzTabLabel *kztab;
	KzEmbed *current_kzembed;
	gint page_num;

	kztab = KZ_TAB_LABEL(widget);

	g_return_val_if_fail (KZ_IS_EMBED(kztab->kzembed), FALSE);

	current_kzembed = KZ_EMBED(KZ_WINDOW_CURRENT_PAGE(kztab->kz));

	if (KZ_EMBED(kztab->kzembed) == current_kzembed)
		return FALSE;

	page_num = gtk_notebook_page_num(GTK_NOTEBOOK(kztab->kz->notebook),
					 GTK_WIDGET(kztab->kzembed));
	gtk_notebook_set_current_page(GTK_NOTEBOOK(kztab->kz->notebook),
				      page_num);
	return FALSE;
}

static void
drag_data_get (GtkWidget        *widget,
               GdkDragContext   *context,
               GtkSelectionData *data,
               guint             info,
               guint             time)
{
	KzTabLabel *kztab;
	const gchar *uri, *title;

	kztab = KZ_TAB_LABEL(widget);

	g_return_if_fail (KZ_IS_EMBED(kztab->kzembed));

	uri   = kz_embed_get_location(kztab->kzembed);
	title = kz_embed_get_title(kztab->kzembed);

	if (!uri || !*uri) return;

	switch (info)
	{
	case TARGET_KAZEHAKASE_TAB:
		gtk_selection_data_set(data, data->target,
				       8, (const guchar*)"dummy", strlen("dummy"));
		break;
	case TARGET_NETSCAPE_URL:
	{
		gchar *str;
		if (title && *title)
		{
			gchar *title_locale;
			gsize bytes_read, bytes_written;
			GError *error = NULL;

			title_locale = g_locale_from_utf8(title, -1,
							  &bytes_read,
							  &bytes_written,
							  &error);
			if (error)
			{
				g_warning("kz_tab_label_drag_data_get(): %s",
					 error->message);
				g_error_free(error);
			}
			if (title_locale && *title_locale)
			{
				str = g_strconcat(uri, "\n", title_locale,
						  NULL);
				g_free(title_locale);
			}
			else
			{
				str = g_strdup (uri);
			}
		}
		else
		{
			str = g_strdup (uri);
		}
		gtk_selection_data_set(data, data->target,
				       8, (const guchar*)str, strlen(str));
		g_free(str);
		break;
	}
	case TARGET_TEXT_URI_LIST:
	case TARGET_TEXT_PLAIN:
	case TARGET_STRING:
		gtk_selection_data_set(data, data->target,
				       8, (const guchar*)uri, strlen(uri));
		break;
	default:
		break;
	}
}

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_KAZEHAKASE_TAB:
	{
		GtkWidget *src_widget = gtk_drag_get_source_widget(drag_context);
		KzTabLabel *src_kztab;

		if (!KZ_IS_TAB_LABEL(src_widget)) return;
		src_kztab = KZ_TAB_LABEL(src_widget);

		kz_tab_label_move_page(src_kztab, kztab);
		return;
	}

	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;
	gboolean show_favicon = 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);

	/* favicon */
	KZ_CONF_GET("Tab", "show_favicon", show_favicon, BOOL);
	kz_tab_label_set_show_favicon(kztab, show_favicon);

	/* 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);
}

/* move kztab to dest_kztab's position */
static void
kz_tab_label_move_page(KzTabLabel *kztab, KzTabLabel *dest_kztab)
{
	GtkWidget *src_page;
	GtkNotebook *notebook;
	gint dest_pos;

	g_return_if_fail(dest_kztab->kz && dest_kztab->kzembed);
	g_return_if_fail(kztab->kz && kztab->kzembed);

	notebook = GTK_NOTEBOOK(dest_kztab->kz->notebook);
	dest_pos = gtk_notebook_page_num(notebook,
					 GTK_WIDGET(dest_kztab->kzembed));

	src_page = GTK_WIDGET(kztab->kzembed);
	if (dest_kztab->kz != kztab->kz)
		kz_window_move_tab(dest_kztab->kz, src_page);
	
	kz_window_reorder_tab(dest_kztab->kz, src_page, dest_pos);
	kz_actions_set_sensitive
		(kztab->kz, KZ_EMBED(KZ_WINDOW_CURRENT_PAGE(kztab->kz)));

	if (dest_kztab->kz != kztab->kz)
		gtk_widget_destroy(GTK_WIDGET(kztab));
}


static void
make_progress_circle(GtkWidget *widget)
{
	GdkGC *gc;
	gint width, height;
	GdkColormap *colormap;
	KzTabLabel *kztab = KZ_TAB_LABEL(widget);

	gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height);
	kztab->circle = gdk_pixmap_new(widget->window,
				       width, height, -1);
	kztab->mask = gdk_pixmap_new(widget->window,
				     width, height, 1);
	gc = gdk_gc_new(kztab->mask);
	gdk_draw_rectangle(kztab->mask,
			   gc,
			   TRUE,
			   0, 0,
			   width, height);
	gdk_gc_set_function(gc, GDK_INVERT);
	gdk_draw_arc(kztab->mask,
		     gc,
		     TRUE,
		     0, 0,
		     width, 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,
			   width, height);
	gdk_draw_arc(kztab->circle,
		     gc, 
		     TRUE,
		     0, 0,
		     width, 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, GTK_WIDGET(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));

	kz_tab_label_sync_to_profile (kztab);
}

/* callbacks for embed */

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

	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));

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

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

	if (kztab->favicon_pixbuf)
	{
		gtk_image_set_from_pixbuf(GTK_IMAGE(kztab->favicon), NULL);
		g_object_unref(kztab->favicon_pixbuf);
		kztab->favicon_pixbuf = NULL;
	}
	/* show favicon widget for progress maru. */
	gtk_widget_show(kztab->favicon);
}

static void
cb_net_stop (KzEmbed *embed, KzTabLabel *kztab)
{
	GtkNotebook *note;
	gboolean show_favicon;

	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));

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

	note = GTK_NOTEBOOK(kztab->kz->notebook);
	if(gtk_notebook_page_num(note, GTK_WIDGET(embed)) ==
	   gtk_notebook_get_current_page(note))
	{
		kz_tab_label_set_state(kztab, KZ_TAB_LABEL_STATE_NORMAL);
	}
	else
	{
		KzBookmark *bookmark = NULL;
		guint cur, last_modified, last_visited = 0;
		GList *children;
	
		cur = kz_bookmark_get_current(kztab->history);
		children = kz_bookmark_get_children(kztab->history);
		bookmark = KZ_BOOKMARK(g_list_nth_data(children, cur));
		g_list_free(children);

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

	KZ_CONF_GET("Tab", "show_favicon", show_favicon, BOOL);

	if (show_favicon)
	{
		const gchar *uri;
		uri = kz_embed_get_location(KZ_EMBED(kztab->kzembed));
		kztab->favicon_pixbuf = kz_favicon_get_pixbuf(KZ_GET_FAVICON, uri,
							      GTK_ICON_SIZE_MENU);
		gtk_image_set_from_pixbuf(GTK_IMAGE(kztab->favicon),
					  kztab->favicon_pixbuf);
	}

	kz_tab_label_set_show_favicon(kztab, show_favicon);
}



static void
cb_destroy (GtkObject *object, KzTabLabel *kztab)
{
	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));
	g_object_unref(kztab->kzembed);
	kztab->kzembed = NULL;
}


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

	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));

	widget = GTK_WIDGET(kztab);
	progress = kz_embed_get_progress(KZ_EMBED(embed));

	if(GTK_WIDGET_REALIZED(widget))
	{
		GdkBitmap *mask;
		gint width, height;
		gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height);

		mask = gdk_pixmap_new(widget->window,
				      width, height, 1);
		gc = gdk_gc_new(mask);
		gdk_draw_rectangle(mask,
				   gc,
				   TRUE,
				   0, 0,
				   width, height);
		gdk_gc_set_function(gc, GDK_INVERT);
		gdk_draw_rectangle(mask,
				   gc,
				   TRUE,
				   0, 0,
				   width, height);
		gdk_gc_set_function(gc, GDK_COPY);
		gdk_draw_arc(mask,
			     gc,
			     TRUE,
			     0, 0,
			     width, height,
			     90 * 64, 360 * 64 * progress);
		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_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_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_set_auto_refresh(kztab->history, auto_refresh);
	kz_tab_label_sync_to_profile(kztab);
}

void
kz_tab_label_set_history (KzTabLabel *kztab, KzBookmark *history)
{	
	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));

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

	if (kz_bookmark_get_lock(history))
	{
		kz_tab_label_set_lock(kztab, TRUE);
	}
	if (kz_bookmark_get_auto_refresh(history))
	{
		kz_tab_label_set_auto_refresh(kztab, TRUE);
	}
	if (kz_bookmark_get_javascript(history))
	{
		kz_embed_set_allow_javascript(KZ_EMBED(kztab->kzembed), TRUE);
		kz_tab_label_set_javascript(kztab, TRUE);
	}
	else
	{
		kz_embed_set_allow_javascript(KZ_EMBED(kztab->kzembed), FALSE);
		kz_tab_label_set_javascript(kztab, FALSE);
	}
	
	kz_embed_set_history(kztab->kzembed, 
			     kztab->history);
}
static void
kz_tab_label_set_visited (KzTabLabel *kztab)
{
	KzBookmark *bookmark = NULL;
	const gchar *uri;
	GTimeVal now;
	guint cur;
	GList *children;
	
	g_get_current_time(&now);

	cur = kz_bookmark_get_current(kztab->history);
	children = kz_bookmark_get_children(kztab->history);
	bookmark = KZ_BOOKMARK(g_list_nth_data(children, cur));
	g_list_free(children);

	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_find_bookmark_from_uri(KZ_GET_MENU_BOOKMARK,
						      uri);
	if (bookmark)
		kz_bookmark_set_last_visited(bookmark, now.tv_sec);
}

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