/*   EXTRAITS DE LA LICENCE
	Copyright CEA, contributeurs : Luc BILLARD et Damien
	CALISTE, laboratoire L_Sim, (2001-2005)
  
	Adresse mèl :
	BILLARD, non joignable par mèl ;
	CALISTE, damien P caliste AT cea P fr.

	Ce logiciel est un programme informatique servant à visualiser des
	structures atomiques dans un rendu pseudo-3D. 

	Ce logiciel est régi par la licence CeCILL soumise au droit français et
	respectant les principes de diffusion des logiciels libres. Vous pouvez
	utiliser, modifier et/ou redistribuer ce programme sous les conditions
	de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA 
	sur le site "http://www.cecill.info".

	Le fait que vous puissiez accéder à cet en-tête signifie que vous avez 
	pris connaissance de la licence CeCILL, et que vous en avez accepté les
	termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel).
*/

/*   LICENCE SUM UP
	Copyright CEA, contributors : Luc BILLARD et Damien
	CALISTE, laboratoire L_Sim, (2001-2005)

	E-mail address:
	BILLARD, not reachable any more ;
	CALISTE, damien P caliste AT cea P fr.

	This software is a computer program whose purpose is to visualize atomic
	configurations in 3D.

	This software is governed by the CeCILL  license under French law and
	abiding by the rules of distribution of free software.  You can  use, 
	modify and/ or redistribute the software under the terms of the CeCILL
	license as circulated by CEA, CNRS and INRIA at the following URL
	"http://www.cecill.info". 

	The fact that you are presently reading this means that you have had
	knowledge of the CeCILL license and that you accept its terms. You can
	find a copy of this licence shipped with this software at Documentation/licence.en.txt.
*/

#include "toolFileFormat.h"

#include <visu_tools.h>
#include <visu_commandLine.h>
#include <string.h>
#include <stdlib.h>

/**
 * SECTION:toolFileFormat
 * @short_description: Describes file format objects (name patterns,
 * description, properties...).
 *
 * <para>When dealing with files, it is convenient to class then by
 * formats, one format for JPEG files, one other for
 * postscript... Such file formats are characterized by their
 * description, explaining what they are, one or more name pattern
 * (e.g. "*.jpg") and some properties (e.g. compression level for JPEG
 * file).</para>
 * <para>This module describes objects that can store all these
 * informations and deals with them. To create a new file format, use
 * tool_file_format_new(). A #ToolFileFormat object can be used in a
 * GtkFileChooser object, using a GtkFileFilter. tool_file_format_getLabel()
 * will return directly the label to give to the GtkFileFilter and the
 * name patterns can be passed to it also.</para>
 * <para>A file format property is a #ToolOption value. There are some
 * convenient routines to add common boolean or integer
 * properties. For instance, use tool_file_format_addPropertyBoolean()
 * to add a boolean property to a given #ToolFileFormat object. Then the stored
 * properties can be iterated on using a #ToolFileFormatIter iterator.</para>
 */

/**
 * ToolFileFormatIter:
 * @lst: internal pointer.
 * @name: name of the current iterated property (read only).
 * @label: label of the current iterated property (read only).
 * @val: its value (read only).
 *
 * Iterator on #ToolFileFormat object properties. See
 * tool_file_format_iterNextProperty().
 *
 * Since: 3.6
 */

GQuark tool_file_format_getQuark(void)
{
  return g_quark_from_static_string("ToolFileFormat");
}

/**
 * ToolFileFormatPrivate:
 *
 * Private attributes of #ToolFileFormat objects.
 **/
struct _ToolFileFormatPrivate
{
  /* This is the list of file patterns, for example (*.jpg; *.jpeg; *.jpe). */
  GList *fileType;
  GList *fileMatchers;
  gboolean ignoreFileType;
  
  /* This is a short text to describe this file format.
     It should not be bigger than 30 characters. */
  gchar *name;
  /* This is a private field, it is a concatenation
     of "name ({patterns},)". */
  gchar *labelString;

  /* A validating routine for this file format. */
  ToolFileFormatValidate validate;

  /* This is a private field. It enables to add some properties
     to a file format. See fileFormatAdd_property*() and tool_file_format_property_get*()
     to control them. */
  GList *properties;
};

enum {
    PROP_0,
    NAME_PROP,
    LABEL_PROP,
    IGNORE_PROP
};

static void tool_file_format_finalize(GObject *obj);
static void tool_file_format_get_property(GObject* obj, guint property_id,
                                          GValue *value, GParamSpec *pspec);
static void tool_file_format_set_property(GObject* obj, guint property_id,
                                          const GValue *value, GParamSpec *pspec);

static ToolOption* _getProperty(const ToolFileFormat *format, const gchar *name);

G_DEFINE_TYPE_WITH_CODE(ToolFileFormat, tool_file_format, VISU_TYPE_OBJECT,
                        G_ADD_PRIVATE(ToolFileFormat))

static void tool_file_format_class_init(ToolFileFormatClass *klass)
{
  DBG_fprintf(stderr, "Tool FileFormat: creating the class of the object.\n");

  G_OBJECT_CLASS(klass)->finalize     = tool_file_format_finalize;
  G_OBJECT_CLASS(klass)->set_property = tool_file_format_set_property;
  G_OBJECT_CLASS(klass)->get_property = tool_file_format_get_property;

  /**
   * ToolFileFormat::name:
   *
   * The name identifying one file format, can be translate and used in a UI.
   *
   * Since: 3.7
   */
  g_object_class_install_property
    (G_OBJECT_CLASS(klass), NAME_PROP,
     g_param_spec_string("name", _("Name"), _("File format description."), "",
                         G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
  /**
   * ToolFileFormat::label:
   *
   * The label giving the file pattern, can be translate and used in a UI.
   *
   * Since: 3.7
   */
  g_object_class_install_property
    (G_OBJECT_CLASS(klass), LABEL_PROP,
     g_param_spec_string("label", _("Label"), _("Label used to show the file pattern."), "",
                         G_PARAM_READABLE));
  /**
   * ToolFileFormat::ignore-type:
   *
   * Store if the patterns of format descibes all possible patterns
   * for the file format.
   *
   * Since: 3.7
   */
  g_object_class_install_property
    (G_OBJECT_CLASS(klass), IGNORE_PROP,
     g_param_spec_boolean("ignore-type", _("Ignore file patterns"),
                          _("Don't restrict file matching to the given patterns."),
                          FALSE, G_PARAM_READWRITE));
}

static void tool_file_format_init(ToolFileFormat *fmt)
{
  DBG_fprintf(stderr, "Tool FileFormat: initializing new object (%p).\n",
	      (gpointer)fmt);

  fmt->priv = tool_file_format_get_instance_private(fmt);
  fmt->priv->name           = (gchar*)0;
  fmt->priv->fileType       = (GList*)0;
  fmt->priv->fileMatchers   = (GList*)0;
  fmt->priv->labelString    = (gchar*)0;
  fmt->priv->validate       = (ToolFileFormatValidate)0;
  fmt->priv->properties     = (GList*)0;
  fmt->priv->ignoreFileType = FALSE;
}

static void tool_file_format_finalize(GObject *obj)
{
  ToolFileFormatPrivate *format;

  DBG_fprintf(stderr, "Tool FileFormat: finalize object %p.\n", (gpointer)obj);

  format = TOOL_FILE_FORMAT(obj)->priv;

  g_free(format->name);
  g_free(format->labelString);

  g_list_free_full(format->fileType, g_free);
  g_list_free_full(format->fileMatchers, (GDestroyNotify)g_pattern_spec_free);
  g_list_free_full(format->properties, (GDestroyNotify)tool_option_free);

  /* Chain up to the parent class */
  G_OBJECT_CLASS(tool_file_format_parent_class)->finalize(obj);

  DBG_fprintf(stderr, "Tool FileFormat: freeing ... OK.\n");
}
static void tool_file_format_get_property(GObject* obj, guint property_id,
                                          GValue *value, GParamSpec *pspec)
{
  ToolFileFormatPrivate *self = TOOL_FILE_FORMAT(obj)->priv;

  DBG_fprintf(stderr, "Tool FileFormat: get property '%s' -> ",
	      g_param_spec_get_name(pspec));
  switch (property_id)
    {
    case NAME_PROP:
      g_value_set_string(value, self->name); DBG_fprintf(stderr, "%s.\n", self->name); break;
    case LABEL_PROP:
      g_value_set_string(value, self->labelString);
      DBG_fprintf(stderr, "%s.\n", self->labelString); break;
    case IGNORE_PROP:
      g_value_set_boolean(value, self->ignoreFileType);
      DBG_fprintf(stderr, "%d.\n", self->ignoreFileType); break;
    default:
      /* We don't have any other property... */
      G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
      break;
    }
}
static void tool_file_format_set_property(GObject* obj, guint property_id,
                                          const GValue *value, GParamSpec *pspec)
{
  ToolFileFormatPrivate *self = TOOL_FILE_FORMAT(obj)->priv;
  gint nbCharacterMax = 45, lg;

  DBG_fprintf(stderr, "Tool FileFormat: set property '%s' -> ",
	      g_param_spec_get_name(pspec));
  switch (property_id)
    {
    case NAME_PROP:
      lg = strlen(g_value_get_string(value));
      if (lg > nbCharacterMax)
        {
          g_warning("The label property is bigger than"
                    " %d characters and it will be truncated.", nbCharacterMax);
          lg = nbCharacterMax;
        }
      self->name = g_strndup(g_value_get_string(value), lg);
      DBG_fprintf(stderr, "%s.\n", self->name); break;
    case IGNORE_PROP:
      self->ignoreFileType = g_value_get_boolean(value);
      DBG_fprintf(stderr, "%d.\n", self->ignoreFileType); break;
    default:
      /* We don't have any other property... */
      G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
      break;
    }
}

static void _buildLabel(ToolFileFormat *format)
{
  GList *lst;
  GString *tmpStr;
  
  tmpStr = g_string_new(format->priv->name);
  g_string_append_printf(tmpStr, " (");
  for (lst = format->priv->fileType; lst; lst = g_list_next(lst))
    {
      g_string_append_printf(tmpStr, "%s", (gchar*) lst->data);
      if (lst->next)
	g_string_append_printf(tmpStr, ", ");
    }
  if (!format->priv->fileType)
    g_string_append_printf(tmpStr, "no filter");
  if (format->priv->fileType && format->priv->ignoreFileType)
    g_string_append_printf(tmpStr, ", ...");
  g_string_append_printf(tmpStr, ")");
  if (format->priv->labelString)
    g_free(format->priv->labelString);
  format->priv->labelString = tmpStr->str;
  g_string_free(tmpStr, FALSE);
}

/**
 * tool_file_format_newRestricted:
 * @descr: a short string to label a new file format.
 * @patterns: a set of patterns to identify files of this format.
 *
 * Allocate a new #ToolFileFormat. The @patterns argument is copied in
 * the #ToolFileFormat object and can be freed safely after the call to this method.
 * The @patterns list is not all the patterns supported by the format.
 *
 * Returns: (transfer none): a newly allocated ToolFileFormat,
 * or NULL if something goes wrong.
 */
ToolFileFormat* tool_file_format_newRestricted(const gchar* descr, const gchar** patterns)
{
  ToolFileFormat *format;

  g_return_val_if_fail(descr && descr[0] && patterns, (ToolFileFormat*)0);

  format = TOOL_FILE_FORMAT(g_object_new(TOOL_TYPE_FILE_FORMAT,
                                         "name", descr, "ignore-type", TRUE, NULL));
  tool_file_format_addPatterns(format, patterns);

  return format;
}

/**
 * tool_file_format_new:
 * @descr: a short string to label a new file format.
 * @patterns: (array zero-terminated=1) (element-type utf8): a set of patterns to identify files of this format.
 *
 * Allocate a new #ToolFileFormat. The @patterns argument is copied in
 * the #ToolFileFormat object and can be freed safely after the call to this method.
 *
 * Returns: (transfer none): a newly allocated ToolFileFormat,
 * or NULL if something goes wrong.
 */
ToolFileFormat* tool_file_format_new(const gchar* descr, const gchar** patterns)
{
  ToolFileFormat *format;

  g_return_val_if_fail(descr && descr[0] && patterns, (ToolFileFormat*)0);

  format = TOOL_FILE_FORMAT(g_object_new(TOOL_TYPE_FILE_FORMAT,
                                         "name", descr, "ignore-type", FALSE, NULL));
  tool_file_format_addPatterns(format, patterns);

  return format;
}
/**
 * tool_file_format_addPatterns:
 * @fmt: a #ToolFileFormat object.
 * @patterns: (array zero-terminated=1): a list of matching patterns.
 *
 * A file format may have pattern for the naming scheme of files, like
 * "*.jpg" and "*.jpeg" for JPEG files. It's not mandatory for a file
 * format to match its own pattern anyway.
 *
 * Since: 3.7
 **/
void tool_file_format_addPatterns(ToolFileFormat *fmt, const gchar **patterns)
{
  gint n;

  g_return_if_fail(TOOL_IS_FILE_FORMAT(fmt));

  for (n = 0; patterns[n]; n++)
    fmt->priv->fileType = g_list_append(fmt->priv->fileType, g_strdup(patterns[n]));
  g_list_free_full(fmt->priv->fileMatchers, (GDestroyNotify)g_pattern_spec_free);
  fmt->priv->fileMatchers = (GList*)0;
  _buildLabel(fmt);
}
/**
 * tool_file_format_copy:
 * @from: a #ToolFileFormat object.
 *
 * Copy the given file format @from a create a new one.
 *
 * Since: 3.6
 *
 * Returns: (transfer full): a newly created #ToolFileFormat. Should
 * be freed with g_object_unref().
 */
ToolFileFormat* tool_file_format_copy(const ToolFileFormat *from)
{
  ToolFileFormat *to;
  GList *lst;

  g_return_val_if_fail(from, (ToolFileFormat*)0);

  to = TOOL_FILE_FORMAT(g_object_new(TOOL_TYPE_FILE_FORMAT,
                                     "name", from->priv->name,
                                     "ignore-type", from->priv->ignoreFileType, NULL));
  DBG_fprintf(stderr, "Tool ToolFileFormat: copy to file format %p.\n", (gpointer)to);
  to->priv->fileType       = (GList*)0;
  for (lst = from->priv->fileType; lst; lst = g_list_next(lst))
    to->priv->fileType = g_list_append(to->priv->fileType, g_strdup((gchar*)lst->data));
  _buildLabel(to);
  to->priv->properties     = (GList*)0;
  for (lst = from->priv->properties; lst; lst = g_list_next(lst))
    to->priv->properties = g_list_append(to->priv->properties,
                                         tool_option_copy((ToolOption*)lst->data));
  
  return to;
}
/**
 * tool_file_format_getName:
 * @format: a #ToolFileFormat.
 *
 * This method gives the name describing the file format.
 *
 * Returns: (transfer none): a string with the name. This string
 * should not be freed.
 */
const gchar* tool_file_format_getName(ToolFileFormat *format)
{
  DBG_fprintf(stderr, "Tool ToolFileFormat: get the name of format '%p'.\n",
	      (gpointer)format);
  g_return_val_if_fail(format, (gchar*)0);
  return format->priv->name;
}
/**
 * tool_file_format_getLabel:
 * @format: a #ToolFileFormat.
 *
 * This method gives a label describing the file format.
 *
 * Returns: (transfer none): a string made by the name and all
 * the paterns of the given format, given in parentethis. This string
 * should not be freed.
 */
const gchar* tool_file_format_getLabel(ToolFileFormat *format)
{
  DBG_fprintf(stderr, "Tool ToolFileFormat: get the label of format '%p'.\n",
	      (gpointer)format);
  g_return_val_if_fail(format, (gchar*)0);
  return format->priv->labelString;
}
/**
 * tool_file_format_getFilePatterns:
 * @format: a #ToolFileFormat.
 *
 * This method gives a list with the file patterns.
 *
 * Returns: (transfer none) (element-type utf8): a list with the file
 * patterns. This list should not be freed.
 *
 * Since: 3.6
 */
const GList* tool_file_format_getFilePatterns(ToolFileFormat *format)
{
  DBG_fprintf(stderr, "Tool ToolFileFormat: get the file patterns of format '%p'.\n",
	      (gpointer)format);
  g_return_val_if_fail(format, (GList*)0);
  return format->priv->fileType;
}

/**
 * tool_file_format_canMatch:
 * @format: a #ToolFileFormat.
 *
 * This method is used to know if the file pattern list can be used
 * to match a given filename with tool_file_format_match().
 *
 * Returns: TRUE if a call to tool_file_format_match() is safe.
 *
 * Since: 3.6
 */
gboolean tool_file_format_canMatch(ToolFileFormat* format)
{
  g_return_val_if_fail(format, FALSE);

  return !format->priv->ignoreFileType;
}
/**
 * tool_file_format_match:
 * @format: a #ToolFileFormat ;
 * @filename: a string to match.
 *
 * This method try to match the given string to one of the patterns of
 * the #ToolFileFormat @format.
 *
 * Returns: the matching pattern, if any.
 */
const gchar* tool_file_format_match(ToolFileFormat *format, const gchar *filename)
{
  GList *tmpLst;

  g_return_val_if_fail(format, FALSE);

  DBG_fprintf(stderr, "Tool FileFormat: try to match '%s' with '%s' -> ",
              filename, format->priv->name);
  tmpLst = format->priv->fileType;
  while(tmpLst && !g_pattern_match_simple(tmpLst->data, filename))
    tmpLst = g_list_next(tmpLst);
  DBG_fprintf(stderr, "%d.\n", (tmpLst != (GList*)0));
  return (tmpLst)?(const gchar*)tmpLst->data:(const gchar*)0;
}
static gboolean _validate(ToolFileFormat *format, const gchar *filename)
{
  gboolean passed;
  GList *lst;

  if (!format->priv->fileMatchers)
    for (lst = format->priv->fileType; lst; lst = g_list_next(lst))
      format->priv->fileMatchers = g_list_prepend(format->priv->fileMatchers,
                                                  g_pattern_spec_new((char*)lst->data));

  passed = FALSE;
  for (lst = format->priv->fileMatchers; lst && !passed; lst = g_list_next(lst))
    passed = g_pattern_match_string((GPatternSpec*)lst->data, filename);
  return passed;
}
/**
 * tool_file_format_validate:
 * @format: a #ToolFileFormat ;
 * @filename: a string to match.
 *
 * This method runs a minimal parsing routine set with
 * tool_file_format_setValidator() to check if the provided filename
 * correspond to this file format.
 *
 * Since: 3.7
 *
 * Returns: TRUE, if the file (after minimal parsing) is of this file
 * format. If there is no validator routine, it is using a built-in
 * one, based on pattern matching with file types, see
 * tool_file_format_addPatterns().
 */
gboolean tool_file_format_validate(ToolFileFormat *format, const gchar *filename)
{
  gboolean res;

  g_return_val_if_fail(format, FALSE);

  DBG_fprintf(stderr, "Tool FileFormat: try to validate '%s' with '%s' -> ",
              filename, format->priv->name);
  if (format->priv->validate)
    res = format->priv->validate(filename);
  else
    res = _validate(format, filename);
  DBG_fprintf(stderr, "%d.\n", res);
  return res;
}
/**
 * tool_file_format_setValidator:
 * @format: a #ToolFileFormat ;
 * @validate: (scope call) (allow-none): a pointer to a validator routine.
 *
 * Set up a validating routine that do a minimal parsing to check that
 * a provided file corresponds to this file format.
 *
 * Since: 3.7
 */
void tool_file_format_setValidator(ToolFileFormat *format,
                                   ToolFileFormatValidate validate)
{
  g_return_if_fail(format);
  format->priv->validate = validate;
}

/**
 * tool_file_format_addOption:
 * @format: a #ToolFileFormat object.
 * @opt: a #ToolOption object.
 *
 * File format may have options, like pseudo-potential pparameters in
 * case of BigDFT calculations.
 *
 * Since: 3.7
 **/
void tool_file_format_addOption(ToolFileFormat *format, ToolOption *opt)
{
  g_return_if_fail(TOOL_IS_FILE_FORMAT(format));

  format->priv->properties = g_list_append(format->priv->properties, (gpointer)opt);
}

/**
 * tool_file_format_addPropertyBoolean:
 * @format: the #ToolFileFormat object.
 * @name: a name ;
 * @label: a description ;
 * @defaultVal: a default value.
 *
 * Add a new boolean property to the file format @format.
 *
 * Returns: (transfer none): a newly created #ToolOption, free with tool_option_free().
 */
ToolOption* tool_file_format_addPropertyBoolean(ToolFileFormat *format,
                                                const gchar *name, const gchar *label,
                                                gboolean defaultVal)
{
  ToolOption *opt;
  GValue *val;

  opt = _getProperty(format, name);
  if (!opt)
    {
      opt = tool_option_new(name, label, G_TYPE_BOOLEAN);
      format->priv->properties = g_list_append(format->priv->properties, (gpointer)opt);
    }
  val = tool_option_getValue(opt);
  g_value_set_boolean(val, defaultVal);
  return opt;
}
/**
 * tool_file_format_addPropertyInt:
 * @format: the #ToolFileFormat object.
 * @name: a name ;
 * @label: a description ;
 * @defaultVal: a default value.
 *
 * Add a new integer property to the file format @format.
 *
 * Returns: (transfer none): a newly created #ToolOption, free with tool_option_free().
 */
ToolOption* tool_file_format_addPropertyInt(ToolFileFormat *format,
                                            const gchar *name, const gchar *label,
                                            gint defaultVal)
{
  ToolOption *opt;
  GValue *val;

  opt = _getProperty(format, name);
  if (!opt)
    {
      opt = tool_option_new(name, label, G_TYPE_INT);
      format->priv->properties = g_list_append(format->priv->properties, (gpointer)opt);
    }
  val = tool_option_getValue(opt);
  g_value_set_int(val, defaultVal);
  return opt;
}
/**
 * tool_file_format_addPropertyDouble:
 * @format: the #ToolFileFormat object.
 * @name: a name ;
 * @label: a description ;
 * @defaultVal: a default value.
 *
 * Add a new integer property to the file format @format.
 *
 * Since: 3.7
 *
 * Returns: (transfer none): a newly created #ToolOption, free with tool_option_free().
 */
ToolOption* tool_file_format_addPropertyDouble(ToolFileFormat *format,
                                               const gchar *name, const gchar *label,
                                               gdouble defaultVal)
{
  ToolOption *opt;
  GValue *val;

  opt = _getProperty(format, name);
  if (!opt)
    {
      opt = tool_option_new(name, label, G_TYPE_DOUBLE);
      format->priv->properties = g_list_append(format->priv->properties, (gpointer)opt);
    }
  val = tool_option_getValue(opt);
  g_value_set_double(val, defaultVal);
  return opt;
}

/**
 * tool_file_format_iterNextProperty:
 * @format: a #ToolFileFormat object.
 * @iter: an iterator.
 *
 * Run to the next property of the file format @format. The iterator
 * attributes are updated so it's convenient to access the property
 * values and details, see #ToolFileFormatIter.
 *
 * Since: 3.6
 *
 * Returns: TRUE if any.
 */
gboolean tool_file_format_iterNextProperty(ToolFileFormat *format,
                                           ToolFileFormatIter *iter)
{
  if (!iter->lst)
    iter->lst = format->priv->properties;
  else
    iter->lst = g_list_next(iter->lst);

  if (!iter->lst)
    return FALSE;

  iter->name  = (gchar*)tool_option_getName ((ToolOption*)iter->lst->data);
  iter->label = (gchar*)tool_option_getLabel((ToolOption*)iter->lst->data);
  iter->val   = tool_option_getValue((ToolOption*)iter->lst->data);

  return TRUE;
}

static ToolOption* _getProperty(const ToolFileFormat *format, const gchar *name)
{
  GList *lst;

  g_return_val_if_fail(format && name, (ToolOption*)0);

  DBG_fprintf(stderr, "Tool FileFormat: grep property '%s' from file format %p.\n",
              name, (gpointer)format);
  for (lst = format->priv->properties; lst; lst = g_list_next(lst))
    if (!strcmp(name, tool_option_getName((ToolOption*)lst->data)))
      return (ToolOption*)lst->data;
  return (ToolOption*)0;
}

/**
 * tool_file_format_setPropertiesFromCLI:
 * @format: A #ToolFileFormat object.
 *
 * Scan all options from command line and affects values.
 *
 * Since: 3.8
 **/
void tool_file_format_setPropertiesFromCLI(ToolFileFormat *format)
{
  GHashTable *opts;
  GHashTableIter iter;
  gpointer key, value;
  ToolOption *prop;

  opts = commandLineGet_options();
  if (!opts)
    return;

  g_hash_table_iter_init(&iter, opts);
  while(g_hash_table_iter_next(&iter, &key, &value))
    {
      prop = _getProperty(format, (const gchar*)key);
      if (prop)
        g_value_copy(tool_option_getValue((ToolOption*)value),
                     tool_option_getValue(prop));
    }
}

/**
 * tool_file_format_getPropertyBoolean:
 * @format: a #ToolFileFormat object.
 * @name: a property name.
 *
 * Retrieves the value of property @prop.
 *
 * Since: 3.8
 *
 * Returns: the property value if exists, FALSE otherwise.
 **/
gboolean tool_file_format_getPropertyBoolean(const ToolFileFormat *format,
                                             const gchar *name)
{
  ToolOption *prop;

  g_return_val_if_fail(TOOL_IS_FILE_FORMAT(format), FALSE);

  prop = _getProperty(format, name);
  if (!prop)
    return FALSE;

  return g_value_get_boolean(tool_option_getValue(prop));  
}

/**
 * tool_file_format_getPropertyInt:
 * @format: a #ToolFileFormat object.
 * @name: a property name.
 *
 * Retrieves the value of property @prop.
 *
 * Since: 3.8
 *
 * Returns: the property value if exists, -1 otherwise.
 **/
gint tool_file_format_getPropertyInt(const ToolFileFormat *format,
                                     const gchar *name)
{
  ToolOption *prop;

  g_return_val_if_fail(TOOL_IS_FILE_FORMAT(format), -1);

  prop = _getProperty(format, name);
  if (!prop)
    return -1;

  return g_value_get_int(tool_option_getValue(prop));  
}
