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

/*
 *  Engrampa
 *
 *  Copyright (C) 2001, 2003, 2004 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., 59 Temple Street #330, Boston, MA 02110-1301, USA.
 */

#include <config.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include <gio/gio.h>
#include <gtk/gtk.h>
#include "file-utils.h"
#include "fr-stock.h"
#include "fr-window.h"
#include "typedefs.h"
#include "gtk-utils.h"
#include "glib-utils.h"
#include "preferences.h"
#include "main.h"


#define ARCHIVE_ICON_SIZE (48)
#define BAD_CHARS "/\\*"


typedef struct {
	FrWindow   *window;
	GSettings *settings;
	GSettings *settings_general;
	GtkBuilder *builder;
	int        *supported_types;

	GtkWidget  *dialog;
	GtkWidget  *a_add_to_entry;
	GtkWidget  *a_location_filechooserbutton;
	GtkWidget  *add_image;
	GtkWidget  *a_archive_type_combo_box;
	GtkWidget  *a_other_options_expander;
	GtkWidget  *a_password_entry;
	GtkWidget  *a_password_label;
	GtkWidget  *a_encrypt_header_checkbutton;
	GtkWidget  *a_volume_checkbutton;
	GtkWidget  *a_volume_spinbutton;
	GtkWidget  *a_volume_box;

	GList      *file_list;
	gboolean    add_clicked;
	const char *last_mime_type;
	gboolean    single_file;
} DialogData;


static const char *
get_ext (DialogData *data)
{
	int idx;

	idx = gtk_combo_box_get_active (GTK_COMBO_BOX (data->a_archive_type_combo_box));

	return mime_type_desc[data->supported_types[idx]].default_ext;
}


/* called when the main dialog is closed. */
static void
destroy_cb (GtkWidget  *widget,
	    DialogData *data)
{
	g_settings_set_string (data->settings, PREF_BATCH_ADD_DEFAULT_EXTENSION, get_ext (data));
	/*g_settings_set_boolean (data->settings, PREF_BATCH_ADD_OTHER_OPTIONS, data->add_clicked ? FALSE : gtk_expander_get_expanded (GTK_EXPANDER (data->a_other_options_expander)));*/
	g_settings_set_boolean (data->settings_general, PREF_GENERAL_ENCRYPT_HEADER, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (data->a_encrypt_header_checkbutton)));


	if (! data->add_clicked) {
		fr_window_pop_message (data->window);
		fr_window_stop_batch (data->window);
	}

	g_object_unref (data->builder);
	g_object_unref (data->settings_general);
	g_object_unref (data->settings);
	g_free (data);
}


static void
set_archive_options (DialogData *data)
{
	int idx;

	idx = gtk_combo_box_get_active (GTK_COMBO_BOX (data->a_archive_type_combo_box));
	if (mime_type_desc[data->supported_types[idx]].capabilities & FR_COMMAND_CAN_ENCRYPT) {
		const char *pwd;

		pwd = gtk_entry_get_text (GTK_ENTRY (data->a_password_entry));
		if (pwd != NULL) {
			if (strcmp (pwd, "") != 0) {
				fr_window_set_password (data->window, pwd);
				if (mime_type_desc[data->supported_types[idx]].capabilities & FR_COMMAND_CAN_ENCRYPT_HEADER)
					fr_window_set_encrypt_header (data->window, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (data->a_encrypt_header_checkbutton)));
			}
		}
	}

	if ((mime_type_desc[data->supported_types[idx]].capabilities & FR_COMMAND_CAN_CREATE_VOLUMES)
	    && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (data->a_volume_checkbutton)))
	{
		double value;
		int    size;

		value = gtk_spin_button_get_value (GTK_SPIN_BUTTON (data->a_volume_spinbutton));
		size = floor (value * MEGABYTE);
		g_settings_set_int (data->settings, PREF_BATCH_ADD_VOLUME_SIZE, size);
		fr_window_set_volume_size (data->window, (guint) size);
	}
}


static void
help_clicked_cb (GtkWidget  *widget,
		 DialogData *data)
{
	show_help_dialog (GTK_WINDOW (data->dialog), "engrampa-fmgr-add");
}


static void
add_clicked_cb (GtkWidget  *widget,
		DialogData *data)
{
	FrWindow   *window = data->window;
	char       *archive_name;
	char       *archive_dir;
	char       *archive_file;
	char       *tmp;
	const char *archive_ext;
	gboolean    do_not_add = FALSE;
	GError     *error = NULL;

	data->add_clicked = TRUE;

	/* Collect data */

	archive_name = g_uri_escape_string (gtk_entry_get_text (GTK_ENTRY (data->a_add_to_entry)), NULL, FALSE);

	/* Check whether the user entered a valid archive name. */

	if ((archive_name == NULL) || (*archive_name == '\0')) {
		GtkWidget *d;

		d = _gtk_error_dialog_new (GTK_WINDOW (window),
					   GTK_DIALOG_DESTROY_WITH_PARENT,
					   NULL,
					   _("Could not create the archive"),
					   "%s",
					   _("You have to specify an archive name."));
		gtk_dialog_run (GTK_DIALOG (d));
		gtk_widget_destroy (GTK_WIDGET (d));
		g_free (archive_name);

		return;
	}
	else if (strchrs (archive_name, BAD_CHARS)) {
		GtkWidget *d;
		char      *utf8_name = g_filename_display_name (archive_name);

		d = _gtk_error_dialog_new (GTK_WINDOW (window),
					   GTK_DIALOG_DESTROY_WITH_PARENT,
					   NULL,
					   _("Could not create the archive"),
					   _("The name \"%s\" is not valid because it cannot contain the characters: %s\n\n%s"),
					   utf8_name,
					   BAD_CHARS,
					   _("Please use a different name."));
		gtk_dialog_run (GTK_DIALOG (d));
		gtk_widget_destroy (GTK_WIDGET (d));

		g_free (utf8_name);
		g_free (archive_name);

		return;
	}

	/* Check directory existence. */

	archive_dir = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (data->a_location_filechooserbutton));
	if (archive_dir == NULL) {
		g_free (archive_dir);
		g_free (archive_name);
		return;
	}

	if (! check_permissions (archive_dir, R_OK|W_OK|X_OK)) {
		GtkWidget  *d;

		d = _gtk_error_dialog_new (GTK_WINDOW (window),
					   GTK_DIALOG_DESTROY_WITH_PARENT,
					   NULL,
					   _("Could not create the archive"),
					   "%s",
					   _("You don't have the right permissions to create an archive in the destination folder."));
		gtk_dialog_run (GTK_DIALOG (d));
		gtk_widget_destroy (GTK_WIDGET (d));

		g_free (archive_dir);
		g_free (archive_name);
		return;
	}

	if (! uri_is_dir (archive_dir)) {
		GtkWidget *d;
		int        r;
		char      *folder_name;
		char      *msg;

		folder_name = g_filename_display_name (archive_dir);
		msg = g_strdup_printf (_("Destination folder \"%s\" does not exist.\n\nDo you want to create it?"), folder_name);
		g_free (folder_name);

		d = _gtk_message_dialog_new (GTK_WINDOW (data->dialog),
					     GTK_DIALOG_MODAL,
					     GTK_STOCK_DIALOG_QUESTION,
					     msg,
					     NULL,
					     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
					     _("Create _Folder"), GTK_RESPONSE_YES,
					     NULL);

		gtk_dialog_set_default_response (GTK_DIALOG (d), GTK_RESPONSE_YES);
		r = gtk_dialog_run (GTK_DIALOG (d));
		gtk_widget_destroy (GTK_WIDGET (d));

		g_free (msg);

		do_not_add = (r != GTK_RESPONSE_YES);
	}

	if (! do_not_add && ! ensure_dir_exists (archive_dir, 0755, &error)) {
		GtkWidget  *d;

		d = _gtk_error_dialog_new (GTK_WINDOW (window),
					   GTK_DIALOG_DESTROY_WITH_PARENT,
					   NULL,
					   _("Could not create the archive"),
					   _("Could not create the destination folder: %s."),
					   error->message);
		gtk_dialog_run (GTK_DIALOG (d));
		gtk_widget_destroy (GTK_WIDGET (d));

		g_error_free (error);
		g_free (archive_dir);
		g_free (archive_name);
		return;
	}

	if (do_not_add) {
		GtkWidget *d;

		d = _gtk_message_dialog_new (GTK_WINDOW (window),
					     GTK_DIALOG_DESTROY_WITH_PARENT,
					     GTK_STOCK_DIALOG_WARNING,
					     _("Archive not created"),
					     NULL,
					     GTK_STOCK_OK, GTK_RESPONSE_OK,
					     NULL);
		gtk_dialog_set_default_response (GTK_DIALOG (d), GTK_RESPONSE_OK);
		gtk_dialog_run (GTK_DIALOG (d));
		gtk_widget_destroy (GTK_WIDGET (d));

		g_free (archive_dir);
		g_free (archive_name);

		return;
	}

	/**/

	archive_ext = get_ext (data);
	tmp = archive_name;
	archive_name = g_strconcat (tmp, archive_ext, NULL);
	g_free (tmp);
	archive_file = g_strconcat (archive_dir, "/", archive_name, NULL);

	if (uri_is_dir (archive_file)) {
		GtkWidget  *d;

		d = _gtk_error_dialog_new (GTK_WINDOW (window),
					   GTK_DIALOG_DESTROY_WITH_PARENT,
					   NULL,
					   _("Could not create the archive"),
					   "%s",
					   _("You have to specify an archive name."));
		gtk_dialog_run (GTK_DIALOG (d));
		gtk_widget_destroy (GTK_WIDGET (d));

		g_free (archive_name);
		g_free (archive_dir);
		g_free (archive_file);

		return;
	}

	if (uri_exists (archive_file)) {
		GtkWidget *d;
		int        r;

		d = _gtk_message_dialog_new (GTK_WINDOW (data->dialog),
					     GTK_DIALOG_MODAL,
					     GTK_STOCK_DIALOG_QUESTION,
					     _("The archive is already present.  Do you want to overwrite it?"),
					     NULL,
					     GTK_STOCK_NO, GTK_RESPONSE_NO,
					     _("_Overwrite"), GTK_RESPONSE_YES,
					     NULL);

		gtk_dialog_set_default_response (GTK_DIALOG (d), GTK_RESPONSE_YES);
		r = gtk_dialog_run (GTK_DIALOG (d));
		gtk_widget_destroy (GTK_WIDGET (d));

		if (r == GTK_RESPONSE_YES) {
			GFile  *file;
			GError *err = NULL;

			/* FIXME: convert this code in a function in file-utils.c */
			file = g_file_new_for_uri (archive_file);
			g_file_delete (file, NULL, &err);
			if (err != NULL) {
				g_warning ("Failed to delete file %s: %s",
					   archive_file,
					   err->message);
				g_clear_error (&err);
			}
			g_object_unref (file);
		}
		else {
			g_free (archive_name);
			g_free (archive_dir);
			g_free (archive_file);
			return;
		}
	}
	set_archive_options (data);
	gtk_widget_destroy (data->dialog);

	fr_window_archive_new (window, archive_file);

	g_free (archive_name);
	g_free (archive_dir);
	g_free (archive_file);
}


static void
update_sensitivity_for_mime_type (DialogData *data,
				  const char *mime_type)
{
	int i;

	if (mime_type == NULL) {
		gtk_widget_set_sensitive (data->a_password_entry, FALSE);
		gtk_widget_set_sensitive (data->a_password_label, FALSE);
		gtk_widget_set_sensitive (data->a_encrypt_header_checkbutton, FALSE);
		gtk_toggle_button_set_inconsistent (GTK_TOGGLE_BUTTON (data->a_encrypt_header_checkbutton), TRUE);
		gtk_widget_set_sensitive (data->a_volume_box, FALSE);
		return;
	}

	for (i = 0; mime_type_desc[i].mime_type != NULL; i++) {
		if (strcmp (mime_type_desc[i].mime_type, mime_type) == 0) {
			gboolean sensitive;

			sensitive = mime_type_desc[i].capabilities & FR_COMMAND_CAN_ENCRYPT;
			gtk_widget_set_sensitive (data->a_password_entry, sensitive);
			gtk_widget_set_sensitive (data->a_password_label, sensitive);

			sensitive = mime_type_desc[i].capabilities & FR_COMMAND_CAN_ENCRYPT_HEADER;
			gtk_widget_set_sensitive (data->a_encrypt_header_checkbutton, sensitive);
			gtk_toggle_button_set_inconsistent (GTK_TOGGLE_BUTTON (data->a_encrypt_header_checkbutton), ! sensitive);

			sensitive = mime_type_desc[i].capabilities & FR_COMMAND_CAN_CREATE_VOLUMES;
			gtk_widget_set_sensitive (data->a_volume_box, sensitive);

			break;
		}
	}
}


static void
archive_type_combo_box_changed_cb (GtkComboBox *combo_box,
				   DialogData  *data)
{
	const char *mime_type;
	int         idx = gtk_combo_box_get_active (combo_box);

	mime_type = mime_type_desc[data->supported_types[idx]].mime_type;

	gtk_image_set_from_pixbuf (GTK_IMAGE (data->add_image), get_mime_type_pixbuf (mime_type, ARCHIVE_ICON_SIZE, NULL));
	update_sensitivity_for_mime_type (data, mime_type);
}


static void
update_archive_type_combo_box_from_ext (DialogData  *data,
					const char  *ext)
{
	int idx = 0;
	int i;

	if (ext == NULL) {
		gtk_combo_box_set_active (GTK_COMBO_BOX (data->a_archive_type_combo_box), 0);
		return;
	}

	for (i = 0; data->supported_types[i] != -1; i++)
		if (strcmp (ext, mime_type_desc[data->supported_types[i]].default_ext) == 0) {
			idx = i;
			break;
		}

	gtk_combo_box_set_active (GTK_COMBO_BOX (data->a_archive_type_combo_box), idx);
}


static void
update_sensitivity (DialogData *data)
{
	gtk_widget_set_sensitive (data->a_volume_spinbutton, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (data->a_volume_checkbutton)));
}


static void
password_entry_changed_cb (GtkEditable *editable,
			   gpointer     user_data)
{
	update_sensitivity ((DialogData *) user_data);
}


static void
volume_toggled_cb (GtkToggleButton *toggle_button,
		   gpointer         user_data)
{
	update_sensitivity ((DialogData *) user_data);
}


void
dlg_batch_add_files (FrWindow *window,
		     GList    *file_list)
{
	DialogData   *data;
	GtkWidget    *cancel_button;
	GtkWidget    *help_button;
	GtkWidget    *add_button;
	GtkWidget    *a_archive_type_box;
	GtkSizeGroup *size_group;
	char         *automatic_name = NULL;
	char         *default_ext;
	const char   *first_filename;
	char         *parent;
	int           i;

	if (file_list == NULL)
		return;

	data = g_new0 (DialogData, 1);
	data->settings = g_settings_new (ENGRAMPA_SCHEMA_BATCH_ADD);
	data->settings_general = g_settings_new (ENGRAMPA_SCHEMA_GENERAL);

	data->builder = _gtk_builder_new_from_file ("batch-add-files.ui");
	if (data->builder == NULL) {
		g_free (data);
		return;
	}

	data->window = window;
	data->file_list = file_list;
	data->single_file = ((file_list->next == NULL) && uri_is_file ((char*) file_list->data));
	data->add_clicked = FALSE;

	/* Get the widgets. */

	data->dialog = _gtk_builder_get_widget (data->builder, "batch_add_files_dialog");
	data->a_add_to_entry = _gtk_builder_get_widget (data->builder, "a_add_to_entry");
	data->a_location_filechooserbutton = _gtk_builder_get_widget (data->builder, "a_location_filechooserbutton");
	data->a_password_entry = _gtk_builder_get_widget (data->builder, "a_password_entry");
	data->a_password_label = _gtk_builder_get_widget (data->builder, "a_password_label");
	data->a_other_options_expander = _gtk_builder_get_widget (data->builder, "a_other_options_expander");
	data->a_encrypt_header_checkbutton = _gtk_builder_get_widget (data->builder, "a_encrypt_header_checkbutton");

	data->a_volume_checkbutton = _gtk_builder_get_widget (data->builder, "a_volume_checkbutton");
	data->a_volume_spinbutton = _gtk_builder_get_widget (data->builder, "a_volume_spinbutton");
	data->a_volume_box = _gtk_builder_get_widget (data->builder, "a_volume_box");

	add_button = _gtk_builder_get_widget (data->builder, "a_add_button");
	cancel_button = _gtk_builder_get_widget (data->builder, "a_cancel_button");
	help_button = _gtk_builder_get_widget (data->builder, "a_help_button");
	a_archive_type_box = _gtk_builder_get_widget (data->builder, "a_archive_type_box");

	data->add_image = _gtk_builder_get_widget (data->builder, "a_add_image");

	/* Set widgets data. */

	size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
	gtk_size_group_add_widget (size_group, _gtk_builder_get_widget (data->builder, "a_archive_label"));
	gtk_size_group_add_widget (size_group, _gtk_builder_get_widget (data->builder, "a_location_label"));
	gtk_size_group_add_widget (size_group, _gtk_builder_get_widget (data->builder, "a_password_label"));

	gtk_button_set_use_stock (GTK_BUTTON (add_button), TRUE);
	gtk_button_set_label (GTK_BUTTON (add_button), FR_STOCK_CREATE_ARCHIVE);
	gtk_expander_set_expanded (GTK_EXPANDER (data->a_other_options_expander), FALSE /*g_settings_get_boolean (data->settings, PREF_BATCH_ADD_OTHER_OPTIONS)*/);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (data->a_encrypt_header_checkbutton), g_settings_get_boolean (data->settings_general, PREF_GENERAL_ENCRYPT_HEADER));
	gtk_spin_button_set_value (GTK_SPIN_BUTTON (data->a_volume_spinbutton), (double) g_settings_get_int (data->settings, PREF_BATCH_ADD_VOLUME_SIZE) / MEGABYTE);


	first_filename = (char*) file_list->data;
	parent = remove_level_from_path (first_filename);

	if (file_list->next == NULL)
		automatic_name = g_uri_unescape_string (file_name_from_path ((char*) file_list->data), NULL);
	else {
		automatic_name = g_uri_unescape_string (file_name_from_path (parent), NULL);
		if ((automatic_name == NULL) || (automatic_name[0] == '\0')) {
			g_free (automatic_name);
			automatic_name = g_uri_unescape_string (file_name_from_path (first_filename), NULL);
		}
	}

	_gtk_entry_set_filename_text (GTK_ENTRY (data->a_add_to_entry), automatic_name);
	g_free (automatic_name);

	if (check_permissions (parent, R_OK | W_OK))
		gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (data->a_location_filechooserbutton), parent);
	else
		gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (data->a_location_filechooserbutton), get_home_uri ());
	g_free (parent);

	/* archive type combobox */

	data->a_archive_type_combo_box = gtk_combo_box_new_text ();
	if (data->single_file)
		data->supported_types = single_file_save_type;
	else
		data->supported_types = save_type;
	sort_mime_types_by_extension (data->supported_types);

	for (i = 0; data->supported_types[i] != -1; i++)
		gtk_combo_box_append_text (GTK_COMBO_BOX (data->a_archive_type_combo_box),
					   mime_type_desc[data->supported_types[i]].default_ext);

	gtk_box_pack_start (GTK_BOX (a_archive_type_box), data->a_archive_type_combo_box, TRUE, TRUE, 0);
	gtk_widget_show_all (a_archive_type_box);

	/* Set the signals handlers. */

	g_signal_connect (G_OBJECT (data->dialog),
			  "destroy",
			  G_CALLBACK (destroy_cb),
			  data);
	g_signal_connect_swapped (G_OBJECT (cancel_button),
				  "clicked",
				  G_CALLBACK (gtk_widget_destroy),
				  G_OBJECT (data->dialog));
	g_signal_connect (G_OBJECT (add_button),
			  "clicked",
			  G_CALLBACK (add_clicked_cb),
			  data);
	g_signal_connect (G_OBJECT (help_button),
			  "clicked",
			  G_CALLBACK (help_clicked_cb),
			  data);
	g_signal_connect (G_OBJECT (data->a_archive_type_combo_box),
			  "changed",
			  G_CALLBACK (archive_type_combo_box_changed_cb),
			  data);
	g_signal_connect (G_OBJECT (data->a_password_entry),
			  "changed",
			  G_CALLBACK (password_entry_changed_cb),
			  data);
	g_signal_connect (G_OBJECT (data->a_volume_checkbutton),
			  "toggled",
			  G_CALLBACK (volume_toggled_cb),
			  data);

	/* Run dialog. */

	default_ext = g_settings_get_string (data->settings, PREF_BATCH_ADD_DEFAULT_EXTENSION);
	update_archive_type_combo_box_from_ext (data, default_ext);
	g_free (default_ext);

	gtk_widget_grab_focus (data->a_add_to_entry);
	gtk_editable_select_region (GTK_EDITABLE (data->a_add_to_entry),
				    0, -1);

	update_sensitivity (data);

	gtk_window_set_modal (GTK_WINDOW (data->dialog), FALSE);
	gtk_window_present (GTK_WINDOW (data->dialog));
}