/* 
 * 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 "asgtkimagedir.h"
#include "asgtkimageview.h"
#include "asgtkimagebrowser.h"

#define DIR_LIST_WIDTH   200
#define DIR_LIST_HEIGHT  150
#define FILE_LIST_WIDTH  200
#define FILE_LIST_HEIGHT 210
#define PREVIEW_WIDTH  480
#define PREVIEW_HEIGHT 360


/*  local function prototypes  */
static void asgtk_image_browser_class_init (ASGtkImageBrowserClass *
																						klass);
static void asgtk_image_browser_init (ASGtkImageBrowser * ib);
static void asgtk_image_browser_dispose (GObject * object);
static void asgtk_image_browser_finalize (GObject * object);
static void asgtk_image_browser_style_set (GtkWidget * widget,
																					 GtkStyle * prev_style);

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

GType asgtk_image_browser_get_type (void)
{
	static GType ib_type = 0;

	if (!ib_type) {
		static const GTypeInfo ib_info = {
			sizeof (ASGtkImageBrowserClass),
			(GBaseInitFunc) NULL,
			(GBaseFinalizeFunc) NULL,
			(GClassInitFunc) asgtk_image_browser_class_init,
			NULL,											/* class_finalize */
			NULL,											/* class_data     */
			sizeof (ASGtkImageBrowser),
			0,												/* n_preallocs    */
			(GInstanceInitFunc) asgtk_image_browser_init,
		};

		ib_type =
				g_type_register_static (GTK_TYPE_WINDOW, "ASGtkImageBrowser",
																&ib_info, 0);
	}

	return ib_type;
}

static void asgtk_image_browser_class_init (ASGtkImageBrowserClass * 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_browser_dispose;
	object_class->finalize = asgtk_image_browser_finalize;

	widget_class->style_set = asgtk_image_browser_style_set;

}

static void asgtk_image_browser_init (ASGtkImageBrowser * ib)
{
}

static void asgtk_image_browser_dispose (GObject * object)
{
	/* ASGtkImageBrowser *ib = ASGTK_IMAGE_BROWSER (object); */
	G_OBJECT_CLASS (parent_class)->dispose (object);
}

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

static void
asgtk_image_browser_style_set (GtkWidget * widget, GtkStyle * prev_style)
{
	/* ASGtkImageBrowser *id = ASGTK_IMAGE_BROWSER (widget); */

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

static char *asgtk_image_browser_make_fullfilename (ASGtkImageBrowser * ib,
																										const char *filename)
{
	if (filename[0] == '.' && filename[1] == '\0')
		return mystrdup (ib->current_dir);

	if (filename[0] == '.' && filename[1] == '.' && filename[2] == '\0') {
		char *sep = strrchr (ib->current_dir, '/');

		if (sep > ib->current_dir)
			return mystrndup (ib->current_dir, sep - ib->current_dir);

		return mystrdup ("/");
	}

	if (filename[0] == '/')
		return mystrdup (filename);

	return make_file_name (ib->current_dir, filename);
}

static void
asgtk_image_browser_dir_activate (GtkTreeView * tree_view,
																	GtkTreePath * path,
																	GtkTreeViewColumn * column,
																	gpointer user_data)
{
	ASGtkImageBrowser *ib = ASGTK_IMAGE_BROWSER (user_data);
	GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
	GtkTreeIter iter;
	char *filename;

	gtk_tree_model_get_iter (model, &iter, path);
	gtk_tree_model_get (model, &iter, 0, &filename, -1);
	LOCAL_DEBUG_OUT ("filename == \"%s\"", filename);
	/* TODO : change directory/populate file list */
	if (filename[0] == '.' && filename[1] == '\0') {
		/* already in current dir - do nothing */
	} else {
		filename = asgtk_image_browser_make_fullfilename (ib, filename);
		asgtk_image_browser_change_dir (ib, filename);
		free (filename);
	}
}

static void
asgtk_image_browser_dir_select (GtkTreeSelection * selection,
																gpointer user_data)
{
	ASGtkImageBrowser *ib = ASGTK_IMAGE_BROWSER (user_data);
	char *filename;
	GtkTreeIter iter;
	GtkTreeModel *model;

	if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
		gtk_tree_model_get (model, &iter, 0, &filename, -1);
		LOCAL_DEBUG_OUT ("filename == \"%s\"", filename);
		/* TODO : change directory/populate file list */
		if (filename[0] == '.' && filename[1] == '\0')
			asgtk_image_dir_set_path (ASGTK_IMAGE_DIR (ib->image_dir),
																ib->current_dir);
		else {
			filename = asgtk_image_browser_make_fullfilename (ib, filename);
			asgtk_image_dir_set_path (ASGTK_IMAGE_DIR (ib->image_dir), filename);
			free (filename);
		}
	}
}

static void on_root_clicked (GtkButton * button, gpointer user_data)
{
	ASGtkImageBrowser *ib = ASGTK_IMAGE_BROWSER (user_data);

	asgtk_image_browser_change_dir (ib, "/");
}

static void on_home_clicked (GtkButton * button, gpointer user_data)
{
	ASGtkImageBrowser *ib = ASGTK_IMAGE_BROWSER (user_data);

	asgtk_image_browser_change_dir (ib, "~/");
}


static void
asgtk_image_browser_path_entry (GtkWidget * widget, gpointer data)
{
	ASGtkImageBrowser *ib = ASGTK_IMAGE_BROWSER (data);

	if (ib->path_entry) {
		const gchar *entry_text =
				gtk_entry_get_text (GTK_ENTRY (ib->path_entry));

		asgtk_image_browser_change_dir (ib, entry_text);
	}
}

static void
asgtk_image_browser_path_changed (GtkWidget * widget, gpointer data)
{
	ASGtkImageBrowser *ib = ASGTK_IMAGE_BROWSER (data);

	if (ib) {
		const gchar *entry_text =
				asgtk_combo_box_get_active_text (GTK_COMBO_BOX (ib->path_combo));

		asgtk_image_browser_change_dir (ib, entry_text);
	}
}

static void
asgtk_image_browser_scale_toggle (GtkWidget * checkbutton, gpointer data)
{
	ASGtkImageBrowser *ib = ASGTK_IMAGE_BROWSER (data);

	asgtk_image_view_set_resize (ib->preview,
															 GTK_TOGGLE_BUTTON (checkbutton)->active ?
															 ASGTK_IMAGE_VIEW_SCALE_TO_VIEW : 0,
															 ASGTK_IMAGE_VIEW_SCALE_TO_VIEW);
}



static void
asgtk_image_browser_create_dir_list (ASGtkImageBrowser * ib,
																		 GtkWidget * list_vbox)
{
	GtkWidget *scrolled_win, *model;
	GtkTreeViewColumn *column;

	model = GTK_WIDGET (gtk_list_store_new (1, G_TYPE_STRING));
	ib->dir_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
	g_object_unref (model);

	column =
			gtk_tree_view_column_new_with_attributes ("Folders",
																								gtk_cell_renderer_text_new
																								(), "text", 0, NULL);
	gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
	gtk_tree_view_append_column (GTK_TREE_VIEW (ib->dir_list), column);

	gtk_widget_set_size_request (ib->dir_list, DIR_LIST_WIDTH,
															 DIR_LIST_HEIGHT);
	g_signal_connect (ib->dir_list, "row_activated",
										G_CALLBACK (asgtk_image_browser_dir_activate), ib);
	g_signal_connect (gtk_tree_view_get_selection
										(GTK_TREE_VIEW (ib->dir_list)), "changed",
										G_CALLBACK (asgtk_image_browser_dir_select), ib);

	scrolled_win =
			ASGTK_SCROLLED_WINDOW (GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS,
														 GTK_SHADOW_IN);

	ASGTK_CONTAINER_CONFIG (scrolled_win, DIR_LIST_WIDTH, DIR_LIST_HEIGHT,
													0);
	ASGTK_CONTAINER_ADD (scrolled_win, ib->dir_list);
	if (GTK_IS_PANED (list_vbox))
		gtk_paned_pack1 (GTK_PANED (list_vbox), GTK_WIDGET (scrolled_win),
										 TRUE, TRUE);
	else
		gtk_box_pack_end (GTK_BOX (list_vbox), GTK_WIDGET (scrolled_win), TRUE,
											TRUE, 0);

	gtk_widget_show (scrolled_win);
	colorize_gtk_tree_view_window (GTK_WIDGET (scrolled_win));
}

static void
asgtk_image_browser_file_sel_handler (ASGtkImageDir * id,
																			gpointer user_data)
{
	ASGtkImageBrowser *ib = ASGTK_IMAGE_BROWSER (user_data);

	g_return_if_fail (ASGTK_IS_IMAGE_DIR (id));
	if (ib) {
		ASImageListEntry *le = asgtk_image_dir_get_selection (id);

		asgtk_image_view_set_entry (ib->preview, le);
		if (le)
			unref_asimage_list_entry (le);
	}
}


/*  public functions  */
GtkWidget *asgtk_image_browser_new ()
{
	ASGtkImageBrowser *ib;
	GtkWidget *main_vbox;
	GtkWidget *shortcuts_hbox, *btn;
	GtkWidget *list_vbox, *preview_vbox;

	ib = g_object_new (ASGTK_TYPE_IMAGE_BROWSER, NULL);
	colorize_gtk_window (GTK_WIDGET (ib));

	gtk_container_set_border_width (GTK_CONTAINER (ib), 5);
	main_vbox = gtk_vbox_new (FALSE, 0);
	gtk_widget_show (main_vbox);
	gtk_container_add (GTK_CONTAINER (ib), main_vbox);
	gtk_box_set_spacing (GTK_BOX (main_vbox), 5);

	shortcuts_hbox = gtk_hbox_new (FALSE, 0);
	gtk_widget_show (shortcuts_hbox);
	gtk_box_pack_start (GTK_BOX (main_vbox), shortcuts_hbox, FALSE, FALSE,
											0);
	gtk_box_set_spacing (GTK_BOX (shortcuts_hbox), 5);

	btn =
			asgtk_add_button_to_box (GTK_BOX (shortcuts_hbox),
															 GTK_STOCK_GOTO_TOP, "/",
															 G_CALLBACK (on_root_clicked), ib);
	gtk_widget_set_size_request (btn, 50, -1);
	btn =
			asgtk_add_button_to_box (GTK_BOX (shortcuts_hbox), GTK_STOCK_HOME,
															 "~/", G_CALLBACK (on_home_clicked), ib);
	gtk_widget_set_size_request (btn, 50, -1);

	ib->path_combo = gtk_combo_box_entry_new_text ();
	//gtk_widget_set_size_request ( ib->path_combo, DIR_LIST_WIDTH+300-105 , -1);
	gtk_box_pack_end (GTK_BOX (shortcuts_hbox), ib->path_combo, TRUE, TRUE,
										10);
	gtk_widget_show (ib->path_combo);
	colorize_gtk_edit (ib->path_combo);
	ib->path_entry = NULL;
	/* path_entry is actually found trough the following discovery process :  */
	if (GTK_IS_CONTAINER (ib->path_combo))
		gtk_container_forall (GTK_CONTAINER (ib->path_combo),
													find_combobox_entry, &(ib->path_entry));
	/* if above succeeded then path_entry should be not NULL here : */
	if (ib->path_entry)
		g_signal_connect (G_OBJECT (ib->path_entry), "activate",
											G_CALLBACK (asgtk_image_browser_path_entry),
											(gpointer) ib);
	g_signal_connect (G_OBJECT (ib->path_combo), "changed",
										G_CALLBACK (asgtk_image_browser_path_changed),
										(gpointer) ib);


	ib->list_hbox = gtk_hpaned_new ();
	colorize_gtk_widget (ib->list_hbox, get_colorschemed_style_normal ());
	gtk_widget_show (ib->list_hbox);
	gtk_box_pack_start (GTK_BOX (main_vbox), ib->list_hbox, TRUE, TRUE, 0);

	ib->main_buttons_hbox = gtk_hbutton_box_new ();
	gtk_hbutton_box_set_layout_default (GTK_BUTTONBOX_SPREAD);
	gtk_widget_show (ib->main_buttons_hbox);
	gtk_box_pack_end (GTK_BOX (main_vbox), ib->main_buttons_hbox, FALSE,
										FALSE, 5);


	/* separator really goes above the buttons box, so it is added second from the end ! */
	ib->separator = gtk_hseparator_new ();
	gtk_box_pack_end (GTK_BOX (main_vbox), ib->separator, FALSE, FALSE, 5);
	colorize_gtk_widget (GTK_WIDGET (ib->separator),
											 get_colorschemed_style_button ());

	/* now designing dirlist controls : */
	list_vbox = gtk_vpaned_new ();
	colorize_gtk_widget (list_vbox, get_colorschemed_style_normal ());
	gtk_widget_show (list_vbox);

	if (GTK_IS_PANED (ib->list_hbox))
		gtk_paned_pack1 (GTK_PANED (ib->list_hbox), list_vbox, FALSE, FALSE);
	else
		gtk_box_pack_start (GTK_BOX (ib->list_hbox), list_vbox, FALSE, FALSE,
												0);

	/* dir list : */
	asgtk_image_browser_create_dir_list (ib, list_vbox);
	/* image file list : */
	ib->image_dir = ASGTK_IMAGE_DIR (asgtk_image_dir_new ());
	if (GTK_IS_PANED (list_vbox))
		gtk_paned_pack2 (GTK_PANED (list_vbox), GTK_WIDGET (ib->image_dir),
										 TRUE, TRUE);
	else
		gtk_box_pack_end (GTK_BOX (list_vbox), GTK_WIDGET (ib->image_dir),
											TRUE, TRUE, 0);

	gtk_widget_set_size_request (GTK_WIDGET (ib->image_dir), FILE_LIST_WIDTH,
															 FILE_LIST_HEIGHT);
	gtk_widget_show (GTK_WIDGET (ib->image_dir));

	asgtk_image_dir_set_title (ASGTK_IMAGE_DIR (ib->image_dir),
														 "Image files:");

	/* now designing preview controls : */
	preview_vbox = gtk_vbox_new (FALSE, 0);
	gtk_widget_show (preview_vbox);
	if (GTK_IS_PANED (ib->list_hbox))
		gtk_paned_pack2 (GTK_PANED (ib->list_hbox), preview_vbox, TRUE, TRUE);
	else
		gtk_box_pack_end (GTK_BOX (ib->list_hbox), preview_vbox, TRUE, TRUE,
											5);

	ib->preview = ASGTK_IMAGE_VIEW (asgtk_image_view_new ());
	gtk_widget_set_size_request (GTK_WIDGET (ib->preview), PREVIEW_WIDTH,
															 PREVIEW_HEIGHT);
	gtk_box_pack_start (GTK_BOX (preview_vbox), GTK_WIDGET (ib->preview),
											TRUE, TRUE, 0);
	gtk_widget_show (GTK_WIDGET (ib->preview));
	asgtk_image_view_set_resize (ib->preview, ASGTK_IMAGE_VIEW_SCALE_TO_VIEW,
															 ASGTK_IMAGE_VIEW_RESIZE_ALL);

	ib->scale_check_box = gtk_check_button_new_with_label ("Scale to fit");
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ib->scale_check_box),
																TRUE);
	gtk_widget_show (ib->scale_check_box);
	colorize_gtk_widget (ib->scale_check_box,
											 get_colorschemed_style_normal ());
	g_signal_connect (G_OBJECT (ib->scale_check_box), "toggled",
										G_CALLBACK (asgtk_image_browser_scale_toggle),
										(gpointer) ib);

	gtk_button_set_alignment (GTK_BUTTON (ib->scale_check_box), 1.0, 0.5);
	asgtk_image_view_add_detail (ib->preview, ib->scale_check_box, 0);
	/* changing to default dir : */
	asgtk_image_dir_set_sel_handler (ASGTK_IMAGE_DIR (ib->image_dir),
																	 asgtk_image_browser_file_sel_handler,
																	 ib);
	asgtk_image_browser_change_dir (ib, NULL);

	LOCAL_DEBUG_OUT ("created image ASGtkImageBrowser object %p", ib);
	return GTK_WIDGET (ib);
}

GtkWidget *asgtk_image_browser_add_main_button (ASGtkImageBrowser * ib,
																								const char *stock,
																								GCallback func,
																								gpointer user_data)
{
	if (!ASGTK_IS_IMAGE_BROWSER (ib))
		return NULL;

	gtk_widget_show (ib->separator);
	return asgtk_add_button_to_box (GTK_BOX (ib->main_buttons_hbox), stock,
																	NULL, func, user_data);
}

GtkWidget *asgtk_image_browser_add_selection_button (ASGtkImageBrowser *
																										 ib, const char *stock,
																										 GCallback func)
{
	GtkWidget *btn;

	if (!ASGTK_IS_IMAGE_BROWSER (ib))
		return NULL;

	btn = asgtk_add_button_to_box (NULL, stock, NULL, func, ib->image_dir);
	asgtk_image_view_add_tool (ib->preview, btn, 0);
	return btn;
}

void asgtk_image_browser_refresh (ASGtkImageBrowser * ib)
{
	GtkListStore *dir_store;
	GtkTreeIter iter;

	g_return_if_fail (ASGTK_IS_IMAGE_BROWSER (ib));
	LOCAL_DEBUG_OUT (" refreshing %p: current dir = \"%s\"", ib,
									 ib->current_dir ? ib->current_dir : "null");
	asgtk_image_dir_set_path (ASGTK_IMAGE_DIR (ib->image_dir),
														ib->current_dir);
	dir_store =
			GTK_LIST_STORE (gtk_tree_view_get_model
											(GTK_TREE_VIEW (ib->dir_list)));
	gtk_list_store_clear (dir_store);
	if (ib->current_dir != NULL) {
		/* Add current dir entry as the first item : */
		gtk_list_store_append (dir_store, &iter);
		gtk_list_store_set (dir_store, &iter, 0, ".", -1);

		if (strcmp (ib->current_dir, "/") != 0) {
			gtk_list_store_append (dir_store, &iter);
			gtk_list_store_set (dir_store, &iter, 0, "..", -1);
		}

		/* Add subdirs : */
		{
			struct direntry **list = NULL;
			int n = my_scandir (ib->current_dir, &list, NULL, NULL);

			LOCAL_DEBUG_OUT (" scandir indicates %d entries in list", n);
			if (n > 0) {
				int i;

				for (i = 0; i < n; i++) {
					if (S_ISDIR (list[i]->d_mode)) {
						Bool skip = False;

						if (list[i]->d_name[0] == '.') {
							skip = (list[i]->d_name[1] == '\0' ||
											(list[i]->d_name[1] == '.'
											 && list[i]->d_name[2] == '\0'));
						}
						if (!skip) {
							gtk_list_store_append (dir_store, &iter);
							gtk_list_store_set (dir_store, &iter, 0, list[i]->d_name,
																	-1);
						}
					}
					free (list[i]);
				}
				free (list);
			}
		}

		/* Add dirs above us : */
		{
			char *above_dir = mystrdup (ib->current_dir);
			int i = strlen (above_dir) - 1;

			while (--i > 0) {
				if (above_dir[i] == '/') {
					above_dir[i] = '\0';
					gtk_list_store_append (dir_store, &iter);
					gtk_list_store_set (dir_store, &iter, 0, above_dir, -1);
				}
			}
		}
	}
	if (ib->current_dir == NULL || strcmp (ib->current_dir, "/") != 0) {
		gtk_list_store_append (dir_store, &iter);
		gtk_list_store_set (dir_store, &iter, 0, "/", -1);
	}
	/*
	   :sG:
	   The following 3 lines make the file lists sorted by
	   the Directory Name, Ascending.

	   For general directory listing (not files)
	 */
	GtkTreeSortable *sortable;

	sortable = GTK_TREE_SORTABLE (dir_store);
	gtk_tree_sortable_set_sort_column_id (sortable, 0, GTK_SORT_ASCENDING);


}

static void add_dir_to_history (ASGtkImageBrowser * ib, const char *dir)
{
	g_signal_handlers_block_by_func (G_OBJECT (ib->path_combo),
																	 G_CALLBACK
																	 (asgtk_image_browser_path_changed),
																	 (gpointer) ib);

	asgtk_combo_box_add_to_history (GTK_COMBO_BOX (ib->path_combo), dir);
	g_signal_handlers_unblock_by_func (G_OBJECT (ib->path_combo),
																		 G_CALLBACK
																		 (asgtk_image_browser_path_changed),
																		 (gpointer) ib);

}

void
asgtk_image_browser_change_dir (ASGtkImageBrowser * ib, const char *dir)
{
	char *fullfilename;
	int fullnamelen;

	g_return_if_fail (ASGTK_IS_IMAGE_BROWSER (ib));

	if (dir == NULL)
		fullfilename = PutHome ("~/");
	else if (dir[0] == '/')
		fullfilename = mystrdup (dir);
	else
		fullfilename = PutHome (dir);

	fullnamelen = strlen (fullfilename);
	while (fullnamelen > 1 && fullfilename[fullnamelen - 1] == '/') {
		fullfilename[fullnamelen - 1] = '\0';
		--fullnamelen;
	}

	LOCAL_DEBUG_OUT
			(" changing dir for  %p: current dir = \"%s\", new dir = \"%s\"", ib,
			 ib->current_dir ? ib->current_dir : "null", fullfilename);
	if (ib->current_dir == NULL
			|| strcmp (ib->current_dir, fullfilename) != 0) {
		char *title = safemalloc (128 + fullnamelen + 1);

		if (ib->current_dir)
			free (ib->current_dir);

		ib->current_dir = fullfilename;
		sprintf (title, "AfterStep image browser: %s", fullfilename);
		gtk_window_set_title (GTK_WINDOW (ib), title);
		free (title);
		add_dir_to_history (ib, fullfilename);
		asgtk_image_browser_refresh (ib);
	}

}
