/* 
 * Copyright (C) 2005 Sasha Vasko <sasha at aftercode.net>
 *
 * 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 of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#define LOCAL_DEBUG
#include "../configure.h"

#include "../libAfterStep/asapp.h"
#include "../libAfterStep/screen.h"
#include "../libAfterImage/afterimage.h"


#include "asgtk.h"
#include "asgtkai.h"
#include "asgtkimageview.h"

#define NO_IMAGE_TEXT 	"No image to display"


/*  local function prototypes  */
static void asgtk_image_view_class_init (ASGtkImageViewClass * klass);
static void asgtk_image_view_init (ASGtkImageView * iv);
static void asgtk_image_view_dispose (GObject * object);
static void asgtk_image_view_finalize (GObject * object);
static void asgtk_image_view_style_set (GtkWidget * widget,
																				GtkStyle * prev_style);

/*  private variables  */
static GtkFrameClass *parent_class = NULL;

GType asgtk_image_view_get_type (void)
{
	static GType iv_type = 0;

	if (!iv_type) {
		static const GTypeInfo iv_info = {
			sizeof (ASGtkImageViewClass),
			(GBaseInitFunc) NULL,
			(GBaseFinalizeFunc) NULL,
			(GClassInitFunc) asgtk_image_view_class_init,
			NULL,											/* class_finalize */
			NULL,											/* class_data     */
			sizeof (ASGtkImageView),
			0,												/* n_preallocs    */
			(GInstanceInitFunc) asgtk_image_view_init,
		};

		iv_type =
				g_type_register_static (GTK_TYPE_FRAME, "ASGtkImageView", &iv_info,
																0);
	}

	return iv_type;
}

static void asgtk_image_view_class_init (ASGtkImageViewClass * klass)
{
	GObjectClass *object_class = G_OBJECT_CLASS (klass);
	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);

	parent_class = g_type_class_peek_parent (klass);

	object_class->dispose = asgtk_image_view_dispose;
	object_class->finalize = asgtk_image_view_finalize;

	widget_class->style_set = asgtk_image_view_style_set;
}

static void asgtk_image_view_init (ASGtkImageView * iv)
{
	iv->image_entry = NULL;
	iv->aspect_x = -1;
	iv->aspect_y = -1;
	iv->view_width = -1;
	iv->view_height = -1;
	gtk_frame_set_shadow_type (GTK_FRAME (iv), GTK_SHADOW_NONE);
}

static void asgtk_image_view_dispose (GObject * object)
{
	ASGtkImageView *iv = ASGTK_IMAGE_VIEW (object);

	unref_asimage_list_entry (iv->image_entry);
	iv->image_entry = NULL;
	G_OBJECT_CLASS (parent_class)->dispose (object);
}

static void asgtk_image_view_finalize (GObject * object)
{
	G_OBJECT_CLASS (parent_class)->finalize (object);
}

static void
asgtk_image_view_style_set (GtkWidget * widget, GtkStyle * prev_style)
{
	ASGtkImageView *iv = ASGTK_IMAGE_VIEW (widget);

	GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);

	gtk_widget_modify_bg (iv->view, GTK_STATE_NORMAL,
												&widget->style->base[GTK_STATE_NORMAL]);
	gtk_widget_modify_bg (iv->view, GTK_STATE_INSENSITIVE,
												&widget->style->base[GTK_STATE_NORMAL]);
}

static void display_image_view (ASGtkImageView * iv)
{
	ASImage *im = iv->image_entry ? iv->image_entry->preview : NULL;
	GdkPixbuf *pb = NULL;
	ASImage *scaled = NULL, *tiled = NULL;
	int scaled_w, scaled_h;
	int tiled_h, tiled_w;
	ASVisual *asv = get_screen_visual (NULL);
	int view_w, view_h;

	if (im == NULL) {
		gtk_image_set_from_stock (GTK_IMAGE (iv->view),
															GTK_STOCK_MISSING_IMAGE,
															GTK_ICON_SIZE_BUTTON);
		return;
	}
#if 1
	view_w = iv->view_width;
	view_h = iv->view_height;
	if (view_w <= 0 || view_h <= 0)
		return;

	scaled_w = im->width;
	scaled_h = im->height;

	if (get_flags (iv->flags, ASGTK_IMAGE_VIEW_SCALE_TO_VIEW)) {
		if (get_flags (iv->flags, ASGTK_IMAGE_VIEW_TILE_TO_ASPECT)
				&& iv->aspect_x > 0 && iv->aspect_y > 0) {
			scaled_w = (im->width * view_w) / iv->aspect_x;
			scaled_h = (im->height * view_h) / iv->aspect_y;
		} else {
			scaled_w = view_w;
			scaled_h = view_h;
		}
	} else if (get_flags (iv->flags, ASGTK_IMAGE_VIEW_SCALE_TO_ASPECT)
						 && iv->aspect_x > 0 && iv->aspect_y > 0) {
		scaled_w = iv->aspect_x;
		scaled_h = iv->aspect_y;
	}

	tiled_w = scaled_w;
	tiled_h = scaled_h;

	if (get_flags (iv->flags, ASGTK_IMAGE_VIEW_TILE_TO_ASPECT)
			&& iv->aspect_x > 0 && iv->aspect_y > 0) {
		if (get_flags (iv->flags, ASGTK_IMAGE_VIEW_SCALE_TO_VIEW)) {
			if (tiled_w < view_w)
				tiled_w = view_w;
			if (tiled_h < view_h)
				tiled_h = view_h;
		} else {
			if (tiled_w < iv->aspect_x)
				tiled_w = iv->aspect_x;
			if (tiled_h < iv->aspect_y)
				tiled_h = iv->aspect_y;
		}
	}
	if (get_flags (iv->flags, ASGTK_IMAGE_VIEW_TILE_TO_VIEW)) {
		if (tiled_w < view_w)
			tiled_w = view_w;
		if (tiled_h < view_h)
			tiled_h = view_h;
	}


	LOCAL_DEBUG_OUT ("scaled size is %dx%d, tiled size %dx%d", scaled_w,
									 scaled_h, tiled_w, tiled_h);
	if (scaled_w != im->width || scaled_h != im->height) {
		scaled =
				scale_asimage (asv, im, scaled_w, scaled_h, ASA_ASImage, 0,
											 ASIMAGE_QUALITY_DEFAULT);
		if (scaled)
			im = scaled;
	}

	if (tiled_w != im->width || tiled_h != im->height) {
		tiled = tile_asimage (asv, im, 0, 0, tiled_w, tiled_h,
													TINT_LEAVE_SAME, ASA_ASImage, 0,
													ASIMAGE_QUALITY_DEFAULT);
		if (tiled)
			im = tiled;
	}

	pb = ASImage2GdkPixbuf (im);
	if (tiled)
		destroy_asimage (&tiled);
	if (scaled)
		destroy_asimage (&scaled);
	if (pb) {
		gtk_image_set_from_pixbuf (GTK_IMAGE (iv->view), pb);
		g_object_unref (pb);
	}
	LOCAL_DEBUG_OUT ("####!!! recquisition is %dx%d",
									 GTK_WIDGET (iv->view)->requisition.width,
									 GTK_WIDGET (iv->view)->requisition.height);
#endif
}



static void
asgtk_imview_view_size_alloc (GtkWidget * widget,
															GtkAllocation * allocation,
															gpointer user_data)
{
	ASGtkImageView *iv = ASGTK_IMAGE_VIEW (user_data);
	int view_w, view_h;
	int w = allocation->width - 4;
	int h = allocation->height - 4;

	view_w = GTK_WIDGET (iv->view)->requisition.width;
	view_h = GTK_WIDGET (iv->view)->requisition.height;

	LOCAL_DEBUG_OUT ("####!!! SizeAlloc for %p is %dx%d%+d%+d", widget,
									 allocation->width, allocation->height, allocation->x,
									 allocation->y);
	LOCAL_DEBUG_OUT ("####!!! recquisition was %dx%d",
									 widget->requisition.width, widget->requisition.height);
	LOCAL_DEBUG_OUT ("####!!! view size is     %dx%d", iv->view_width,
									 iv->view_height);

#if 1														/* if size changed - refresh */
	if (iv->view_width != w || iv->view_height != h) {
		iv->view_width = w;
		iv->view_height = h;
		display_image_view (iv);
	}
#endif
}

static gfloat get_old_ratio (ASGtkImageView * iv)
{
	gfloat old_ratio;

	g_object_get (G_OBJECT (iv->frame), "ratio", &old_ratio, NULL);
	return old_ratio;
}


static Bool set_aspect_ratio_from_image (ASGtkImageView * iv)
{
	gfloat old_ratio, new_ratio;

	if (iv->image_entry && iv->image_entry->preview)
		new_ratio =
				(gfloat) iv->image_entry->preview->width /
				(gfloat) iv->image_entry->preview->height;
	else
		new_ratio = 1.0;
	old_ratio = get_old_ratio (iv);
	if (old_ratio == new_ratio)
		return False;

	gtk_aspect_frame_set (GTK_ASPECT_FRAME (iv->frame), 0.5, 0.5, new_ratio,
												FALSE);
	return True;
}

static void setup_asgtk_image_view_layout_vert (ASGtkImageView * iv)
{
	GtkWidget *main_vbox;

	/***************************************/
	/* Layout code : */
	main_vbox = gtk_vbox_new (FALSE, 0);
	gtk_widget_show (main_vbox);
	gtk_container_add (GTK_CONTAINER (iv), main_vbox);

	gtk_box_pack_start (GTK_BOX (main_vbox), iv->frame, TRUE, TRUE, 0);

	gtk_box_pack_end (GTK_BOX (main_vbox), iv->tools_hbox, FALSE, FALSE, 0);
	gtk_box_pack_end (GTK_BOX (main_vbox), iv->details_frame, FALSE, FALSE,
										5);

}

static void setup_asgtk_image_view_layout_hor (ASGtkImageView * iv)
{
	GtkWidget *main_hbox, *buttons_vbox, *buttons_frame;

	/***************************************/
	/* Layout code : */
	main_hbox = gtk_hbox_new (FALSE, 0);
	gtk_widget_show (main_hbox);
	gtk_container_add (GTK_CONTAINER (iv), main_hbox);

	gtk_box_pack_start (GTK_BOX (main_hbox), iv->frame, TRUE, TRUE, 0);

	buttons_vbox = gtk_vbox_new (FALSE, 0);
	gtk_widget_show (buttons_vbox);
	gtk_box_pack_end (GTK_BOX (main_hbox), buttons_vbox, FALSE, FALSE, 0);

	buttons_frame = gtk_frame_new (NULL);
	gtk_widget_show (buttons_frame);
	gtk_container_set_border_width (GTK_CONTAINER (buttons_frame), 0);
	gtk_frame_set_shadow_type (GTK_FRAME (buttons_frame), GTK_SHADOW_NONE);
	colorize_gtk_widget (buttons_frame, get_colorschemed_style_normal ());
	gtk_container_add (GTK_CONTAINER (buttons_frame), iv->tools_hbox);

	gtk_box_pack_start (GTK_BOX (buttons_vbox), iv->details_frame, FALSE,
											FALSE, 5);
	gtk_box_pack_end (GTK_BOX (buttons_vbox), buttons_frame, TRUE, TRUE, 0);
}

static void
asgtk_image_view_make_parts (ASGtkImageView * iv, Bool horizontal)
{
	iv->frame = gtk_aspect_frame_new (NULL, 0.5, 0.5, 1.0, TRUE);
	gtk_frame_set_shadow_type (GTK_FRAME (iv->frame), GTK_SHADOW_NONE);
	gtk_widget_show (iv->frame);
	colorize_gtk_widget (iv->frame, get_colorschemed_style_normal ());

	iv->scrolled_window =
			ASGTK_SCROLLED_WINDOW (GTK_POLICY_NEVER, GTK_POLICY_NEVER,
														 GTK_SHADOW_NONE);
	ASGTK_CONTAINER_ADD (iv->frame, iv->scrolled_window);

	if (!get_flags
			(iv->flags,
			 ASGTK_IMAGE_VIEW_SCALE_TO_VIEW | ASGTK_IMAGE_VIEW_TILE_TO_VIEW)) {
		gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW
																		(iv->scrolled_window),
																		GTK_POLICY_AUTOMATIC,
																		GTK_POLICY_AUTOMATIC);
	}
	colorize_gtk_widget (GTK_WIDGET (iv->scrolled_window),
											 get_colorschemed_style_normal ());

	iv->view = gtk_image_new_from_pixbuf (NULL);
	gtk_widget_show (GTK_WIDGET (iv->view));
	gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW
																				 (iv->scrolled_window),
																				 GTK_WIDGET (iv->view));
	colorize_gtk_widget (GTK_WIDGET (iv->view),
											 get_colorschemed_style_normal ());

	g_signal_connect ((gpointer) iv->scrolled_window, "size-allocate",
										G_CALLBACK (asgtk_imview_view_size_alloc), iv);
	iv->details_label = gtk_label_new (NO_IMAGE_TEXT);
	gtk_widget_show (iv->details_label);

	iv->details_frame = gtk_frame_new (NULL);
	gtk_widget_show (iv->details_frame);
	gtk_container_set_border_width (GTK_CONTAINER (iv->details_frame), 1);
	gtk_frame_set_shadow_type (GTK_FRAME (iv->details_frame), GTK_SHADOW_IN);
	colorize_gtk_widget (iv->details_frame,
											 get_colorschemed_style_normal ());

	iv->tools_hbox =
			horizontal ? gtk_vbox_new (FALSE, 0) : gtk_hbutton_box_new ();
	gtk_container_set_border_width (GTK_CONTAINER (iv->tools_hbox), 0);
	if (GTK_IS_BUTTON_BOX (iv->tools_hbox))
		gtk_button_box_set_layout (GTK_BUTTON_BOX (iv->tools_hbox),
															 GTK_BUTTONBOX_END /*SPREAD*/);
	gtk_widget_show (iv->tools_hbox);

	iv->details_hbox =
			horizontal ? gtk_vbutton_box_new () : gtk_hbutton_box_new ();
	gtk_container_set_border_width (GTK_CONTAINER (iv->details_hbox), 0);
	gtk_button_box_set_layout (GTK_BUTTON_BOX (iv->details_hbox),
														 GTK_BUTTONBOX_EDGE);
	gtk_widget_show (iv->details_hbox);

	gtk_container_add (GTK_CONTAINER (iv->details_frame), iv->details_hbox);
	gtk_box_pack_end (GTK_BOX (iv->details_hbox), iv->details_label, TRUE,
										TRUE, 0);

}

/*  public functions  */

GtkWidget *asgtk_image_view_new ()
{
	ASGtkImageView *iv;

	iv = g_object_new (ASGTK_TYPE_IMAGE_VIEW, NULL);

	asgtk_image_view_make_parts (iv, False);
	setup_asgtk_image_view_layout_vert (iv);

	LOCAL_DEBUG_OUT ("created image ASGtk view object %p", iv);
	return GTK_WIDGET (iv);
}

GtkWidget *asgtk_image_view_new_horizontal ()
{
	ASGtkImageView *iv;

	iv = g_object_new (ASGTK_TYPE_IMAGE_VIEW, NULL);

	asgtk_image_view_make_parts (iv, True);
	setup_asgtk_image_view_layout_hor (iv);

	LOCAL_DEBUG_OUT ("created image ASGtk view object %p", iv);
	return GTK_WIDGET (iv);
}

void
asgtk_image_view_set_entry (ASGtkImageView * iv,
														ASImageListEntry * image_entry)
{
	g_return_if_fail (ASGTK_IS_IMAGE_VIEW (iv));

	LOCAL_DEBUG_OUT (" ASGtk image view object's %p entry to %p", iv,
									 image_entry);
	unref_asimage_list_entry (iv->image_entry);
	iv->image_entry = ref_asimage_list_entry (image_entry);

	if (iv->image_entry) {
#if 1
		asgtk_image_view_refresh (iv, (iv->image_entry->preview == NULL));

#endif
	} else {
		gtk_label_set_text (GTK_LABEL (iv->details_label), NO_IMAGE_TEXT);
		gtk_image_set_from_stock (GTK_IMAGE (iv->view),
															GTK_STOCK_MISSING_IMAGE,
															GTK_ICON_SIZE_BUTTON);
	}

}

ASImageListEntry *asgtk_image_view_get_entry (ASGtkImageView * iv)
{
	if (ASGTK_IS_IMAGE_VIEW (iv))
		return ref_asimage_list_entry (iv->image_entry);
	return NULL;
}

void
asgtk_image_view_set_aspect (ASGtkImageView * iv, int aspect_x,
														 int aspect_y)
{
	Bool changed = False;

	g_return_if_fail (ASGTK_IS_IMAGE_VIEW (iv));

	if (aspect_x <= 0 || aspect_y <= 0) {
		iv->aspect_x = iv->aspect_y = -1;
		changed = set_aspect_ratio_from_image (iv);
	} else {
		gfloat old_ratio, new_ratio;

		iv->aspect_x = aspect_x;
		iv->aspect_y = aspect_y;
		new_ratio = (gfloat) aspect_x / (gfloat) aspect_y;
		old_ratio = get_old_ratio (iv);
		if (old_ratio != new_ratio) {
			changed = True;
			gtk_aspect_frame_set (GTK_ASPECT_FRAME (iv->frame), 0.5, 0.5,
														new_ratio, FALSE);
		}
	}
	if (!changed)
		display_image_view (iv);
	else
		gtk_image_set_from_pixbuf (GTK_IMAGE (iv->view), NULL);
}

void
asgtk_image_view_set_resize (ASGtkImageView * iv,
														 unsigned long resize_flags,
														 unsigned long set_mask)
{
	unsigned long new_flags;

	g_return_if_fail (ASGTK_IS_IMAGE_VIEW (iv));

	new_flags = (iv->flags & (~set_mask)) | (resize_flags & set_mask);
	if (new_flags == iv->flags)
		return;

	iv->flags = new_flags;
	if (get_flags
			(new_flags,
			 ASGTK_IMAGE_VIEW_SCALE_TO_VIEW | ASGTK_IMAGE_VIEW_TILE_TO_VIEW)) {
		gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW
																		(iv->scrolled_window),
																		GTK_POLICY_NEVER, GTK_POLICY_NEVER);
	} else {
		gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW
																		(iv->scrolled_window),
																		GTK_POLICY_AUTOMATIC,
																		GTK_POLICY_AUTOMATIC);
	}
	if (iv->image_entry) {
		display_image_view (iv);
	}
}

void
asgtk_image_view_add_detail (ASGtkImageView * iv, GtkWidget * detail,
														 int spacing)
{
	g_return_if_fail (ASGTK_IS_IMAGE_VIEW (iv));
	if (detail) {
		gtk_box_pack_start (GTK_BOX (iv->details_hbox), detail, FALSE, FALSE,
												spacing);
		gtk_box_reorder_child (GTK_BOX (iv->details_hbox), iv->details_label,
													 -1);
	}

}

void
asgtk_image_view_add_tool (ASGtkImageView * iv, GtkWidget * tool,
													 int spacing)
{
	g_return_if_fail (ASGTK_IS_IMAGE_VIEW (iv));
	if (tool) {
		if (GTK_IS_VBOX (iv->tools_hbox)) {
			//gtk_widget_set_size_request( tool, iv->details_label->requisition.width, -1 );    
			gtk_box_pack_end (GTK_BOX (iv->tools_hbox), tool, FALSE, FALSE,
												spacing);
		} else
			gtk_box_pack_start (GTK_BOX (iv->tools_hbox), tool, TRUE, TRUE,
													spacing);
		gtk_container_set_border_width (GTK_CONTAINER (iv->tools_hbox), 1);
	}
}

void asgtk_image_view_refresh (ASGtkImageView * iv, Bool reload_file)
{
	g_return_if_fail (ASGTK_IS_IMAGE_VIEW (iv));
	if (iv->image_entry) {

		if (reload_file && iv->image_entry->type <= ASIT_Supported) {
			if (iv->image_entry->preview) {
				safe_asimage_destroy (iv->image_entry->preview);
				iv->image_entry->preview = NULL;
			}
			/* show empty screen while loading background for now : */
			display_image_view (iv);

			LOCAL_DEBUG_OUT ("imman = %p, fullname = \"%s\"",
											 get_screen_image_manager (NULL),
											 iv->image_entry->fullfilename);
			iv->image_entry->preview =
					get_asimage (get_screen_image_manager (NULL),
											 iv->image_entry->fullfilename, 0xffffffff, 100);
			LOCAL_DEBUG_OUT (" ASGtk image view loaded image %p",
											 iv->image_entry->preview);

		}


		if (iv->image_entry->preview) {
			Bool ratio_changed = False;
			char *details_text;

			details_text =
					format_asimage_list_entry_details (iv->image_entry,
																						 GTK_IS_VBUTTON_BOX (iv->
																																 details_hbox));
			gtk_label_set_text (GTK_LABEL (iv->details_label), details_text);
			free (details_text);

			if (iv->aspect_x <= 0 || iv->aspect_y <= 0)
				ratio_changed = set_aspect_ratio_from_image (iv);
			LOCAL_DEBUG_OUT (" ASGtk image view refreshing image %p",
											 iv->image_entry->preview);
			/* redisplay */
			if (!ratio_changed)
				display_image_view (iv);
			else
				gtk_image_set_from_stock (GTK_IMAGE (iv->view),
																	GTK_STOCK_MISSING_IMAGE,
																	GTK_ICON_SIZE_BUTTON);
		}
	}
}


void
asgtk_image_view_screen_aspect_toggle (GtkWidget * checkbutton,
																			 gpointer data)
{
	ASGtkImageView *iv = ASGTK_IMAGE_VIEW (data);

	if (GTK_TOGGLE_BUTTON (checkbutton)->active) {
		asgtk_image_view_set_aspect (iv, get_screen_width (NULL),
																 get_screen_height (NULL));
		asgtk_image_view_set_resize (iv, ASGTK_IMAGE_VIEW_TILE_TO_ASPECT,
																 ASGTK_IMAGE_VIEW_TILE_TO_ASPECT);
	} else {
		asgtk_image_view_set_aspect (iv, -1, -1);
		asgtk_image_view_set_resize (iv, 0, ASGTK_IMAGE_VIEW_TILE_TO_ASPECT);
	}
}

void
asgtk_image_view_scale_to_view_toggle (GtkWidget * checkbutton,
																			 gpointer data)
{
	ASGtkImageView *iv = ASGTK_IMAGE_VIEW (data);

	if (GTK_TOGGLE_BUTTON (checkbutton)->active)
		asgtk_image_view_set_resize (iv, ASGTK_IMAGE_VIEW_SCALE_TO_VIEW,
																 ASGTK_IMAGE_VIEW_SCALE_TO_VIEW);
	else
		asgtk_image_view_set_resize (iv, 0, ASGTK_IMAGE_VIEW_SCALE_TO_VIEW);
}
