/* -*- 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-tablabel.h"

#include <string.h>
#include "gobject-utils.h"
#include "intl.h"

/* XPM */
#include "pixmaps/small-close.xpm"

static void     kz_tab_label_class_init         (KzTabLabelClass *class);
static void     kz_tab_label_init               (KzTabLabel *kztab);
static void     kz_tab_label_destroy            (GtkObject *object);
static void     kz_tab_label_realize            (GtkWidget *widget);
static void     kz_tab_label_unrealize          (GtkWidget *widget);
static void     kz_tab_label_close_cb           (GtkWidget *button,
						 KzTabLabel *kztab);
static gboolean kz_tab_label_drag_motion        (GtkWidget *widget,
						 GdkDragContext *drag_context,
						 gint x, gint y,
						 guint time);
static void     kz_tab_label_drag_data_get      (GtkWidget        *widget,
						 GdkDragContext   *context,
						 GtkSelectionData *seldata,
						 guint             info,
						 guint             time);
static void     kz_tab_label_drag_data_received (GtkWidget *widget,
						 GdkDragContext *drag_context,
						 gint x, gint y,
						 GtkSelectionData *data,
						 guint info,
						 guint time);

static void     kz_tab_label_move_page          (KzTabLabel *kztab,
						 KzTabLabel *dest_kztab);

/* callbacks for mozilla */
static void title_changed_cb (GtkMozEmbed *embed, KzTabLabel *kztab);
static void net_start_cb     (GtkMozEmbed *embed, KzTabLabel *kztab);
static void net_stop_cb      (GtkMozEmbed *embed, KzTabLabel *kztab);
static void destroy_cb       (GtkObject *object, KzTabLabel *kztab);


static GtkEventBoxClass *parent_class = NULL;

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);
 
KZ_OBJECT_GET_TYPE(kz_tab_label, "KzTabLabel", KzTabLabel,
		   kz_tab_label_class_init, kz_tab_label_init,
		   GTK_TYPE_EVENT_BOX)

static void
kz_tab_label_class_init (KzTabLabelClass *class)
{
	GtkObjectClass *object_class;
	GtkWidgetClass *widget_class;

	parent_class = g_type_class_peek_parent (class);

	object_class = (GtkObjectClass *) class;
	widget_class = (GtkWidgetClass *) class;

	/* GtkObject signals */
	object_class->destroy = kz_tab_label_destroy;

	/* GtkWidget signales */
	widget_class->realize            = kz_tab_label_realize;
	widget_class->unrealize          = kz_tab_label_unrealize;
	widget_class->drag_motion        = kz_tab_label_drag_motion;
	widget_class->drag_data_get      = kz_tab_label_drag_data_get;
	widget_class->drag_data_received = kz_tab_label_drag_data_received;
}

static void
kz_tab_label_init (KzTabLabel *kztab)
{
	gint i;

	kztab->kz           = NULL;
	kztab->kzembed      = NULL;
	kztab->state        = KZ_TAB_LABEL_STATE_NORMAL;
	kztab->hbox         = NULL;
	kztab->label        = NULL;
	kztab->close_button = NULL;
	for (i = 0; i < KZ_TAB_LABEL_N_STATE; i++)
		kztab->style[i] = NULL;
}

static void
kz_tab_label_destroy (GtkObject *object)
{
	KzTabLabel *kztab;

	g_return_if_fail (KZ_IS_TAB_LABEL(object));

	kztab = KZ_TAB_LABEL(object);

	if (kztab->kzembed)
	{
		g_signal_handlers_disconnect_by_func(G_OBJECT(kztab->kzembed),
						     net_start_cb, kztab);
		g_signal_handlers_disconnect_by_func(G_OBJECT(kztab->kzembed),
						     net_stop_cb, kztab);
		g_signal_handlers_disconnect_by_func(G_OBJECT(kztab->kzembed),
						     title_changed_cb, kztab);
		g_signal_handlers_disconnect_by_func(G_OBJECT(kztab->kzembed),
						     destroy_cb, kztab);
	}
	kztab->kzembed = NULL;

	if (GTK_OBJECT_CLASS (parent_class)->destroy)
		GTK_OBJECT_CLASS (parent_class)->destroy(object);
}

GtkWidget *
kz_tab_label_new (KzWindow *kz, KzMozEmbed *kzembed)
{
	KzTabLabel *kztab = KZ_TAB_LABEL(g_object_new(KZ_TYPE_TAB_LABEL, NULL));
	GdkPixmap *pixmap;
	GdkBitmap *mask;
	GtkWidget *image;
	const gchar *title;

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

	title = kz_moz_embed_get_title(kzembed);
	if (!title || !*title) title = _("no title");

	kztab->kz           = kz;
	kztab->kzembed      = kzembed;
	kztab->hbox         = gtk_hbox_new(0, FALSE);
	kztab->label        = gtk_label_new(title);
	kztab->close_button = gtk_button_new();

	/*  hbox */
	gtk_container_add (GTK_CONTAINER(kztab), kztab->hbox);
	gtk_widget_show(kztab->hbox);

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

	/* button */
	gtk_widget_set_size_request(kztab->close_button, 14, 14);
	gtk_button_set_relief(GTK_BUTTON(kztab->close_button), GTK_RELIEF_NONE);
	g_signal_connect(G_OBJECT(kztab->close_button), "clicked", 
			 G_CALLBACK(kz_tab_label_close_cb), kztab);

	gtk_box_pack_start(GTK_BOX(kztab->hbox), kztab->label, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(kztab->hbox), kztab->close_button, FALSE, FALSE, 0);

	pixmap = gdk_pixmap_colormap_create_from_xpm_d
			(GTK_WIDGET(kz)->window,
			 gtk_widget_get_colormap(GTK_WIDGET(kztab)),
			 &mask,
			 NULL,
			 small_close);
	image = gtk_image_new_from_pixmap(pixmap,mask);
	gdk_pixmap_unref(pixmap);
	gdk_bitmap_unref(mask);
	gtk_container_add(GTK_CONTAINER(kztab->close_button), image);

	gtk_widget_show(image);
	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);

	/* set signals */
	g_signal_connect(G_OBJECT(kzembed), "title",
			 G_CALLBACK(title_changed_cb), kztab);
	g_signal_connect(G_OBJECT(kzembed), "net-start",
			 G_CALLBACK(net_start_cb), kztab);
	g_signal_connect(G_OBJECT(kzembed), "net-stop",
			 G_CALLBACK(net_stop_cb), kztab);
	g_signal_connect(G_OBJECT(kzembed), "destroy",
			 G_CALLBACK(destroy_cb), kztab);

	return GTK_WIDGET(kztab);
}

void
kz_tab_label_show_close_button (KzTabLabel *kztab)
{
	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));
	gtk_widget_show(kztab->close_button);
}

void
kz_tab_label_hide_close_button (KzTabLabel *kztab)
{
	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));
	gtk_widget_hide(kztab->close_button);
}

void
kz_tab_label_set_text(KzTabLabel *kztab, const gchar *text)
{
	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));
	gtk_label_set_text(GTK_LABEL(kztab->label), text);
}

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

	if (!GTK_WIDGET_REALIZED(kztab)) return;

	switch(state)
	{
	case KZ_TAB_LABEL_STATE_LOADING:
		gtk_widget_modify_style(GTK_WIDGET(kztab->label),
					kztab->style[KZ_TAB_LABEL_STATE_LOADING]);
		break;
	case KZ_TAB_LABEL_STATE_NORMAL:
	default:
		gtk_widget_modify_style(GTK_WIDGET(kztab->label),
					kztab->style[KZ_TAB_LABEL_STATE_NORMAL]);
		break;
	}
}

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

static void
kz_tab_label_realize (GtkWidget *widget)
{
	KzTabLabel *kztab = KZ_TAB_LABEL(widget);
	gint i;

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

	/* new rc styles */
	if (!kztab->style[KZ_TAB_LABEL_STATE_LOADING])
	{
		GtkRcStyle *style = gtk_rc_style_new();

		/* set colors */
		for(i = 0; i< 5; i++)
		{
			style->color_flags[i]   = GTK_RC_FG;
			style->fg[i].red   = 0xffff;
			style->fg[i].blue  = 0x0000;
			style->fg[i].green = 0x0000;
		}
		kztab->style[KZ_TAB_LABEL_STATE_LOADING] = style;
	}

	if (!kztab->style[KZ_TAB_LABEL_STATE_NORMAL])
	{
		kztab->style[KZ_TAB_LABEL_STATE_NORMAL]
			= gtk_widget_get_modifier_style(widget);
		gtk_rc_style_ref(kztab->style[KZ_TAB_LABEL_STATE_NORMAL]);
	}

	if (kz_moz_embed_is_loading(kztab->kzembed))
		kz_tab_label_set_state (kztab, KZ_TAB_LABEL_STATE_LOADING);
}

static void
kz_tab_label_unrealize (GtkWidget *widget)
{
	KzTabLabel *kztab = KZ_TAB_LABEL(widget);
	gint i;

	for (i = 0; i < KZ_TAB_LABEL_N_STATE; i++)
	{
		if (kztab->style[i])
		{
			gtk_rc_style_unref(kztab->style[i]);
			kztab->style[i] = NULL;
		}
	}

	if (GTK_WIDGET_CLASS (parent_class)->unrealize)
		GTK_WIDGET_CLASS (parent_class)->unrealize(widget);
}

/* callbacks for mozilla */

static void
title_changed_cb (GtkMozEmbed *embed, KzTabLabel *kztab)
{
	const gchar *title;

	g_return_if_fail(KZ_IS_MOZ_EMBED(embed));
	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));

	title = kz_moz_embed_get_title(kztab->kzembed);
	if (!title || !*title) title = _("no title");

	gtk_label_set_text(GTK_LABEL(kztab->label), (gchar *) title);
}

static void
net_start_cb (GtkMozEmbed *embed, KzTabLabel *kztab)
{
	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));
	kz_tab_label_set_state(kztab, KZ_TAB_LABEL_STATE_LOADING);
}

static void
net_stop_cb (GtkMozEmbed *embed, KzTabLabel *kztab)
{
	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));
	kz_tab_label_set_state(kztab, KZ_TAB_LABEL_STATE_NORMAL);
}

static void
kz_tab_label_close_cb (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
destroy_cb (GtkObject *object, KzTabLabel *kztab)
{
	g_return_if_fail(KZ_IS_TAB_LABEL(kztab));
	kztab->kzembed = NULL;
}

static gboolean
kz_tab_label_drag_motion (GtkWidget *widget,
			  GdkDragContext *drag_context,
			  gint x, gint y,
			  guint time)
{
	KzTabLabel *kztab;
	KzMozEmbed *current_kzembed;
	gint page_num;

	g_return_val_if_fail(KZ_TAB_LABEL(widget), FALSE);
	kztab = KZ_TAB_LABEL(widget);

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

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

	if (KZ_MOZ_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
kz_tab_label_drag_data_get (GtkWidget        *widget,
			    GdkDragContext   *context,
			    GtkSelectionData *data,
			    guint             info,
			    guint             time)
{
	KzTabLabel *kztab;
	const gchar *uri, *title;

	g_return_if_fail(KZ_TAB_LABEL(widget));
	kztab = KZ_TAB_LABEL(widget);

	g_return_if_fail (KZ_IS_MOZ_EMBED(kztab->kzembed));

	uri   = kz_moz_embed_get_location(kztab->kzembed);
	title = kz_moz_embed_get_title(kztab->kzembed);

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

	switch (info)
	{
	case TARGET_KAZEHAKASE_TAB:
		gtk_selection_data_set(data, data->target,
				       8, "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, 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, uri, strlen(uri));
		break;
	default:
		break;
	}
}

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

	g_return_if_fail(KZ_TAB_LABEL(widget));
	kztab = KZ_TAB_LABEL(widget);

	g_return_if_fail (KZ_IS_MOZ_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:
		string = g_strsplit(data->data, "\n", 2);
		gtk_moz_embed_load_url(GTK_MOZ_EMBED(kztab->kzembed),
				       string[0]);
		g_strfreev(string);
		break;

	default:
		break;
	}
}

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

	if (dest_kztab->kz != kztab->kz)
	{
		src_page = GTK_WIDGET(kztab->kzembed);
		kz_window_move_tab(dest_kztab->kz, GTK_WIDGET(src_page));
	}
	else
	{
		src_page = GTK_WIDGET(kztab->kzembed);
	}

	gtk_notebook_reorder_child (notebook, src_page, dest_pos);
}
