/* 
 *  Copyright (C) 2002	Ricardo Fernándezs Pascual <ric@users.sourceforge.net>
 *		  2004	Crispin Flowerday <gnome@flowerday.cx>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

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

#include "bookmarks-icon-provider.h"
#include "gul-general.h"
#include "galeon-debug.h"

/* to render the default icons */
#include "pixbuf-cache.h"
#include <gtk/gtktoolbar.h>

#define GB_ICON_PROVIDER_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), \
					      GB_TYPE_ICON_PROVIDER, GbIconProviderPrivate))

struct _GbIconProviderPrivate
{
	GdkPixbuf *folder_pixbuf_data;
	GdkPixbuf *default_folder_pixbuf_data;
	GdkPixbuf *site_pixbuf_data;
	GdkPixbuf *separator_pixbuf_data;
	gboolean show_default_icon_site;

	GHashTable *alias_icon_cache;
	GdkPixbuf  *alias_mark;
};


static GObjectClass *parent_class = NULL;

/* ------------------------------------------------------------ */
static void
alias_icon_weak_notify_cb (gpointer data,
			   GObject *where_the_object_was)
{
	GHashTable *ht = GB_ICON_PROVIDER (data)->priv->alias_icon_cache;
	g_hash_table_remove (ht, where_the_object_was);
}

/**
 * gb_icon_provider_make_alias_icon: Create an alias icon
 * This returns a GdkPixbuf, which the caller must unref
 */
GdkPixbuf *
gb_icon_provider_make_alias_icon (GbIconProvider *ip, GdkPixbuf *icon)
{
	GbIconProviderPrivate *p = GB_ICON_PROVIDER (ip)->priv;

	GdkPixbuf *ret;
	if (!p->alias_icon_cache)
	{
		p->alias_icon_cache = g_hash_table_new_full (NULL, NULL, NULL,
							     (GDestroyNotify) g_object_unref);
	}

	ret = g_hash_table_lookup (p->alias_icon_cache, icon);
	if (ret) 
	{
		return g_object_ref (ret);
	}

	if (!p->alias_mark)
	{
		char *filename;
		filename = gul_general_user_file ("galeon-bookmark-alias-mark.png", FALSE);
		p->alias_mark = gul_pixbuf_cache_get (filename);
		g_free (filename);
	}

	if (icon)
	{
		ret = gdk_pixbuf_copy (icon);
		if (p->alias_mark)
		{
			int width = gdk_pixbuf_get_width (p->alias_mark);
			int height = gdk_pixbuf_get_height (p->alias_mark);

			gdk_pixbuf_composite (p->alias_mark, ret, 0, 0, width, height,
					      0, 0, 1, 1, GDK_INTERP_BILINEAR, 255);
		}

		g_hash_table_insert (p->alias_icon_cache, icon, ret);
		g_object_weak_ref (G_OBJECT (icon), alias_icon_weak_notify_cb,
				   ip);
	}
	else
	{
		ret = p->alias_mark;
	}

	return g_object_ref (ret);
}



static GdkPixbuf *
gb_icon_provider_icon_provider_get_icon_impl (GbIconProvider *ip, GbBookmark *b)
{
	GbIconProviderPrivate *p = ip->priv;
	GdkPixbuf *ret = NULL;

	LOG ("getting icon for %s", b->name);

	if (GB_IS_FOLDER (b))
	{
		if (gb_folder_is_default_folder (GB_FOLDER (b)))
		{
			ret = p->default_folder_pixbuf_data;
		}
		else
		{
			ret = p->folder_pixbuf_data;
		}
	}
	else if (GB_IS_SEPARATOR (b))
	{
		ret = p->separator_pixbuf_data;
	}
	else if (p->show_default_icon_site)
	{
		ret = p->site_pixbuf_data;
	}

	if (gb_bookmark_is_alias (b))
	{
		return gb_icon_provider_make_alias_icon 
			(GB_ICON_PROVIDER (ip), ret);
	}
	
	return ret ? g_object_ref (ret) : NULL;
}

static gboolean
hash_table_remove_foreach (gpointer key, gpointer value, gpointer user_data)
{
	GbIconProvider *dip = GB_ICON_PROVIDER (user_data);

	g_object_weak_unref (G_OBJECT (key),
			     alias_icon_weak_notify_cb, dip);
	return TRUE; /* remove the icon */
}

static void
gb_icon_provider_clear_cache (GbIconProvider *ip)
{
	if (ip->priv->alias_icon_cache)
	{
		g_hash_table_foreach_remove (ip->priv->alias_icon_cache,
					     hash_table_remove_foreach,
					     ip);
		g_hash_table_destroy (ip->priv->alias_icon_cache);
		ip->priv->alias_icon_cache = NULL;
	}
	
	if (ip->priv->alias_mark)
	{
		g_object_unref (ip->priv->alias_mark);
		ip->priv->alias_mark = NULL;
	}
}


static void
gb_icon_provider_load_default_icons (GbIconProvider *ip)
{
	GbIconProviderPrivate *p = ip->priv;
	GtkWidget *dummy = gtk_toolbar_new ();

	g_object_ref (dummy);
	gtk_object_sink (GTK_OBJECT (dummy));

	if (p->folder_pixbuf_data)
	{
		g_object_unref (p->folder_pixbuf_data);
	}

	if (p->default_folder_pixbuf_data)
	{
		g_object_unref (p->default_folder_pixbuf_data);
	}

	if (p->site_pixbuf_data)
	{
		g_object_unref (p->site_pixbuf_data);
	}

	if (p->separator_pixbuf_data)
	{
		g_object_unref (p->separator_pixbuf_data);
	}

	p->folder_pixbuf_data = 
		gtk_widget_render_icon (dummy, GALEON_STOCK_FOLDER, GTK_ICON_SIZE_MENU, NULL);
	p->default_folder_pixbuf_data =
		gtk_widget_render_icon (dummy, GALEON_STOCK_DEFAULT, GTK_ICON_SIZE_MENU, NULL);
	p->site_pixbuf_data  =
		gtk_widget_render_icon (dummy, GALEON_STOCK_BOOKMARK, GTK_ICON_SIZE_MENU, NULL);
	p->separator_pixbuf_data  =
		gtk_widget_render_icon (dummy, GALEON_STOCK_SEPARATOR, GTK_ICON_SIZE_MENU, NULL);

	g_object_unref (dummy);
}


static void
gb_icon_provider_init (GbIconProvider *ip)
{
	LOG ("GbIconProvider ctor (%p)", ip);

	ip->priv = GB_ICON_PROVIDER_GET_PRIVATE (ip);
	ip->priv->show_default_icon_site = FALSE;

	gb_icon_provider_load_default_icons (ip);
}

static void
gb_icon_provider_finalize (GObject *object)
{
	GbIconProvider *ip = GB_ICON_PROVIDER (object);
	GbIconProviderPrivate *p = ip->priv;

	gb_icon_provider_clear_cache (ip);

	g_object_unref (p->folder_pixbuf_data);
	g_object_unref (p->default_folder_pixbuf_data);
	g_object_unref (p->site_pixbuf_data);
	g_object_unref (p->separator_pixbuf_data);

	LOG ("GbIconProvider dtor (%p)", object);
	G_OBJECT_CLASS (parent_class)->finalize (object);
}

static void
gb_icon_provider_class_init (GbIconProviderClass *klass)
{
	GObjectClass *object_class = G_OBJECT_CLASS (klass);

	parent_class = g_type_class_peek_parent (klass);
	
	object_class->finalize = gb_icon_provider_finalize;
	klass->get_icon = gb_icon_provider_icon_provider_get_icon_impl;

	g_type_class_add_private (object_class, sizeof (GbIconProviderPrivate));

	gul_pixbuf_cache_register_stocks ();
}

GdkPixbuf *
gb_icon_provider_get_icon (GbIconProvider *ip, GbBookmark *b)
{
	return (GB_ICON_PROVIDER_GET_CLASS (ip)->get_icon) (ip, b);
}


G_DEFINE_TYPE (GbIconProvider, gb_icon_provider, G_TYPE_OBJECT);


GbIconProvider *
gb_icon_provider_new (void)
{
	GbIconProvider *ret = g_object_new (GB_TYPE_ICON_PROVIDER, NULL);
	return ret;
}

