#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#ifdef HAVE_IMLIB
# include <Imlib.h>
#endif
#include <gtk/gtk.h>

#include "imgview.h"

#include "cfg.h"
#include "edv_types.h"
#include "edv_obj.h"
#include "imbr.h"
#include "imbr_tlist.h"
#include "imbr_img_view.h"
#include "endeavour2.h"
#include "edv_utils.h"
#include "edv_utils_gtk.h"
#include "edv_cfg_list.h"
#include "config.h"


void EDVImbrImgViewClear(edv_imbr_struct *imbr);
void EDVImbrImgViewLoad(
	edv_imbr_struct *imbr, const gchar *path, gint thumb_num
);


#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)


/*
 *	Clears the Image Browser's ImgView.
 */
void EDVImbrImgViewClear(edv_imbr_struct *imbr)
{
	imgview_struct *iv = (imbr != NULL) ? imbr->imgview : NULL;
	if(iv == NULL)
	    return;

	ImgViewClear(iv);
}


/*
 *	Loads the image file specified by path to the Image Browser's
 *	ImgView, if thumb_num is not -1 then the thumb on the Image
 *	Browser's Thumbs List will be updated as well.
 *
 *	This function will automatically call EDVImbrImgViewClear()
 *	first.
 */
void EDVImbrImgViewLoad(
	edv_imbr_struct *imbr, const gchar *path, gint thumb_num
)
{
	gboolean need_zoom_to_fit = FALSE;
	const gchar *name;
	gint width, height, bpl, nframes;
	const guint8 *first_rgba = NULL;
	GList *rgba_list, *delay_list;
	GdkWindow *window;
	GtkWidget *w;
	const cfg_item_struct *cfg_list;
	imgview_image_struct *img;
	edv_core_struct *core;
	imgview_struct *iv = (imbr != NULL) ? imbr->imgview : NULL;
	if(iv == NULL)
	    return;

	/* Clear the ImgView */
	EDVImbrImgViewClear(imbr);

	core = imbr->core;
	if((core == NULL) || STRISEMPTY(path))
	    return;

	name = g_basename(path);
	cfg_list = core->cfg_list;

	/* Is the file's extension not supported by Imlib? */
	if(!EDVCheckImlibImage(core, name))
	    return;


	EDVImbrSetBusy(imbr, TRUE);

	/* Get the ImgView's view widget and window */
	w = (GtkWidget *)ImgViewGetViewWidget(iv);
	window = (w != NULL) ? w->window : NULL;

	/* Load the image data from the specified file */
	rgba_list = EDVImbrTListLoadImageRGBA(
	    NULL, path,
	    &width, &height, &bpl, &nframes, &delay_list,
	    FALSE,		/* Do not resize for thumbs list */
	    FALSE,		/* Allow enlarge */
	    window
	);
	if(rgba_list == NULL)
	{
	    /* Failed to load image */
	    g_list_free(delay_list);
	    EDVImbrSetBusy(imbr, FALSE);
	    return;
	}

	/* Record the first image data, the RGBA image datas in the
	 * list will be transfered to the ImgView image, however
	 * since the ImgView image will not be deleted, the RGBA image
	 * datas will still be valid until the ImgView image is set
	 * to the ImgView
	 */
	first_rgba = (guint8 *)rgba_list->data;

	/* Check if the image size is larger in any one dimension than
	 * the ImgView's view widget to determine if we need to zoom
	 * to fit
	 */
	if(w != NULL)
	{
	    if((width > w->allocation.width) ||
	       (height > w->allocation.height)
	    )
		need_zoom_to_fit = TRUE;
	}

	/* Create a new ImgView image */
	img = ImgViewImageNew(width, height, 4, bpl);
	if(img != NULL)
	{
	    /* Transfer each RGBA image data to the new ImgView image
	     * and set the RGBA image data as NULL on the RGBA image
	     * list
	     */
	    guint8 *rgba;
	    gulong delay;
	    GList	*glist_rgba = rgba_list,
			*glist_delay = delay_list;
	    while(glist_rgba != NULL)
	    {
		rgba = (guint8 *)glist_rgba->data;
		delay = (gulong)((glist_delay != NULL) ?
		    (guint)glist_delay->data : 0
		);
		ImgViewImageAppendFrame(img, rgba, delay);

		glist_rgba->data = NULL;	/* Mark transfered */

		glist_rgba = g_list_next(glist_rgba);
		glist_delay = g_list_next(glist_delay);
	    }
	}

	/* Update the Thumbs List thumb? */
	if(thumb_num > -1)
	{
	    const gboolean no_enlarge = CFGItemListGetValueI(
		cfg_list, EDV_CFG_PARM_IMBR_THUMB_NO_ENLARGE
	    );
	    tlist_struct *tlist = imbr->tlist;
	    if(tlist != NULL)
	    {
		TListSetRGBA(
		    tlist, thumb_num,
		    width, height, bpl,
		    GDK_RGB_DITHER_NORMAL,
		    first_rgba,		/* First RGBA image data, is
					 * still valid */
		    no_enlarge
		);
		TListSetLoadState(
		    tlist, thumb_num, TLIST_LOAD_STATE_LOADED
		);
	    }
	}

	/* Delete loaded images */
	g_list_foreach(rgba_list, (GFunc)g_free, NULL);
	g_list_free(rgba_list);
	rgba_list = NULL;
	first_rgba = NULL;
	g_list_free(delay_list);
	delay_list = NULL;

	/* Set/transfer the ImgView image to the ImgView */
	if(need_zoom_to_fit)
	    ImgViewSetImageToFit(iv, img);
	else
	    ImgViewSetImage(iv, img);
	img = NULL;	/* Do not reference again after the above call */

	/* Set the ImgView to play if there are multiple frames */
	if(nframes > 1)
	    ImgViewPlay(iv);

	EDVImbrSetBusy(imbr, FALSE);
}
