/*
 *  nautilus-wipe - a nautilus extension to wipe file(s)
 * 
 *  Copyright (C) 2009-2022 Colomban Wendling <ban@herbesfolles.org>
 *
 *  This library 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 3 of the License, or (at your option) any later version.
 *
 *  This library 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
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public
 *  License along with this library; if not, write to the Free
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <glib.h>
#include <glib/gi18n-lib.h>
#include <gtk/gtk.h>
#include <gio/gio.h>

#include <gsecuredelete.h>

#include "nw-operation-manager.h"
#include "nw-delete-operation.h"
#include "nw-fill-operation.h"
#include "nw-fill-operation-utils.h"


/* Runs the wipe operation */
static void
nw_extension_run_delete_operation (const gchar *native_parent,
                                   GList       *files)
{
  gchar  *confirm_primary_text = NULL;
  guint   n_items;
  
  n_items = g_list_length (files);
  if (n_items > 1) {
    confirm_primary_text = g_strdup_printf (g_dngettext(GETTEXT_PACKAGE,
    /* TRANSLATORS: singular is not really used, N is strictly >1 */
                                                        "Are you sure you want "
                                                        "to wipe the %u "
                                                        "selected items?",
                                                        /* plural form */
                                                        "Are you sure you want "
                                                        "to wipe the %u "
                                                        "selected items?",
                                                        n_items),
                                            n_items);
  } else if (n_items > 0) {
    gchar *name;
    
    name = g_filename_display_basename (files->data);
    confirm_primary_text = g_strdup_printf (_("Are you sure you want to wipe "
                                              "\"%s\"?"),
                                            name);
    g_free (name);
  }
  nw_operation_manager_run (
    native_parent, files,
    _("Wipe Files"),
    /* confirm dialog */
    confirm_primary_text,
    _("If you wipe an item, it will not be recoverable."),
    _("_Wipe"),
    gtk_image_new_from_stock (GTK_STOCK_DELETE, GTK_ICON_SIZE_BUTTON),
    /* progress dialog */
    _("Wiping files..."),
    /* operation launcher */
    nw_delete_operation_new (),
    /* failed dialog */
    _("Wipe failed."),
    /* success dialog */
    _("Wipe successful."),
    g_dngettext(GETTEXT_PACKAGE,
                "The item has been successfully wiped.",
                "The items have been successfully wiped.",
                n_items)
  );
  g_free (confirm_primary_text);
}

/* Runs the fill operation */
static void
nw_extension_run_fill_operation (const gchar *native_parent,
                                 GList       *paths,
                                 GList       *mountpoints)
{
  gchar  *confirm_primary_text = NULL;
  gchar  *success_secondary_text = NULL;
  guint   n_items;
  
  n_items = g_list_length (mountpoints);
  /* FIXME: can't truly use g_dngettext since the args are not the same */
  if (n_items > 1) {
    GList    *tmp;
    GString  *devices = g_string_new (NULL);
    
    for (tmp = mountpoints; tmp; tmp = g_list_next (tmp)) {
      gchar *name;
      
      name = g_filename_display_name (tmp->data);
      if (devices->len > 0) {
        if (! tmp->next) {
          /* TRANSLATORS: this is the last device names separator */
          g_string_append (devices, _(" and "));
        } else {
          /* TRANSLATORS: this is the device names separator (except last) */
          g_string_append (devices, _(", "));
        }
      }
      /* TRANSLATORS: this is the device name */
      g_string_append_printf (devices, _("\"%s\""), name);
      g_free (name);
    }
    confirm_primary_text = g_strdup_printf (_("Are you sure you want to wipe "
                                              "the available disk space on the "
                                              "%s partitions or devices?"),
                                            devices->str);
    success_secondary_text = g_strdup_printf (_("Available disk space on the "
                                                "partitions or devices %s "
                                                "have been successfully wiped."),
                                              devices->str);
    g_string_free (devices, TRUE);
  } else if (n_items > 0) {
    gchar *name;
    
    name = g_filename_display_name (mountpoints->data);
    confirm_primary_text = g_strdup_printf (_("Are you sure you want to wipe "
                                              "the available disk space on the "
                                              "\"%s\" partition or device?"),
                                            name);
    success_secondary_text = g_strdup_printf (_("Available disk space on the "
                                                "partition or device \"%s\" "
                                                "has been successfully wiped."),
                                              name);
    g_free (name);
  }
  nw_operation_manager_run (
    native_parent, paths,
    _("Wipe Available Disk Space"),
    /* confirm dialog */
    confirm_primary_text,
    _("This operation may take a while."),
    _("_Wipe"),
    gtk_image_new_from_stock (GTK_STOCK_CLEAR, GTK_ICON_SIZE_BUTTON),
    /* progress dialog */
    _("Wiping available disk space..."),
    /* operation launcher */
    nw_fill_operation_new (),
    /* failed dialog */
    _("Wipe failed"),
    /* success dialog */
    _("Wipe successful"),
    success_secondary_text
  );
  g_free (confirm_primary_text);
  g_free (success_secondary_text);
}

static struct {
  gboolean  fill;
  gboolean  wipe;
  gchar    *native_parent;
  gchar   **paths;
} options = {
  FALSE,
  FALSE,
  0,
  NULL
};

static GList *strv_to_list_nocopy (gchar **strv)
{
  GList *list = NULL;
  
  for (; strv && *strv; strv++) {
    list = g_list_prepend (list, *strv);
  }
  
  return g_list_reverse (list);
}

static GOptionEntry option_entries[] = {
  { "fill",             'f', 0, G_OPTION_ARG_NONE, &options.fill,
    N_("Wipe available free space"), NULL },
  { "wipe",             'w', 0, G_OPTION_ARG_NONE, &options.wipe,
    N_("Wipe specified paths"), NULL },
  { "native-parent",    'p', 0, G_OPTION_ARG_STRING, &options.native_parent,
    N_("Native handle of the caller's window"), N_("HANDLE") },
  { G_OPTION_REMAINING, 0,   0, G_OPTION_ARG_FILENAME_ARRAY, &options.paths,
    N_("Paths"), N_("PATHS") },
  { 0 }
};

int
main (int     argc,
      char  **argv)
{
  GOptionContext *context;
  GError         *err = NULL;
  int             ret = 1;
  
  setlocale (LC_ALL, "");
  
  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
  gsd_intl_init ();
  
  context = g_option_context_new (NULL);
  g_option_context_add_main_entries (context, option_entries, GETTEXT_PACKAGE);
  g_option_context_add_group (context, gtk_get_option_group (TRUE));
  
  if (! g_option_context_parse (context, &argc, &argv, &err)) {
    fprintf (stderr, _("Failed to parse options: %s\n"), err->message);
  } else if (options.fill && options.wipe) {
    fprintf (stderr, _("Failed to parse options: %s\n"),
             _("--wipe and --fill are mutually exclusive"));
  } else if (! options.fill && ! options.wipe) {
    fprintf (stderr, _("Failed to parse options: %s\n"),
             _("one of --wipe or --fill is mandatory"));
  } else if (! options.paths || ! options.paths[0]) {
    fprintf (stderr, _("Failed to parse options: %s\n"),
             _("missing PATHS"));
  } else {
    /* FIXME: validate options.native_parent */
    
    if (options.wipe) {
      GList *paths = strv_to_list_nocopy (options.paths);
      
      nw_extension_run_delete_operation (options.native_parent, paths);
      g_list_free (paths);
      ret = 0;
    } else if (options.fill) {
      GList *paths = strv_to_list_nocopy (options.paths);
      GList *work_paths = NULL;
      GList *work_mounts = NULL;
      
      if (! nw_fill_operation_filter_files (paths, &work_paths, &work_mounts,
                                            &err)) {
        fprintf (stderr, _("Failed to filter paths: %s"), err->message);
        g_error_free (err);
      } else {
        nw_extension_run_fill_operation (options.native_parent, work_paths,
                                         work_mounts);
        g_list_free_full (work_paths, g_free);
        g_list_free_full (work_mounts, g_free);
        ret = 0;
      }
      g_list_free (paths);
    } else {
      g_assert_not_reached ();
    }
  }
  
  g_strfreev (options.paths);
  
  return ret;
}
