/*  xfce4
 * 
 * Copyright (c) 2002-2004 The Xfce Development Team
 * Copyright (c) 2004-2006 Brian Tarricone <bjt23@cornell.edu>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; 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

#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif

#ifndef PATH_MAX
#define PATH_MAX 1024
#endif

#include <math.h>
#include <libxfce4util/libxfce4util.h>

#include "icons.h"

static GtkIconTheme *icon_theme = NULL;

static const gchar *builtin_icon_categories[][XFCE_N_BUILTIN_ICON_CATEGORIES] =
{
	{ "xfce-unknown", "unknown", "gnome-fs-executable", "exec", "emblem-generic", NULL, NULL },
	{ "accessories-text-editor", "xfce-edit", "gedit-icon", "edit", NULL, NULL, NULL },
	{ "system-file-manager", "xfce-filemanager", "file-manager", "folder", NULL, NULL, NULL },
	{ "applications-utilities", "xfce-utils", "applications-accessories", "gnome-util", "utilities", NULL, NULL },
	{ "applications-games", "xfce-games", "gnome-joystick", "games", "emblem-fun", NULL, NULL },
	{ "system-help", "xfce-man", "help-browser", "gnome-help", "help", NULL, NULL },
	{ "applications-multimedia", "xfce-multimedia", "gnome-multimedia", "multimedia", "emblem-multimedia", NULL, NULL },
	{ "applications-internet", "xfce-internet", "gnome-globe", "gnome-fs-network", "web-browser", "emblem-web", NULL },
	{ "applications-graphics", "xfce-graphics", "gnome-graphics", "graphics", NULL, NULL, NULL },
	{ "printer", "xfce-printer", "gnome-dev-printer", NULL, NULL, NULL, NULL },
	{ "xfce-schedule", "gnome-month", "productivity", "emblem-documents", "applications-office", NULL, NULL },
	{ "applications-office", "xfce-office", "gnome-applications", NULL, NULL, NULL, NULL },
	{ "xfce-sound", "preferences-desktop-sound", "gnome-audio", "sound", "audio-x-generic", NULL, NULL },
	{ "utilities-terminal", "xfce-terminal", "gnome-terminal", "terminal", NULL, NULL, NULL },
	{ "applications-development", "xfce-devel", "gnome-devel", NULL, NULL, NULL, NULL },
	{ "preferences-desktop", "preferences-system", "xfce-settings", "gnome-settings", NULL, NULL, NULL },
	{ "applications-system", "xfce-system", "gnome-system", NULL, NULL, NULL, NULL },
	{ "xfce-wine", "wine", NULL, NULL, NULL, NULL, NULL },
	{ "applications-accessories", "accessories", "xfce-utils", "gnome-util", "utilities", "gnome-applications", NULL, },
};

/*
 * create a GdkPixbuf from inline data and scale it to a given size
 */
GdkPixbuf *
xfce_inline_icon_at_size (const guint8 *data,
                          int width,
                          int height)
{
    GdkPixbuf *base;

    base = gdk_pixbuf_new_from_inline (-1, data, FALSE, NULL);

    g_return_val_if_fail (base, NULL);

    if ((width < 0 && height < 0)
        || (gdk_pixbuf_get_width (base) == width
            && gdk_pixbuf_get_height (base) == height))
    {
        return base;
    }
    else
    {
        GdkPixbuf *scaled;
        
        scaled = gdk_pixbuf_scale_simple (base,
                                          width >
                                          0 ? width : gdk_pixbuf_get_width (base),
                                          height >
                                          0 ? height :
                                          gdk_pixbuf_get_height (base),
                                          GDK_INTERP_BILINEAR);
        
        g_object_unref (G_OBJECT (base));
        
        return scaled;
    }
}

static inline void
ensure_gtk_icon_theme()
{	
    if(G_UNLIKELY(!icon_theme)) {
        icon_theme = gtk_icon_theme_get_default();
        g_object_add_weak_pointer(G_OBJECT(icon_theme),
                                  (gpointer *)&icon_theme);
    }
}


/**
 * xfce_themed_icon_load:
 * @name: The name of the icon.
 * @size: The requested size of the icon.
 *
 * Uses the current icon theme to find an icon matching @name and @size.  For
 * themed icons, @name should be the root name of the icon, without extension.
 * #xfce_load_themed_icon() will also attempt to directly load icon files if an
 * absoulte or relative path is provided.  If an icon is found, it is resized
 * to the specified size if needed.
 *
 * Return value: A pointer to a #GdkPixbuf, or %NULL on failure.  This data must
 *               be freed with g_object_unref() after use.
 *
 * Since 4.1
 **/
GdkPixbuf *
xfce_themed_icon_load(const gchar *name, gint size)
{
    GdkPixbuf *pix = NULL;
    gchar *name_fixed = NULL, *p;
    
    g_return_val_if_fail(name, NULL);
    
    if(*name == '/' && g_file_test(name, G_FILE_TEST_IS_REGULAR))
        return gdk_pixbuf_new_from_file_at_size(name, size, size, NULL);

    ensure_gtk_icon_theme();

    /* GtkIconTheme doesn't like extensions */
    if((p = g_strrstr(name, ".")) && strlen(p) < 6)
        name_fixed = g_strndup(name, p-name);
    
    pix = gtk_icon_theme_load_icon(icon_theme, name_fixed ? name_fixed : name,
                                   size,
                                   GTK_ICON_LOOKUP_USE_BUILTIN, NULL);

    if(!pix && (p = g_strrstr(name_fixed ? name_fixed : name, "/"))) {
        pix = gtk_icon_theme_load_icon(icon_theme, p+1, size,
                                       GTK_ICON_LOOKUP_USE_BUILTIN, NULL);
    }
    
    g_free(name_fixed);
    
    if (pix)
    {
        int w, h;
        
        w = gdk_pixbuf_get_width (pix);
        h = gdk_pixbuf_get_height (pix);
        
        if (w > size || h > size)
        {
            GdkPixbuf *scaled; 
        
            if (w == h)
            {
                w = h = size;
            }
            else if (w < h)
            {
                h = rint ((double)h * (double)size / (double)w);
                w = size;
            }
            else
            {
                w = rint ((double)w * (double)size / (double)h);
                h = size;
            }
            
            scaled = 
                gdk_pixbuf_scale_simple (pix, w, h, GDK_INTERP_BILINEAR);
            g_object_unref(pix);
            pix = scaled;
        }
    }
    
    return pix;
}

/**
 * xfce_themed_icon_lookup:
 * @name: The name of the icon.
 * @size: The requested size of the icon.
 *
 * Uses the current icon theme to find an icon matching @name and @size.  For
 * themed icons, @name should be the root name of the icon, without extension.
 * #xfce_themed_icon_lookup() will also attempt to directly load icon files if
 * an absoulte or relative path is provided.  
 *
 * Return value: An icon filename (should be freed with #g_free()), or %NULL.
 *
 * Since 4.1
 **/
gchar *
xfce_themed_icon_lookup(const gchar *name, gint size)
{
    GtkIconInfo *info;
    gchar *filename = NULL, *name_fixed = NULL, *p;
    
    g_return_val_if_fail(name, NULL);
    
    if(*name == '/' && g_file_test(name, G_FILE_TEST_IS_REGULAR))
        return g_strdup(name);
    
    ensure_gtk_icon_theme();
    
    /* GtkIconTheme doesn't like extensions */
    if((p = g_strrstr(name, ".")) && strlen(p) < 6)
        name_fixed = g_strndup(name, p-name);
    
    info = gtk_icon_theme_lookup_icon(icon_theme,
                                      name_fixed ? name_fixed : name,
                                      size, 0);
    
    if(!info && (p = g_strrstr(name_fixed ? name_fixed : name, "/")))
        info = gtk_icon_theme_lookup_icon(icon_theme, p+1, size, 0);

    if(info) {
        filename = g_strdup(gtk_icon_info_get_filename(info));
        gtk_icon_info_free(info);
    }
    
    g_free(name_fixed);
    
    return filename;
}

gchar *
xfce_themed_icon_lookup_list(GList *names,
                             gint size)
{
    gchar *filename = NULL;
    GList *l;
    
    g_return_val_if_fail(names, NULL);
    
    for(l = names; l; l = l->next) {
        filename = xfce_themed_icon_lookup((const gchar *)l->data, size);
        if(filename)
            break;
    }
    
    return filename;
}

GdkPixbuf *
xfce_themed_icon_load_list(GList *names,
                           gint size)
{
    GdkPixbuf *pix = NULL;
    GList *l;
    
    g_return_val_if_fail(names, NULL);
    
    for(l = names; l; l = l->next) {
        pix = xfce_themed_icon_load((const gchar *)l->data, size);
        if(pix)
            break;
    }
    
    return pix;
}

gchar *
xfce_themed_icon_lookup_category(XfceIconThemeCategory category,
                                 gint size)
{
    gchar *filename = NULL;
    gint i;
    
    g_return_val_if_fail(category < XFCE_N_BUILTIN_ICON_CATEGORIES, NULL);
        
    for(i = 0; builtin_icon_categories[category][i]; ++i) {
        filename = xfce_themed_icon_lookup(builtin_icon_categories[category][i],
                                           size);
        if(filename)
            break;
    }

	return filename;
}

GdkPixbuf *
xfce_themed_icon_load_category(XfceIconThemeCategory category,
                               gint size)
{
    GdkPixbuf *pix = NULL;
    gint i;
    
    g_return_val_if_fail(category < XFCE_N_BUILTIN_ICON_CATEGORIES, NULL);
    
    for(i = 0; builtin_icon_categories[category][i]; ++i) {
        pix = xfce_themed_icon_load(builtin_icon_categories[category][i],
                                    size);
        if(pix)
            break;
    }
    
    return pix;
}



/*
 * deprecated stuff below here
 */


/**
 * xfce_pixbuf_new_from_file_at_size:
 * @filename: An image file name.
 * @width: The target image width.
 * @height: The target image height.
 * @error: a pointer to a GError, or NULL.
 *
 * Convenience function to avoid GTK_CHECK_VERSION(), as GdkPixbuf 2.2 and below
 * do not have gdk_pixbuf_new_from_file_at_size().
 *
 * Return value: A new GdkPixbuf, sized @width by @height, or NULL if the file
 *               cannot be opened.  If @error is not NULL, it will be set upon
 *               error.
 *
 * Since 4.1
 **/
GdkPixbuf *
xfce_pixbuf_new_from_file_at_size(const gchar *filename, gint width, gint height,
		GError **error)
{
	return gdk_pixbuf_new_from_file_at_size(filename, width, height, error);
}

void
xfce_themed_icon_add_search_path(const gchar *path)
{
    ensure_gtk_icon_theme();
    gtk_icon_theme_prepend_search_path(icon_theme, path);
}

/* deprecated */
GdkPixbuf *
inline_icon_at_size (const guint8 * data, int width, int height)
{
	return xfce_inline_icon_at_size(data, width, height);
}

/**
 * xfce_set_icon_theme:
 * @theme_name: The name of the icon theme.
 *
 * Sets the icon theme that xfce_load_themed_icon() will use when looking up
 * icons.  Note: this function amounts to a no-op if libxfcegui4 is compiled
 * against Gtk+ 2.4.0 or higher, as Gtk+ 2.4.0 has built-in support for icon
 * theming.
 *
 * Since 4.1
 **/
void
xfce_set_icon_theme(const gchar *theme_name)
{
	/* noop */
}

/*< deprecated name; use xfce_themed_icon_load() instead >*/
GdkPixbuf *
xfce_load_themed_icon(const gchar *name, gint size)
{
	return xfce_themed_icon_load(name, size);
}
