/*
     This file is part of GNUnet
     Copyright (C) 2005, 2006, 2010 GNUnet e.V.

     GNUnet 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, or (at your
     option) any later version.

     GNUnet 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 GNUnet; see the file COPYING.  If not, write to the
     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     Boston, MA 02110-1301, USA.
*/

/**
 * @file src/fs/gnunet-fs-gtk_open-directory.c
 * @author Christian Grothoff
 */
#include "gnunet-fs-gtk_common.h"
#include "gnunet-fs-gtk_event-handler.h"


/**
 * Closure for 'add_child' function.
 */
struct AddChildContext
{
  /**
   * Name of the directory file.
   */
  const char *filename;

  /**
   * Reference to the directorie's search result.
   */
  struct SearchResult *sr;

  /**
   * Anonymity level to use for probes in the directory.
   */
  uint32_t anonymity;
};


/**
 * Function used to process entries in a directory.  Adds each
 * entry to our tab.
 *
 * @param cls closure, our 'struct AddChildContext*'
 * @param filename name of the file in the directory
 * @param uri URI of the file
 * @param meta metadata for the file; metadata for
 *        the directory if everything else is NULL/zero
 * @param length length of the available data for the file
 *           (of type size_t since data must certainly fit
 *            into memory; if files are larger than size_t
 *            permits, then they will certainly not be
 *            embedded with the directory itself).
 * @param data data available for the file (@a length bytes)
 */
static void
add_child (void *cls,
           const char *filename,
           const struct GNUNET_FS_Uri *uri,
           const struct GNUNET_CONTAINER_MetaData *meta,
           size_t length,
           const void *data)
{
  struct AddChildContext *acc = cls;

  if (NULL == uri)
  {
    /* directory meta data itself, create parent entry */
    struct GNUNET_CONTAINER_MetaData *dmeta;

    dmeta = GNUNET_CONTAINER_meta_data_duplicate (meta);
    GNUNET_CONTAINER_meta_data_insert (dmeta,
                                       "<user>",
                                       EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME,
                                       EXTRACTOR_METAFORMAT_UTF8,
                                       "text/plain",
                                       acc->filename,
                                       strlen (acc->filename) + 1);
    acc->sr = GNUNET_GTK_add_to_uri_tab (acc->anonymity, dmeta, NULL);
    GNUNET_CONTAINER_meta_data_destroy (dmeta);
    return;
  }
  if (NULL == acc->sr)
  {
    GNUNET_break (0);
    return;
  }
  GNUNET_assert (NULL != GNUNET_GTK_add_search_result (acc->sr->tab,
                                                       acc->anonymity,
                                                       acc->sr->rr,
                                                       uri,
                                                       meta,
                                                       NULL,
                                                       0));
}


/**
 * Function called from the open-directory dialog upon completion.
 *
 * @param dialog the pseudonym selection dialog
 * @param response_id response code from the dialog
 * @param user_data the builder of the dialog
 */
void
GNUNET_GTK_open_directory_dialog_response_cb (GtkDialog *dialog,
                                              gint response_id,
                                              gpointer user_data)
{
  GtkBuilder *builder = GTK_BUILDER (user_data);
  char *filename;
  struct AddChildContext acc;

  if (GTK_RESPONSE_OK != response_id)
  {
    gtk_widget_destroy (GTK_WIDGET (dialog));
    g_object_unref (G_OBJECT (builder));
    return;
  }
  filename =
    GNUNET_GTK_filechooser_get_filename_utf8 (GTK_FILE_CHOOSER (dialog));
  gtk_widget_destroy (GTK_WIDGET (dialog));
  g_object_unref (G_OBJECT (builder));
  acc.filename = filename;
  acc.sr = NULL;
  acc.anonymity =
    1; // FIXME, might want to add this to dialog to allow user to set it.
  GNUNET_FS_GTK_mmap_and_scan (filename, &add_child, &acc);
  GNUNET_free (filename);
}


/**
 * User selected "Open directory" in menu.  Display dialog, open
 * file and then display a new tab with its contents.
 *
 * @param dummy the menu entry
 * @param data the main dialog builder, unused
 */
void
GNUNET_GTK_main_menu_file_open_gnunet_directory_activate_cb (GtkWidget *dummy,
                                                             gpointer data)
{
  GtkWidget *ad;
  GtkBuilder *builder;
  GtkWidget *toplevel;
  GtkFileFilter *ff;

  builder =
    GNUNET_GTK_get_new_builder ("gnunet_fs_gtk_open_directory_dialog.glade",
                                NULL);
  if (NULL == builder)
  {
    GNUNET_break (0);
    return;
  }
  ad = GTK_WIDGET (
    gtk_builder_get_object (builder, "GNUNET_GTK_open_directory_dialog"));
  ff = GTK_FILE_FILTER (
    gtk_builder_get_object (builder, "gnunet_directory_filter"));
  /* FIXME-FEATURE: some day, write a custom file filter for gnunet-directories... */
  gtk_file_filter_add_pattern (ff, "*" GNUNET_FS_DIRECTORY_EXT);

  toplevel = gtk_widget_get_toplevel (dummy);
  if (GTK_IS_WINDOW (toplevel))
    gtk_window_set_transient_for (GTK_WINDOW (ad), GTK_WINDOW (toplevel));
  gtk_window_present (GTK_WINDOW (ad));
}

/* end of gnunet-fs-gtk_open-directory.c */
