/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
  Gpredict: Real-time satellite tracking and orbit prediction program

  Copyright (C)  2001-2009  Alexandru Csete, OZ9AEC.

  Authors: Alexandru Csete <oz9aec@gmail.com>

  Comments, questions and bugreports should be submitted via
  http://sourceforge.net/projects/gpredict/
  More details can be found at the project home page:

  http://gpredict.oz9aec.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, visit http://www.fsf.org/
*/
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <sys/stat.h>      /*** FIXME: ok for win32? see thunar-vfs-io-local.c */
#ifdef HAVE_CONFIG_H
#  include <build-config.h>
#endif
#include "sat-log.h"
#include "map-selector.h"
#include "compat.h"



static GtkWidget *create_preview_widget (const gchar *selection);
static void       update_preview_widget (GtkFileChooser *chooser, gpointer data);
static gchar     *get_map_humanize_size (gint64  size, gchar *buffer, gsize buflen);


/** \brief Execute map selector.
 *  \param curmap The name of the current map.
 *  \return A newly allocated string with filename of the selected map
 *          or NULL if action was cancelled.
 *
 * This function creates and executes a file chooser dialog
 * and selects the currently selected map curmap. The file chooser dialogue
 * has a custom map preview widget showing the scaled down copty of
 * the selected map as well as the size of the map.
 *
 */
gchar *
select_map (const gchar *curmap)
{
    GtkWidget     *chooser;    /* file chooser dialogue */
    GtkFileFilter *filter;     /* file filter object */
    gchar         *selection;  /* full path of selected file */
    gchar         *mapsdir;    /* stock maps directory */
    gchar         *ret = NULL;
    GtkWidget     *preview;


     /* we are going to need this as a shortcut folder
        and to find out whether selected map is stock
        or user specific
     */
     mapsdir = get_maps_dir ();
        

    /* create a new file chooser dialogue in "open file" mode */
    chooser = gtk_file_chooser_dialog_new (_("Select Map"),
                                           NULL,
                                           GTK_FILE_CHOOSER_ACTION_OPEN,
                                           GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                                           GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
                                           NULL);


    /* single selection only */
    gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (chooser), FALSE);

     /* add shortcut */
     gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (chooser), mapsdir, NULL);

    /* create filter */
    filter = gtk_file_filter_new ();
    gtk_file_filter_set_name (filter, _("Image files"));
    gtk_file_filter_add_pixbuf_formats (filter);
    gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
    
    /* select current map file */
    if (g_path_is_absolute (curmap)) {
        /* map is user specific, ie. in USER_CONF_DIR/maps/ */
        selection = g_strdup (curmap);
    }
    else {
        /* build complete path */
        selection = map_file_name (curmap);
    }
    gtk_file_chooser_select_filename (GTK_FILE_CHOOSER (chooser), selection);

    /* preview widget */
    preview = create_preview_widget (selection);
    gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (chooser), preview);
    gtk_file_chooser_set_preview_widget_active (GTK_FILE_CHOOSER (chooser), TRUE);
    /* sig connect */
    g_signal_connect (G_OBJECT (chooser), "update-preview",
                      G_CALLBACK (update_preview_widget), preview);

     /* we don't need this anymore */
    g_free (selection);

    /* run the dialogue */
    if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_ACCEPT) {
        char *filename;

        filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser));

        /* find out whether selected file is a
           stock map or user map */
        if (g_str_has_prefix (filename, mapsdir)) {
            /* selected map is a stock map */
            
            /* get file name without dir component */
            ret = g_path_get_basename (filename);
            
        }
        else {
            ret = g_strdup (filename);
        }

        
        /* clean up */
        g_free (filename);
    }
    
    gtk_widget_destroy (chooser);
    
     g_free (mapsdir);
 
    return ret;
}


/** \brief Create the preview widget and load the current map */
static GtkWidget *
create_preview_widget (const gchar *selection)
{
    GtkWidget *vbox;
    GtkWidget *img;
    GtkWidget *label;
    GdkPixbuf *obuf,*sbuf;
     gchar     *buff;
    gint       w,h;
     gint64     size;
     struct stat sb;
     gchar     *bf = NULL;


    label = gtk_label_new (NULL);
    img = gtk_image_new ();

    vbox = gtk_vbox_new (FALSE, 5);
    g_object_set_data (G_OBJECT (vbox), "image", img);
    g_object_set_data (G_OBJECT (vbox), "label", label);
    gtk_box_pack_start (GTK_BOX (vbox), img, FALSE, FALSE, 0);
    gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
    gtk_widget_show_all (vbox);

     /* load current map into preview widget */
     obuf = gdk_pixbuf_new_from_file (selection, NULL);

     if (G_LIKELY (obuf != NULL)) {

          /* store data */
          w = gdk_pixbuf_get_width (obuf);
          h = gdk_pixbuf_get_height (obuf);

          /* try to stat the file */
          if (G_UNLIKELY (g_stat (selection, &sb) < 0)) {
               sat_log_log (SAT_LOG_LEVEL_ERROR,
                               _("%s:%d: Could not stat %s"),
                               __FILE__, __LINE__, selection);

               size = 0;
          }
          else {
               size = sb.st_size;
          }

          bf = get_map_humanize_size (size, bf, 0);

          buff = g_strdup_printf ("%dx%d pixels\n%s", w, h, bf);
          gtk_label_set_text (GTK_LABEL (label), buff);
          g_free (buff);
          g_free (bf);

          /* scale the pixbuf */
          sbuf = gdk_pixbuf_scale_simple (obuf, 160, 80, GDK_INTERP_HYPER);
          g_object_unref (obuf);
            
          /* update the GtkImage from the pixbuf */
          gtk_image_set_from_pixbuf (GTK_IMAGE (img), sbuf);
          g_object_unref (sbuf);
     }
     else {
          gtk_image_set_from_stock (GTK_IMAGE (img),
                                          GTK_STOCK_MISSING_IMAGE,
                                          GTK_ICON_SIZE_LARGE_TOOLBAR);
     }

    return vbox;
}



static void
update_preview_widget (GtkFileChooser *chooser, gpointer data)
{
    GtkWidget *box = GTK_WIDGET (data);
    GtkImage  *img = GTK_IMAGE (g_object_get_data (G_OBJECT (box), "image"));
    GtkLabel  *lab = GTK_LABEL (g_object_get_data (G_OBJECT (box), "label"));
    gchar     *sel = NULL;
    GdkPixbuf *obuf,*sbuf;
    gint       w,h;
     gint64     size;
     struct stat sb;
     gchar     *buff = NULL;


    sel = gtk_file_chooser_get_preview_filename (chooser);

    if (G_LIKELY (sel != NULL)) {

          obuf = gdk_pixbuf_new_from_file (sel, NULL);

          /* try to stat the file */
          if (G_UNLIKELY (g_stat (sel, &sb) < 0)) {
               sat_log_log (SAT_LOG_LEVEL_ERROR,
                               _("%s:%d: Could not stat %s"),
                               __FILE__, __LINE__, sel);

               size = 0;
          }
          else {
               size = sb.st_size;
          }

          g_free (sel);

          if (G_LIKELY (obuf != NULL)) {

            /* store data */
            w = gdk_pixbuf_get_width (obuf);
            h = gdk_pixbuf_get_height (obuf);

               buff = get_map_humanize_size (size, buff, 0);

            sel = g_strdup_printf ("%dx%d pixels\n%s", w, h, buff);
            gtk_label_set_text (lab, sel);
            g_free (sel);
               g_free (buff);

            /* scale the pixbuf */
            sbuf = gdk_pixbuf_scale_simple (obuf, 160, 80, GDK_INTERP_HYPER);
            g_object_unref (obuf);
            
            /* update the GtkImage from the pixbuf */
            gtk_image_clear (img);
            gtk_image_set_from_pixbuf (img, sbuf);
            g_object_unref (sbuf);

               /* report success */
               gtk_file_chooser_set_preview_widget_active (chooser, TRUE);
          }
          else {
            gtk_image_clear (img);
            gtk_image_set_from_stock (GTK_IMAGE (img),
                                      GTK_STOCK_MISSING_IMAGE,
                                      GTK_ICON_SIZE_LARGE_TOOLBAR);

               /* report failure */
               gtk_file_chooser_set_preview_widget_active (chooser, FALSE);
          }

    }
}

/** \brief Convert map filesize into a human readable format
 *  \param size Size in bytes.
 *  \param buffer Destination buffer or NULL to dynamically allocate a buffer.
 *  \param buflen Length of @buffer in bytes.
 *  \return A string containing a human readable description of size.
 *
 * The caller is responsible to free the returned string using g_free()
 * if you pass NULL for buffer. Else the returned string will be a
 * pointer to buffer.
 *
 * Credits: Thunar (XFCE file manager).
 *
 **/
static gchar*
get_map_humanize_size (gint64  size,
                            gchar  *buffer,
                            gsize   buflen)
{
     /* allocate buffer if necessary */
     if (buffer == NULL) {
          buffer = g_new (gchar, 32);
          buflen = 32;
     }
     
     if (G_UNLIKELY (size > 1024ul * 1024ul * 1024ul))
          g_snprintf (buffer, buflen, "%0.1f GB", size / (1024.0 * 1024.0 * 1024.0));
     else if (size > 1024ul * 1024ul)
          g_snprintf (buffer, buflen, "%0.1f MB", size / (1024.0 * 1024.0));
     else if (size > 1024ul)
          g_snprintf (buffer, buflen, "%0.1f kB", size / 1024.0);
     else
          g_snprintf (buffer, buflen, "%lu B", (gulong) size);

     return buffer;
}

