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

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

#include <string.h>
#include <glib/gi18n.h>

#include "kz-download-box.h"
#include "kz-actions-download.h"
#include "gtk-utils.h"

enum {
	PROP_0,
	PROP_KZ_WINDOW
};

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 drag_data_received (GtkWidget        *widget,
                                GdkDragContext   *context,
                                gint              x,
                                gint              y,
                                GtkSelectionData *data,
                                guint             info,
                                guint             time);

static void cb_add_item       (KzDownloaderGroup *dlgrp,
			       KzDownloader      *dl,
			       KzDownloadBox     *dlbox);
static void cb_remove_item    (KzDownloaderGroup *dlgrp,
			       KzDownloader      *dl,
			       KzDownloadBox     *dlbox);
static void cb_progress_item  (KzDownloaderGroup *dlgrp,
			       KzDownloader      *dl,
			       KzDownloadBox     *dlbox);

static void remove_icon       (KzDownloaderIcon *icon);

enum {
	TARGET_NETSCAPE_URL,
	TARGET_TEXT_URI_LIST
};

static GtkTargetEntry url_drag_types [] = 
{
        { "_NETSCAPE_URL",   0, TARGET_NETSCAPE_URL},
	{ "text/uri-list",   0, TARGET_TEXT_URI_LIST}
};

static guint n_url_drag_types = G_N_ELEMENTS (url_drag_types);

G_DEFINE_TYPE(KzDownloadBox, kz_download_box, GTK_TYPE_STATUSBAR)

static void
kz_download_box_class_init (KzDownloadBoxClass *klass)
{
	GObjectClass *gobject_class;
	GtkWidgetClass *widget_class;

	kz_download_box_parent_class = g_type_class_peek_parent (klass);

	gobject_class = (GObjectClass *) klass;
	widget_class  = (GtkWidgetClass *) klass;

	/* GObject signals */
	gobject_class->dispose      = dispose;
	gobject_class->set_property = set_property;
	gobject_class->get_property = get_property;

	/* GtkWidget signales */
	/* widget_class->drag_motion          = kz_download_box_drag_motion; */
	/* widget_class->drag_data_get        = kz_download_box_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));

}

static void
kz_download_box_init (KzDownloadBox *dlbox)
{
	/* widgets */
	dlbox->kz = NULL;
	
	dlbox->dlgrp = kz_downloader_group_get_instance();
	dlbox->icon_list = NULL;

	gtk_drag_dest_set(GTK_WIDGET(dlbox), 
			  GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_MOTION | 
			  GTK_DEST_DEFAULT_DROP,
                          url_drag_types,n_url_drag_types,
			  GDK_ACTION_LINK);
	
	g_signal_connect(dlbox->dlgrp, "add",
			 G_CALLBACK(cb_add_item), dlbox);
	g_signal_connect(dlbox->dlgrp, "remove",
			 G_CALLBACK(cb_remove_item), dlbox);
	g_signal_connect(dlbox->dlgrp, "progress",
			 G_CALLBACK(cb_progress_item), dlbox);
}


static void
set_property (GObject            *object,
              guint               prop_id,
              const GValue       *value,
              GParamSpec         *pspec)
{
	KzDownloadBox *dlbox = KZ_DOWNLOAD_BOX(object);
  
	switch (prop_id)
	{
	case PROP_KZ_WINDOW:
		dlbox->kz = 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)
{
	KzDownloadBox *dlbox = KZ_DOWNLOAD_BOX(object);

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

GtkWidget *
kz_download_box_new (KzWindow *kz)
{
	KzDownloadBox *dlbox;

	dlbox = g_object_new(KZ_TYPE_DOWNLOAD_BOX,
		       	     "kz-window", kz,
			     NULL);
	
	return GTK_WIDGET(dlbox);
}


static void
dispose (GObject *object)
{
	KzDownloadBox *dlbox = KZ_DOWNLOAD_BOX(object);

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

	if (dlbox->icon_list)
	{
		g_slist_free(dlbox->icon_list);
		dlbox->icon_list = NULL;
	}
	
	if (dlbox->dlgrp)
	{
		g_signal_handlers_disconnect_by_func(dlbox->dlgrp,
						     G_CALLBACK(cb_add_item),
						     dlbox);
		g_signal_handlers_disconnect_by_func(dlbox->dlgrp,
						     G_CALLBACK(cb_remove_item),
						     dlbox);
		g_signal_handlers_disconnect_by_func(dlbox->dlgrp,
						     G_CALLBACK(cb_progress_item),
						     dlbox);
		g_object_unref(dlbox->dlgrp);
		dlbox->dlgrp = NULL;
	}

	if (G_OBJECT_CLASS (kz_download_box_parent_class)->dispose)
		(*G_OBJECT_CLASS (kz_download_box_parent_class)->dispose) (object);
}


static void
drag_data_received (GtkWidget *widget,
                    GdkDragContext *context,
                    gint x, gint y,
                    GtkSelectionData *data,
                    guint info,
                    guint time)
{
	KzDownloadBox *dlbox;
	gchar **strings, *basename;

	dlbox = KZ_DOWNLOAD_BOX(widget);

	switch (info)
	{
	 case TARGET_NETSCAPE_URL:
	 case TARGET_TEXT_URI_LIST:
		if (data->length < 0) return;

		strings = g_strsplit((const gchar*)data->data, "\n", 2);

		basename = g_path_get_basename(strings[0]);
		if (g_file_test(basename, G_FILE_TEST_EXISTS))
		{
			gboolean ret;
			ret = gtkutil_confirm_file_replace(GTK_WINDOW(dlbox->kz),
							   basename);
			if (!ret)
			{
				kz_actions_download_open_save_dialog(GTK_WINDOW(dlbox->kz),
				    				     strings[0], FALSE);
				g_strfreev(strings);
				g_free(basename);
				break;
			}
		}
		
		kz_downloader_group_add_item(dlbox->dlgrp, strings[0]);
		
		g_strfreev(strings);
		g_free(basename);
		gtk_drag_finish(context, TRUE, FALSE, time);
		return;
		break;
	 default:
		break;
	}
	gtk_drag_finish(context, FALSE, FALSE, time);
}


static void
cb_download_icon_destroy (GtkWidget *widget, GtkWidget *menu)
{
	gtk_widget_destroy (menu);
}


static void 
cb_cancel_menu_activate (GtkWidget *widget, KzDownloaderIcon *icon)
{
	kz_downloader_cancel (icon->dl);
}


static void
cb_icon_clicked (GtkWidget *event_box,
		 GdkEventButton *event,
		 KzDownloaderIcon *icon)
{
	GtkWidget *menu, *menuitem;

	switch (event->button) {
	case 1:
		break;
	case 2:
		break;
	case 3:
		menu = gtk_menu_new();
		g_signal_connect(G_OBJECT(icon->event_box), "destroy",
				 G_CALLBACK(cb_download_icon_destroy), menu);
		menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_CANCEL, NULL);
		g_signal_connect(G_OBJECT(menuitem), "activate",
				 G_CALLBACK(cb_cancel_menu_activate), icon);
		gtk_menu_shell_append(GTK_MENU_SHELL (menu), menuitem);
		gtk_widget_show (menuitem);
		gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
				event->button, event->time);
		break;
	default:
		break;
	}
}


static void
cb_add_item (KzDownloaderGroup *dlgrp,
	     KzDownloader      *dl,
	     KzDownloadBox     *dlbox)
{
	KzDownloaderIcon *icon;
	gint width, height;
	GdkPixbuf *orig_pixbuf, *transparent_pixbuf;
	GtkIconSet *icon_set;

	icon = g_new0(KzDownloaderIcon, 1);
	icon->dl    = g_object_ref(dl);

	icon->fraction = 0;

	/* add an icon in download box */
	icon->event_box   = gtk_event_box_new();
	icon->image = gtk_image_new();
	icon->tips  = gtk_tooltips_new();
	dlbox->icon_list = g_slist_append(dlbox->icon_list, icon);

	/* create semitransparent icon image */
	gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height);
	icon_set = gtk_style_lookup_icon_set (GTK_WIDGET(dlbox)->style,
					      GTK_STOCK_SAVE);

	if (icon_set != NULL)
	{
		orig_pixbuf = gtk_icon_set_render_icon (
				icon_set,
				icon->image->style,
				gtk_widget_get_direction (icon->image),
				GTK_WIDGET_STATE (icon->image),
				GTK_ICON_SIZE_MENU,
				icon->image,
				"download icon");
	}
	else
	{
		orig_pixbuf = gtk_widget_render_icon(icon->image,
						     GTK_STOCK_SAVE,
						     GTK_ICON_SIZE_MENU,
						     NULL);
	}
	transparent_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
					    TRUE,
					    8,
					    width,
					    height);
	gdk_pixbuf_fill(transparent_pixbuf, 0);
	gdk_pixbuf_composite(orig_pixbuf,
			     transparent_pixbuf,
			     0, 0,
			     width, height,
			     0, 0,
			     1, 1,
			     GDK_INTERP_NEAREST,
			     64);
		
	gtk_image_set_from_pixbuf(GTK_IMAGE(icon->image), transparent_pixbuf);
	g_object_unref(orig_pixbuf);
	g_object_unref(transparent_pixbuf);

	gtk_container_add(GTK_CONTAINER(icon->event_box), icon->image);
	gtk_widget_show(icon->image);
	gtk_widget_show(icon->event_box);
	gtk_box_pack_start(GTK_BOX(dlbox), icon->event_box, FALSE, FALSE, 0);

	g_signal_connect(icon->event_box, "button_press_event",
			 G_CALLBACK(cb_icon_clicked), icon);

}


static void
cb_remove_item (KzDownloaderGroup *dlgrp,
		KzDownloader      *dl,
		KzDownloadBox     *dlbox)
{
	GSList *list;

	g_return_if_fail(KZ_IS_DOWNLOADER(dl));
	g_return_if_fail(KZ_IS_DOWNLOAD_BOX(dlbox));

	for (list = dlbox->icon_list; list; list = g_slist_next(list))
	{
		KzDownloaderIcon *icon = list->data;
		if (icon->dl == dl)
		{
			dlbox->icon_list = g_slist_remove(dlbox->icon_list, icon);
			remove_icon(icon);
			g_object_unref(icon->dl);
			icon->dl = NULL;
			g_free(icon);
			break;
		}
	}	

}


static void
cb_progress_item (KzDownloaderGroup *dlgrp,
		  KzDownloader      *dl,
		  KzDownloadBox     *dlbox)
{
	GSList *list;
	gchar *percent_str;
	gint percent;
	KzDownloaderIcon *icon = NULL;
	gint width, height, fraction;

	g_return_if_fail(KZ_IS_DOWNLOADER(dl));
	g_return_if_fail(KZ_IS_DOWNLOADER_GROUP(dlgrp));
	g_return_if_fail(KZ_IS_DOWNLOAD_BOX(dlbox));

	/* find icon */
	for (list = dlbox->icon_list; list; list = g_slist_next(list))
	{
		if (list->data && ((KzDownloaderIcon *) list->data)->dl == dl)
		{
			icon = list->data;
			break;
		}
	}
	if (!icon) return;

	/* set status */
	percent = kz_downloader_get_percent(dl);
	gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height);

	fraction = percent / (100 / height);
	if (fraction > icon->fraction && icon->fraction <= height)
	{
		GdkPixbuf *orig_pixbuf, *pixbuf;
		gchar *direction;
		gint x = 0, y = 0;

		icon->fraction = fraction;
		direction = KZ_CONF_GET_STR("Download",
					    "icon_fade_in_direction");
		orig_pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(icon->image));
		pixbuf = gtk_widget_render_icon(icon->image,
						GTK_STOCK_SAVE, 
						GTK_ICON_SIZE_MENU,
						NULL);
		if (direction)
		{
			if (!strcasecmp(direction, "down"))
			{
				height = height * percent / 100;
			}
			else if (!strcasecmp(direction, "left"))
			{
				width = width * percent / 100;
			}
			else if (!strcasecmp(direction, "right"))
			{
				x = width - width * percent / 100;
				width = width * percent / 100;
			}
			else if (!strcasecmp(direction, "up"))
			{
				y = height - height * percent / 100;
				height = height * percent / 100;
			}
			else
			{
				g_warning(_("KzDownloadBox: "
					    "unknown the direction of icon fading in!: %s"),
					  direction);
				y = height - height * percent / 100;
				height = height * percent / 100;
			}
		}
		else /* upward by default */
		{
			y = height - height * percent / 100;
			height = height * percent / 100;
		}
		gdk_pixbuf_composite(pixbuf,
				     orig_pixbuf,
				     x, y,
				     width, height,
				     0, 0,
				     1, 1,
				     GDK_INTERP_NEAREST,
				     255);
		gtk_image_set_from_pixbuf(GTK_IMAGE(icon->image),
					  orig_pixbuf);
		g_object_unref(pixbuf);
		if(direction)
			g_free(direction);
	}
	percent_str = g_strdup_printf("%s:%02d%%",
				      dl->filename,
				      percent);
	gtk_tooltips_set_tip(icon->tips, icon->event_box,
			     percent_str,
			     NULL);
	g_free(percent_str);
}


static void
remove_icon (KzDownloaderIcon *icon)
{
	gtk_widget_destroy(icon->event_box);
}
