/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */

/*
 *  Engrampa
 *
 *  Copyright (C) 2008 Free Software Foundation, Inc.
 *
 *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <config.h>
#include <glib/gi18n.h>

#include <string.h>
#include <gtk/gtk.h>
#include "dlg-update.h"
#include "file-utils.h"
#include "glib-utils.h"
#include "gtk-utils.h"
#include "fr-init.h"
#include "fr-window.h"

#define GET_WIDGET(x) (GTK_WIDGET (gtk_builder_get_object (builder, (x))))

enum {
	IS_SELECTED_COLUMN,
	NAME_COLUMN,
	DATA_COLUMN,
	N_COLUMNS
};

typedef struct {
	FrWindow     *window;

	GtkWidget    *update_file_dialog;
	GtkWidget    *update_file_primary_text_label;
	GtkWidget    *update_file_secondary_text_label;

	GtkWidget    *update_files_dialog;
	GtkWidget    *update_files_primary_text_label;
	GtkWidget    *update_files_secondary_text_label;
	GtkWidget    *update_files_treeview;
	GtkWidget    *update_files_ok_button;

	GList        *file_list;
	GtkTreeModel *list_model;
} DialogData;

/* called when the main dialog is closed. */
static void
dlg_update__destroy_cb (GtkWidget  *widget,
		        DialogData *data)
{
	fr_window_update_dialog_closed (data->window);
	if (data->file_list != NULL)
		g_list_free (data->file_list);
	g_free (data);
}

static GList*
get_selected_files (DialogData *data)
{
	GList       *selection = NULL;
	GtkTreeIter  iter;

	if (! gtk_tree_model_get_iter_first (data->list_model, &iter))
		return NULL;

	do {
		gboolean  is_selected;
		OpenFile *file;

                gtk_tree_model_get (data->list_model, &iter,
                		    IS_SELECTED_COLUMN, &is_selected,
                		    DATA_COLUMN, &file,
                		    -1);
                if (is_selected)
                	selection = g_list_prepend (selection, file);
	} while (gtk_tree_model_iter_next (data->list_model, &iter));

	return g_list_reverse (selection);
}

static void
update_cb (GtkWidget *widget,
	   gpointer   callback_data)
{
	DialogData *data = callback_data;
	GList      *selection;

	selection = get_selected_files (data);
	if (fr_window_update_files (data->window, selection)) {
		int n_files;

		n_files = g_list_length (data->file_list);
		if (n_files == 1)
			gtk_widget_destroy (data->update_file_dialog);
		else
			gtk_widget_destroy (data->update_files_dialog);
	}
	if (selection != NULL)
		g_list_free (selection);
}

static void
update_file_list (DialogData *data)
{
	guint        n_files;
	GList       *scan;
	GtkTreeIter  iter;

	n_files = g_list_length (data->file_list);

	/* update the file list */

	gtk_list_store_clear (GTK_LIST_STORE (data->list_model));
	for (scan = data->file_list; scan; scan = scan->next) {
		char     *utf8_name;
		OpenFile *file = scan->data;

		gtk_list_store_append (GTK_LIST_STORE (data->list_model),
				       &iter);

		utf8_name = g_filename_display_name (file_name_from_path (file->path));
		gtk_list_store_set (GTK_LIST_STORE (data->list_model),
				    &iter,
				    IS_SELECTED_COLUMN, TRUE,
				    NAME_COLUMN, utf8_name,
				    DATA_COLUMN, file,
				    -1);
		g_free (utf8_name);
	}

	/* update the labels */

	if (n_files == 1) {
		OpenFile *file = data->file_list->data;
		char     *file_name;
		char     *unescaped;
		char     *archive_name;
		char     *label;
		char     *markup;

		/* primary text */

		file_name = g_filename_display_name (file_name_from_path (file->path));
		unescaped = g_uri_unescape_string (fr_window_get_archive_uri (data->window), NULL);
		archive_name = g_path_get_basename (unescaped);
		label = g_markup_printf_escaped (_("Update the file \"%s\" in the archive \"%s\"?"), file_name, archive_name);
		markup = g_strdup_printf ("<big><b>%s</b></big>", label);
		gtk_label_set_markup (GTK_LABEL (data->update_file_primary_text_label), markup);

		g_free (markup);
		g_free (label);
		g_free (archive_name);
		g_free (unescaped);
		g_free (file_name);

		/* secondary text */

		label = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE,
		                                      "The file has been modified with an external application. If you don't update the file in the archive, all of your changes will be lost.",
		                                      "%u files have been modified with an external application. If you don't update the files in the archive, all of your changes will be lost.",
		                                      (gulong) n_files),
		                         n_files);
		gtk_label_set_text (GTK_LABEL (data->update_file_secondary_text_label), label);
		g_free (label);
	}
	else if (n_files > 1) {
		char *unescaped;
		char *archive_name;
		char *label;
		char *markup;

		/* primary text */

		unescaped = g_uri_unescape_string (fr_window_get_archive_uri (data->window), NULL);
		archive_name = g_path_get_basename (unescaped);
		label = g_markup_printf_escaped (_("Update the files in the archive \"%s\"?"), archive_name);
		markup = g_strdup_printf ("<big><b>%s</b></big>", label);
		gtk_label_set_markup (GTK_LABEL (data->update_files_primary_text_label), markup);

		g_free (markup);
		g_free (label);
		g_free (archive_name);
		g_free (unescaped);

		/* secondary text */

		label = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE,
		                                      "The file has been modified with an external application. If you don't update the file in the archive, all of your changes will be lost.",
		                                      "%u files have been modified with an external application. If you don't update the files in the archive, all of your changes will be lost.",
		                                      (gulong) n_files),
		                         n_files);
		gtk_label_set_text (GTK_LABEL (data->update_files_secondary_text_label), label);
		g_free (label);
	}

	/* show the appropriate dialog */

	if (n_files == 1) {
		/*gtk_window_set_modal (GTK_WINDOW (data->update_files_dialog), FALSE);*/
		gtk_widget_hide (data->update_files_dialog);
		/*gtk_window_set_modal (GTK_WINDOW (data->update_file_dialog), TRUE);*/
		gtk_widget_show (data->update_file_dialog);
	}
	else if (n_files > 1) {
		/*gtk_window_set_modal (GTK_WINDOW (data->update_file_dialog), FALSE);*/
		gtk_widget_hide (data->update_file_dialog);
		/*gtk_window_set_modal (GTK_WINDOW (data->update_files_dialog), TRUE);*/
		gtk_widget_show (data->update_files_dialog);
	}
	else { /* n_files == 0 */
		/*gtk_window_set_modal (GTK_WINDOW (data->update_files_dialog), FALSE);*/
		gtk_widget_hide (data->update_files_dialog);
		/*gtk_window_set_modal (GTK_WINDOW (data->update_file_dialog), FALSE);*/
		gtk_widget_hide (data->update_file_dialog);
	}
}

static int
n_selected (DialogData *data)
{
	int         n = 0;
	GtkTreeIter iter;

	if (! gtk_tree_model_get_iter_first (data->list_model, &iter))
		return 0;

	do {
		gboolean is_selected;
                gtk_tree_model_get (data->list_model, &iter, IS_SELECTED_COLUMN, &is_selected, -1);
                if (is_selected)
                	n++;
	} while (gtk_tree_model_iter_next (data->list_model, &iter));

	return n;
}

static void
is_selected_toggled (GtkCellRendererToggle *cell,
		     char                  *path_string,
		     gpointer               callback_data)
{
	DialogData   *data  = callback_data;
	GtkTreeModel *model = GTK_TREE_MODEL (data->list_model);
	GtkTreeIter   iter;
	GtkTreePath  *path = gtk_tree_path_new_from_string (path_string);
	guint         value;

	gtk_tree_model_get_iter (model, &iter, path);
	value = ! gtk_cell_renderer_toggle_get_active (cell);
	gtk_list_store_set (GTK_LIST_STORE (model), &iter, IS_SELECTED_COLUMN, value, -1);

	gtk_tree_path_free (path);

	gtk_widget_set_sensitive (data->update_files_ok_button, n_selected (data) > 0);
}

gpointer
dlg_update (FrWindow *window)
{
	GtkBuilder        *builder;
	DialogData        *data;
	GtkCellRenderer   *renderer;
	GtkTreeViewColumn *column;

	data = g_new0 (DialogData, 1);
	builder = gtk_builder_new_from_resource (ENGRAMPA_RESOURCE_UI_PATH G_DIR_SEPARATOR_S "update.ui");
	data->file_list = NULL;
	data->window = window;

	/* Get the widgets. */

	data->update_file_dialog = GET_WIDGET ("update_file_dialog");
	data->update_file_primary_text_label = GET_WIDGET ("update_file_primary_text_label");
	data->update_file_secondary_text_label = GET_WIDGET ("update_file_secondary_text_label");

	data->update_files_dialog = GET_WIDGET ("update_files_dialog");
	data->update_files_primary_text_label = GET_WIDGET ("update_files_primary_text_label");
	data->update_files_secondary_text_label = GET_WIDGET ("update_files_secondary_text_label");
	data->update_files_treeview = GET_WIDGET ("update_files_treeview");
	data->update_files_ok_button = GET_WIDGET ("update_files_ok_button");

	/* Set the signals handlers. */

	gtk_builder_add_callback_symbols (builder,
	                                  "on_update_file_dialog_destroy",	G_CALLBACK (dlg_update__destroy_cb),
	                                  "on_update_file_ok_button_clicked",	G_CALLBACK (update_cb),
	                                  "on_update_files_dialog_destroy",	G_CALLBACK (dlg_update__destroy_cb),
	                                  "on_update_files_ok_button_clicked",	G_CALLBACK (update_cb),
	                                  NULL);

	gtk_builder_connect_signals (builder, data);

	g_signal_connect_swapped (gtk_builder_get_object (builder, "update_file_cancel_button"),
				  "clicked",
				  G_CALLBACK (gtk_widget_destroy),
				  G_OBJECT (data->update_file_dialog));

	g_signal_connect_swapped (gtk_builder_get_object (builder, "update_files_cancel_button"),
				  "clicked",
				  G_CALLBACK (gtk_widget_destroy),
				  G_OBJECT (data->update_files_dialog));

	g_object_unref (builder);

	/* Set dialog data. */

	data->list_model = GTK_TREE_MODEL (gtk_list_store_new (N_COLUMNS,
							       G_TYPE_BOOLEAN,
							       G_TYPE_STRING,
							       G_TYPE_POINTER));
	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (data->list_model),
					      NAME_COLUMN,
					      GTK_SORT_ASCENDING);
	gtk_tree_view_set_model (GTK_TREE_VIEW (data->update_files_treeview),
				 data->list_model);
	g_object_unref (G_OBJECT (data->list_model));

	column = gtk_tree_view_column_new ();

	renderer = gtk_cell_renderer_toggle_new ();
        g_signal_connect (G_OBJECT (renderer),
                          "toggled",
                          G_CALLBACK (is_selected_toggled),
                          data);
        gtk_tree_view_column_pack_start (column, renderer, FALSE);
        gtk_tree_view_column_set_attributes (column, renderer,
                                             "active", IS_SELECTED_COLUMN,
                                             NULL);

	renderer = gtk_cell_renderer_text_new ();
	gtk_tree_view_column_pack_start (column, renderer, TRUE);
	gtk_tree_view_column_set_attributes (column, renderer,
					     "text", NAME_COLUMN,
					     NULL);

	gtk_tree_view_append_column (GTK_TREE_VIEW (data->update_files_treeview), column);

	/* Run dialog. */

	gtk_window_set_transient_for (GTK_WINDOW (data->update_file_dialog),
				      GTK_WINDOW (window));
	gtk_window_set_transient_for (GTK_WINDOW (data->update_files_dialog),
				      GTK_WINDOW (window));

	update_file_list (data);

	return data;
}

void
dlg_update_add_file (gpointer  dialog,
		     OpenFile *file)
{
	DialogData *data = dialog;
	GList      *scan;

	/* avoid duplicates */

	for (scan = data->file_list; scan; scan = scan->next) {
		OpenFile *test = scan->data;
		if (uricmp (test->extracted_uri, file->extracted_uri) == 0)
			return;
	}

	/**/

	data->file_list = g_list_append (data->file_list, file);
	update_file_list (data);
}