/* OGMRip - A library for DVD ripping and encoding
 * Copyright (C) 2004-2012 Olivier Rolland <billl@users.sourceforge.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

/**
 * SECTION:ogmrip-keyfile-settings
 * @title: KeyFile Settings
 * @short_description: Settings manager using key files
 * @include: ogmrip-keyfile-settings.h
 */

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

#include "ogmrip-keyfile-settings.h"

#include <string.h>

#define OGMRIP_KEYFILE_SETTINGS_GET_PRIVATE(o) \
    (G_TYPE_INSTANCE_GET_PRIVATE ((o), OGMRIP_TYPE_KEYFILE_SETTINGS, OGMRipKeyFileSettingsPriv))

struct _OGMRipKeyFileSettingsPriv
{
  GKeyFile *keyfile;
  gchar *filename;
};

static void ogmrip_settings_finalize (GObject              *gobject);
static void ogmrip_settings_init     (OGMRipSettingsIface  *iface);

G_DEFINE_TYPE_WITH_CODE (OGMRipKeyFileSettings, ogmrip_keyfile_settings, G_TYPE_OBJECT,
    G_IMPLEMENT_INTERFACE (OGMRIP_TYPE_SETTINGS, ogmrip_settings_init))

static void
ogmrip_keyfile_settings_class_init (OGMRipKeyFileSettingsClass *klass)
{
  GObjectClass *gobject_class;

  gobject_class = G_OBJECT_CLASS (klass);
  gobject_class->finalize = ogmrip_settings_finalize;

  g_type_class_add_private (klass, sizeof (OGMRipKeyFileSettingsPriv));
}

static void
ogmrip_settings_finalize (GObject *gobject)
{
  OGMRipKeyFileSettings *keyfile;

  keyfile = OGMRIP_KEYFILE_SETTINGS (gobject);

  if (keyfile->priv->keyfile)
  {
    g_key_file_free (keyfile->priv->keyfile);
    keyfile->priv->keyfile = NULL;
  }

  if (keyfile->priv->filename)
  {
    g_free (keyfile->priv->filename);
    keyfile->priv->filename = NULL;
  }

  (*G_OBJECT_CLASS (ogmrip_keyfile_settings_parent_class)->finalize) (gobject);
}

static void
ogmrip_keyfile_settings_set_value (OGMRipSettings *settings, const gchar *section, const gchar *key, const GValue *value)
{
  OGMRipKeyFileSettings *keyfile;

  keyfile = OGMRIP_KEYFILE_SETTINGS (settings);

  switch (G_VALUE_TYPE (value))
  {
    case G_TYPE_INT:
      g_key_file_set_integer (keyfile->priv->keyfile, section, key, g_value_get_int (value));
      break;
    case G_TYPE_BOOLEAN:
      g_key_file_set_boolean (keyfile->priv->keyfile, section, key, g_value_get_boolean (value));
      break;
    case G_TYPE_DOUBLE:
      g_key_file_set_double (keyfile->priv->keyfile, section, key, g_value_get_double (value));
      break;
    case G_TYPE_STRING:
      g_key_file_set_string (keyfile->priv->keyfile, section, key, g_value_get_string (value));
      break;
    default:
      break;
  }
}

static void
ogmrip_keyfile_settings_get_value (OGMRipSettings *settings, const gchar *section, const gchar *key, GValue *value)
{
  GType type;

  type = ogmrip_settings_get_key_type (settings, section, key);
  if (type != G_TYPE_NONE)
  {
    OGMRipKeyFileSettings *keyfile;

    keyfile = OGMRIP_KEYFILE_SETTINGS (settings);

    g_value_init (value, type);

    switch (type)
    {
      case G_TYPE_INT:
        g_value_set_int (value, g_key_file_get_integer (keyfile->priv->keyfile, section, key, NULL));
        break;
      case G_TYPE_BOOLEAN:
        g_value_set_boolean (value, g_key_file_get_boolean (keyfile->priv->keyfile, section, key, NULL));
        break;
      case G_TYPE_DOUBLE:
        g_value_set_double (value, g_key_file_get_double (keyfile->priv->keyfile, section, key, NULL));
        break;
      case G_TYPE_STRING:
        {
          gchar *str;

          str = g_key_file_get_string (keyfile->priv->keyfile, section, key, NULL);
          g_value_take_string (value, str);
        }
        break;
      default:
        break;
    }
  }
}

static GSList *
ogmrip_keyfile_settings_get_subsections (OGMRipSettings *settings, const gchar *section)
{
  OGMRipKeyFileSettings *keyfile;
  GSList *list = NULL;

  gchar **groups;
  gint i;

  keyfile = OGMRIP_KEYFILE_SETTINGS (settings);

  groups = g_key_file_get_groups (keyfile->priv->keyfile, NULL);
  for (i = 0; groups[i]; i ++)
    if (g_str_has_prefix (groups[i], section))
      list = g_slist_append (list, groups[i]);

  return list;
}

static GSList *
ogmrip_keyfile_settings_get_keys (OGMRipSettings *settings, const gchar *section, gboolean recursive)
{
  GSList *list = NULL;

  OGMRipKeyFileSettings *keyfile;
  gchar **keys;
  guint i;

  keyfile = OGMRIP_KEYFILE_SETTINGS (settings);

  keys = g_key_file_get_keys (keyfile->priv->keyfile, section, NULL, NULL);
  for (i = 0; keys[i]; i ++)
    list = g_slist_append (list, keys[i]);
  g_free (keys);

  return list;
}

static void
ogmrip_keyfile_settings_remove_key (OGMRipSettings *settings, const gchar *section, const gchar *key)
{
  OGMRipKeyFileSettings *keyfile;

  keyfile = OGMRIP_KEYFILE_SETTINGS (settings);

  g_key_file_remove_key (keyfile->priv->keyfile, section, key, NULL);
}

static void
ogmrip_keyfile_settings_remove_section (OGMRipSettings *settings, const gchar *section)
{
  OGMRipKeyFileSettings *keyfile;

  keyfile = OGMRIP_KEYFILE_SETTINGS (settings);

  g_key_file_remove_group (keyfile->priv->keyfile, section, NULL);
}

static gboolean
ogmrip_keyfile_settings_has_key (OGMRipSettings *settings, const gchar *section, const gchar *key)
{
  OGMRipKeyFileSettings *keyfile;

  keyfile = OGMRIP_KEYFILE_SETTINGS (settings);

  return g_key_file_has_key (keyfile->priv->keyfile, section, key, NULL);
}

static gboolean
ogmrip_keyfile_settings_has_section (OGMRipSettings *settings, const gchar *section)
{
  OGMRipKeyFileSettings *keyfile;

  keyfile = OGMRIP_KEYFILE_SETTINGS (settings);

  return g_key_file_has_group (keyfile->priv->keyfile, section);
}

static gchar *
ogmrip_keyfile_settings_build_section (OGMRipSettings *settings, const gchar *element, va_list var_args)
{
  gchar *str, *section = NULL;

  while (element)
  {
    if (section)
      str = g_strconcat (section, "-", element, NULL);
    else
      str = g_strdup (element);

    g_free (section);
    section = str;

    element = va_arg (var_args, gchar *);
  }

  return section;
}

static const gchar *
ogmrip_keyfile_settings_get_section_name (OGMRipSettings *settings, const gchar *section)
{
  gchar *name;

  name = strrchr (section, '-');
  if (!name)
    return section;

  return name + 1;
}

static void
ogmrip_settings_init (OGMRipSettingsIface *iface)
{
  iface->set_value = ogmrip_keyfile_settings_set_value;
  iface->get_value = ogmrip_keyfile_settings_get_value;

  iface->get_subsections = ogmrip_keyfile_settings_get_subsections;
  iface->get_keys = ogmrip_keyfile_settings_get_keys;

  iface->has_key = ogmrip_keyfile_settings_has_key;
  iface->has_section = ogmrip_keyfile_settings_has_section;
  iface->remove_key = ogmrip_keyfile_settings_remove_key;
  iface->remove_section = ogmrip_keyfile_settings_remove_section;

  iface->build_section = ogmrip_keyfile_settings_build_section;
  iface->get_section_name = ogmrip_keyfile_settings_get_section_name;
}

static void
ogmrip_keyfile_settings_init (OGMRipKeyFileSettings *settings)
{
  settings->priv = OGMRIP_KEYFILE_SETTINGS_GET_PRIVATE (settings);
}

/**
 * ogmrip_keyfile_settings_new:
 *
 * Creates a new #OGMRipSettings
 *
 * Returns: the new #OGMRipSettings
 */
OGMRipSettings *
ogmrip_keyfile_settings_new (void)
{
  OGMRipKeyFileSettings *settings;

  settings = g_object_new (OGMRIP_TYPE_KEYFILE_SETTINGS, NULL);

  settings->priv->keyfile = g_key_file_new ();

  return OGMRIP_SETTINGS (settings);
}

/**
 * ogmrip_keyfile_settings_load:
 * @settings: an #OGMRipKeyFileSettings
 * @filename: the filename to load
 * @error: return location for error
 *
 * Loads a key file.
 *
 * Returns: %TRUE on success, %FALSE if an error was set
 */
gboolean
ogmrip_keyfile_settings_load (OGMRipKeyFileSettings *settings, const gchar *filename, GError **error)
{
  GError *tmp_error = NULL;

  g_return_val_if_fail (OGMRIP_IS_KEYFILE_SETTINGS (settings), FALSE);
  g_return_val_if_fail (filename != NULL, FALSE);
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

  if (!g_key_file_load_from_file (settings->priv->keyfile, filename, G_KEY_FILE_NONE, &tmp_error))
  {
    g_propagate_error (error, tmp_error);
    return FALSE;
  }

  return TRUE;
}

/**
 * ogmrip_keyfile_settings_save:
 * @settings: an #OGMRipKeyFileSettings
 * @filename: the filename where to save the keys and values
 * @error: return location for error
 *
 * Saves a key file.
 *
 * Returns: %TRUE on success, %FALSE if an error was set
 */
gboolean
ogmrip_keyfile_settings_save (OGMRipKeyFileSettings *settings, const gchar *filename, GError **error)
{
  return FALSE;
}

