#include <string.h>
#include <gtk/gtk.h>
#include "guiutils.h"
#include "edvpixmap.h"


#ifndef DEBUG_LEVEL
# define DEBUG_LEVEL	0
#endif


GList *EDVPixmapListNew(
	GList *glist,
	guint8 **data, const gchar *name,
	edv_pixmap **p_rtn
);
GList *EDVPixmapListClean(GList *glist);

edv_pixmap *EDVPixmapListMatchByName(
	GList *glist, const gchar *name  
);

edv_pixmap *EDVPixmapNew(guint8 **data, const gchar *name);
void EDVPixmapDelete(edv_pixmap *p);


#define ATOI(s)         (((s) != NULL) ? atoi(s) : 0)
#define ATOL(s)         (((s) != NULL) ? atol(s) : 0)
#define ATOF(s)         (((s) != NULL) ? atof(s) : 0.0f)
#define STRDUP(s)       (((s) != NULL) ? g_strdup(s) : NULL)

#define MAX(a,b)        (((a) > (b)) ? (a) : (b))
#define MIN(a,b)        (((a) < (b)) ? (a) : (b))
#define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))
#define STRLEN(s)       (((s) != NULL) ? strlen(s) : 0)
#define STRISEMPTY(s)   (((s) != NULL) ? (*(s) == '\0') : TRUE)


/*
 *	Creates a new Pixmap as needed or returns one that matches
 *	the specified values from the list.
 */
GList *EDVPixmapListNew(
	GList *glist, 
	guint8 **data, const gchar *name,
	edv_pixmap **p_rtn
)
{
	/* Check if pixmap already exists with the specified name */
	edv_pixmap *p = EDVPixmapListMatchByName(glist, name);
	if(p != NULL)
	{
#if (DEBUG_LEVEL >= 1)  
 g_print(
  "EDVPixmapListNew(): Returning existing edv_pixmap \"%s\" with %i ref counts\n",
  name,
  gdk_window_get_ref_count(p->pixmap)
 );
#endif
	    if(p_rtn != NULL)
		*p_rtn = p;
	    return(glist);
	}
	else
	{
	    GList *glist_ptr = glist;

	    /* Need to create a new pixmap */
	    p = EDVPixmapNew(data, name);

	    /* Add to the list, look for an available pointer first,
	     * if none are available then append to the list
	     */	    
	    while(glist_ptr != NULL)
	    {
		if(glist_ptr->data == NULL)
		    break;
		glist_ptr = g_list_next(glist_ptr);
	    }
	    /* Found available pointer? */
	    if(glist_ptr != NULL)
		glist_ptr->data = p;
	    else
		glist = g_list_append(glist, p);

#if (DEBUG_LEVEL >= 1)
 g_print(
  "EDVPixmapListNew(): Creating new edv_pixmap \"%s\"\n",
  name                                        
 );   
#endif
	    if(p_rtn != NULL)
		*p_rtn = p;
	    return(glist);
	}
}

/*
 *	Deletes all pixmaps in the list that have only 1 reference
 *	count remaining
 */
GList *EDVPixmapListClean(GList *glist)
{
	edv_pixmap *p;
	GList *glist2 = glist;

#if (DEBUG_LEVEL >= 3)
 g_print(
  "EDVPixmapListClean(): Cleaning edv_pixmaps...\n"
 );
#endif

	/* Iterate through list and delete pixmaps with only 1 ref
	 * count or less remaining
	 */
	while(glist2 != NULL)
	{
	    p = EDV_PIXMAP(glist2->data);
	    if(p != NULL)
	    {
#if (DEBUG_LEVEL >= 3)
 g_print(
  "EDVPixmapListClean(): Checking edv_pixmap \"%s\"\n",
  p->name
 );
#endif
		/* This pixmap only has one ref count left? */
		if(gdk_window_get_ref_count(p->pixmap) <= 1)
		{
#if (DEBUG_LEVEL >= 2)
 g_print(
  "EDVPixmapListClean(): Found edv_pixmap \"%s\" with 1 or less ref counts remaining\n",
  p->name
 );
#endif
		    /* Delete this pixmap and remove it from the list,
		     * then start the search from the beginning again
		     */
		    EDVPixmapDelete(p);
		    glist2 = glist = g_list_remove(glist, p);
		    continue;
		}
	    }
	    glist2 = g_list_next(glist2);
	}
	return(glist);
}


/*
 *	Returns a pixmap from the list who's name matches the specified
 *	the specified name.
 */
edv_pixmap *EDVPixmapListMatchByName(
	GList *glist, const gchar *name
)
{
	edv_pixmap *p;

	if(STRISEMPTY(name))
	    return(NULL);

#if (DEBUG_LEVEL >= 3)
 g_print(
  "EDVPixmapListMatchByName(): Searching for edv_pixmap \"%s\"...\n",
  >name
 );
#endif

	while(glist != NULL)
	{
	    p = EDV_PIXMAP(glist->data);
	    if(p != NULL)
	    {
#if (DEBUG_LEVEL >= 3)
 g_print(
  "EDVPixmapListMatchByName(): Checking edv_pixmap \"%s\"\n",
  p->name
 );
#endif
		if((p->name != NULL) ? !strcmp(p->name, name) : FALSE)
		{
#if (DEBUG_LEVEL >= 2)
 g_print(
  "EDVPixmapListMatchByName(): Matched edv_pixmap \"%s\"\n",
  p->name
 );
#endif
		    return(p);
		}
	    }
	    glist = g_list_next(glist);
	}

	return(NULL);
}



/*
 *	Creates a new Pixmap from the specified XPM data.
 */
edv_pixmap *EDVPixmapNew(guint8 **data, const gchar *name)
{
	edv_pixmap *p = EDV_PIXMAP(g_malloc0(
	    sizeof(edv_pixmap)
	));

	/* XPM data given? */
	if(data != NULL)
	{
	    GdkPixmap *pixmap;

	    /* Create pixmap and mask pair from the XPM data */
	    p->pixmap = pixmap = GDK_PIXMAP_NEW_FROM_XPM_DATA(
		&p->mask, data
	    );
	    if(pixmap != NULL)
	    {
		gdk_window_get_size(pixmap, &p->width, &p->height);
		p->data = data;
	    }
	}

	/* Set name */
	p->name = STRDUP(name);
	if(STRISEMPTY(p->name))
	    g_printerr(
"EDVPixmapNew(): Warning:\
 Creating edv_pixmap 0x%.8x from data 0x%.8x with no name.\n",
		(guint32)p, (guint32)data
	    );

	/* failed to load pixmap? */
	if((data != NULL) && (p->pixmap == NULL))
	    g_printerr(
"EDVPixmapNew(): Warning:\
 Failed to load GdkPixmap for edv_pixmap \"%s\" from data 0x%.8x.\n",
		p->name, (guint32)data
	    );


	return(p);
}

/*
 *	Deletes the Pixmap.
 */
void EDVPixmapDelete(edv_pixmap *p)
{
	if(p == NULL)
	    return;

#if (DEBUG_LEVEL >= 1)
 g_print(
  "EDVPixmapDelete(): Deleting edv_pixmap \"%s\"\n",
  p->name
 );
#endif

	if(p->pixmap != NULL)
	{
	    const gint ref_count = gdk_window_get_ref_count(p->pixmap);
	    if(ref_count > 1)
		g_printerr(
"EDVPixmapDelete(): Warning:\
 Deleting edv_pixmap \"%s\" with %i reference counts.\n",
		    p->name, ref_count
		);
	}

	GDK_PIXMAP_UNREF(p->pixmap)
	GDK_BITMAP_UNREF(p->mask)
	g_free(p->name);
	g_free(p);
}
