/* PSPPIRE - a graphical user interface for PSPP.
   Copyright (C) 2007, 2009, 2010, 2011, 2012  Free Software Foundation

   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 3 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, see <http://www.gnu.org/licenses/>. */


/* This file is a rubbish bin where stuff gets put when it doesn't seem to
   belong anywhere else.
*/
#include <config.h>

#include	<glib-object.h>

#include <glib.h>
#include "helper.h"
#include <data/format.h>
#include <data/data-in.h>
#include <data/data-out.h>
#include <data/dictionary.h>
#include <data/casereader-provider.h>
#include <libpspp/message.h>
#include "psppire-syntax-window.h"
#include <gtk/gtk.h>
#include <libpspp/i18n.h>

#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <data/settings.h>

#include "psppire-data-store.h"
#include "psppire.h"

#include "gl/configmake.h"
#include "xalloc.h"

#include <gettext.h>

/* Returns a copy of IN with each underscore doubled.  The caller should free
   the returned string (with free()) when it is no longer needed. */
char *
escape_underscores (const char *in)
{
  char *out = xmalloc (2 * strlen (in) + 1);
  char *p;

  p = out;
  for (; *in != '\0'; in++)
    {
      if (*in == '_')
        *p++ = '_';
      *p++ = *in;
    }
  *p = '\0';

  return out;
}

/* Formats a value according to VAR's print format and strips white space
   appropriately for VAR's type.  That is, if VAR is numeric, strips leading
   white space (because numbers are right-justified within their fields), and
   if VAR is string, strips trailing white space (because spaces pad out string
   values on the right).

   Returns an allocated string.  The returned string must be freed when no
   longer required. */
gchar *
value_to_text (union value v, const struct variable *var)
{
  return value_to_text__ (v, var_get_print_format (var),
                          var_get_encoding (var));
}

/* Formats a value with format FORMAT and strips white space appropriately for
   FORMATs' type.  That is, if FORMAT is numeric, strips leading white space
   (because numbers are right-justified within their fields), and if FORMAT is
   string, strips trailing white space (because spaces pad out string values on
   the right).

   Returns an allocated string.  The returned string must be freed when no
   longer required. */
gchar *
value_to_text__ (union value v,
                 const struct fmt_spec *format, const char *encoding)
{
  gchar *s;

  s = data_out (&v, encoding, format);
  if (fmt_is_numeric (format->type))
    g_strchug (s);
  else
    g_strchomp (s);

  return s;
}

/* Converts TEXT to a value.

   VAL will be initialised and filled by this function.
   It is the caller's responsibility to destroy VAL when no longer needed.
   VAR must be the variable with which VAL is associated.

   On success, VAL is returned, NULL otherwise.
*/
union value *
text_to_value (const gchar *text,
	       const struct variable *var,
	       union value *val)
{
  const struct fmt_spec *format = var_get_print_format (var);
  int width = var_get_width (var);

  if ( format->type != FMT_A)
    {
      if ( ! text ) return NULL;

      {
	const gchar *s = text;
	while (*s)
	  {
	    if ( !isspace (*s))
	      break;
	    s++;
	  }

	if ( !*s) return NULL;
      }
    }

  value_init (val, width);
  free (data_in (ss_cstr (text), UTF8, format->type, val, width,
                 var_get_encoding (var)));

  return val;
}


/* This function must be used whenever a filename generated by glib,
   (eg, from gtk_file_chooser_get_filename) and passed to the C library,
   (eg through a pspp syntax string).
*/
gchar *
convert_glib_filename_to_system_filename (const gchar *fname, GError **err)
{
  gchar *output_name;

#ifdef G_OS_WIN32
  const gchar *target_encoding;
  gchar *utf8_name = NULL;

  g_get_charset (&target_encoding);

  output_name = g_convert (fname, -1, target_encoding,
			"UTF-8", NULL, NULL, err);
#else
  output_name = xstrdup (fname);
#endif

  return output_name;
}



#define _(msgid) gettext (msgid)
#define N_(msgid) msgid


static void
give_help (void)
{
  GtkWidget *dialog;

  dialog = gtk_message_dialog_new (NULL,
                                   GTK_DIALOG_MODAL,
                                   GTK_MESSAGE_INFO,
                                   GTK_BUTTONS_CLOSE,
                                   _("Sorry. The help system hasn't yet "
                                     "been implemented."));
  gtk_dialog_run (GTK_DIALOG (dialog));
  gtk_widget_destroy (dialog);
}

void
connect_help (GtkBuilder *xml)
{
  GSList *helps = gtk_builder_get_objects (xml);

  GSList *i;
  for ( i = helps; i ; i = g_slist_next (i))
    {
      GObject *o = i->data;
      if ( GTK_IS_WIDGET (o) )
	{
	  const gchar *name = gtk_buildable_get_name (GTK_BUILDABLE (o));
	  gchar s[12] = {0};

	  if ( name)
	    strncpy (s, name, 11);
	  s[11] = '\0';


	  if ( 0 == strcmp ("help_button", s))
	    {
	    g_signal_connect (o, "clicked", give_help, 0);
	    }
	}
    }

  g_slist_free (helps);
}


/* Create a deep copy of SRC */
GtkListStore *
clone_list_store (const GtkListStore *src)
{
  GtkTreeIter src_iter;
  gboolean ok;
  gint i;
  const gint n_cols =  gtk_tree_model_get_n_columns (GTK_TREE_MODEL (src));
  GType *types = g_malloc (sizeof (*types) *  n_cols);

  int row = 0;
  GtkListStore *dest;

  for (i = 0 ; i < n_cols; ++i )
    types[i] = gtk_tree_model_get_column_type (GTK_TREE_MODEL (src), i);

  dest = gtk_list_store_newv (n_cols, types);

  for (ok = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (src),
					   &src_iter);
       ok;
       ok = gtk_tree_model_iter_next (GTK_TREE_MODEL (src), &src_iter))
    {
      GtkTreeIter dest_iter;
      gtk_list_store_append  (dest, &dest_iter);

      for (i = 0 ; i < n_cols; ++i )
	{
	  GValue val = {0};

	  gtk_tree_model_get_value (GTK_TREE_MODEL (src), &src_iter, i, &val);
	  gtk_list_store_set_value (dest, &dest_iter, i, &val);

	  g_value_unset (&val);
	}
      row++;
    }

  g_free (types);

  return dest;
}




static gboolean 
on_delete (GtkWindow *window, GdkEvent *e, GtkWindow **addr)
{
  *addr = NULL;

  return FALSE;
}

char *
paste_syntax_to_window (gchar *syntax)
{
  static GtkWidget *the_syntax_pasteboard = NULL;

  GtkTextBuffer *buffer = NULL;

  if ( NULL == the_syntax_pasteboard)
    {
      the_syntax_pasteboard = psppire_syntax_window_new (NULL);
      g_signal_connect (the_syntax_pasteboard, "delete-event", G_CALLBACK (on_delete),
			&the_syntax_pasteboard);
    }

  buffer = GTK_TEXT_BUFFER (PSPPIRE_SYNTAX_WINDOW (the_syntax_pasteboard)->buffer);

  gtk_text_buffer_begin_user_action (buffer);
  gtk_text_buffer_insert_at_cursor (buffer, syntax, -1);
  gtk_text_buffer_insert_at_cursor (buffer, "\n", 1);
  gtk_text_buffer_end_user_action (buffer);

  gtk_widget_show (the_syntax_pasteboard);

  return syntax;
}


/* gtk_box_pack_start_defaults is deprecated.
   Therefore we roll our own until a better solution is found */
void
psppire_box_pack_start_defaults (GtkBox *box, GtkWidget *widget)
{
  gtk_box_pack_start (box, widget, TRUE, TRUE, 0);
}
