/* Chrysalide - Outil d'analyse de fichiers binaires
 * configuration.c - prototypes pour l'équivalent Python du fichier "glibext/configuration.c"
 *
 * Copyright (C) 2012 Cyrille Bagard
 *
 *  This file is part of Chrysalide.
 *
 *  OpenIDA 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.
 *
 *  OpenIDA 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, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */


#include "configuration.h"


#include <pygobject.h>


#include <glibext/configuration.h>



/* ---------------------------- ELEMENT DE CONFIGURATION ---------------------------- */


/* Crée un nouvel objet Python de type 'ConfigParam'. */
static PyObject *py_config_param_new(PyTypeObject *, PyObject *, PyObject *);

/* Efface toute valeur courante d'un paramètre de configuration. */
static PyObject *py_config_param_make_empty(PyObject *, PyObject *);

/* Réinitialise la valeur d'un paramètre de configuration. */
static PyObject *py_config_param_reset(PyObject *, PyObject *);

/* Indique le chemin d'accès utilisé pour un paramètre. */
static PyObject *py_config_param_get_path(PyObject *, void *);

/* Indique le type de valeur utilisée par un paramètre. */
static PyObject *py_config_param_get_type(PyObject *, void *);

/* Indique le statut d'une valeur utilisée par un paramètre. */
static PyObject *py_config_param_get_state(PyObject *, void *);

/* Indique la valeur courante d'un paramètre de configuration. */
static PyObject *py_config_param_get_value(PyObject *, void *);

/* Modifie la valeur courante d'un paramètre de configuration. */
static int py_config_param_set_value(PyObject *, PyObject *, void *);

/* Définit les constantes pour les paramètres. */
static bool py_config_param_define_constants(PyObject *);



/* ----------------------------- PARCOURS DE PARAMETRES ----------------------------- */



typedef struct _pyConfigParamIterator
{

  PyObject_HEAD
  long int m;
  long int i;



    GGenConfig *config;                     /* Configuration à parcourir   */
    GList *params;                          /* Liste de paramètres         */

    GList *last;                            /* Dernier élément retourné    */

} pyConfigParamIterator;




/* Prend acte d'un compteur de référence à 0. */
static void py_config_param_iterator_dealloc(PyObject *);

/* Fournit un itérateur pour paramètres de configuration. */
static PyObject *py_config_param_iterator_iter(PyObject *);

/* Fournit un itérateur pour paramètres de configuration. */
static PyObject *py_config_param_iterator_next(PyObject *);

/* Initialise un objet Python de type 'ConfigParamIterator'. */
static int py_config_param_iterator_init(PyObject *, PyObject *, PyObject *);



/* ----------------------- GESTION GENERIQUE DE CONFIGURATION ----------------------- */


/* Crée un nouvel objet Python de type 'GenConfig'. */
static PyObject *py_generic_config_new(PyTypeObject *, PyObject *, PyObject *);

/* Lit la configuration depuis un fichier. */
static PyObject *py_generic_config_read(PyObject *, PyObject *);

/* Ecrit la configuration dans un fichier. */
static PyObject *py_generic_config_write(PyObject *, PyObject *);

/* Retrouve un élément de configuration par son chemin. */
static PyObject *py_generic_config_search(PyObject *, PyObject *);

/* Ajoute un paramètre à une configuration. */
static PyObject *py_generic_config_add(PyObject *, PyObject *);

/* Retire un paramètre d'une configuration. */
static PyObject *py_generic_config_delete(PyObject *, PyObject *);

/* Fournit le chemin d'accès au binaire représenté. */
static PyObject *py_generic_config_get_filename(PyObject *, void *);



/* ---------------------------------------------------------------------------------- */
/*                              ELEMENT DE CONFIGURATION                              */
/* ---------------------------------------------------------------------------------- */


/******************************************************************************
*                                                                             *
*  Paramètres  : type = type de l'objet à instancier.                         *
*                args = arguments fournis à l'appel.                          *
*                kwds = arguments de type key=val fournis.                    *
*                                                                             *
*  Description : Crée un nouvel objet Python de type 'ConfigParam'.           *
*                                                                             *
*  Retour      : Instance Python mise en place.                               *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_config_param_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    PyObject *result;                       /* Instance à retourner        */
    char *path;                             /* Accès au paramètre          */
    unsigned int ptype;                     /* Type de paramètre           */
    PyObject *value;                        /* Valeur par défaut éventuelle*/
    int ret;                                /* Bilan de lecture des args.  */
    GCfgParam *param;                       /* Paramètre mis en place      */

    value = NULL;

    ret = PyArg_ParseTuple(args, "sI|O", &path, &ptype, &value);
    if (!ret) Py_RETURN_NONE;

    if (value == NULL || value == Py_None)
        param = g_config_param_new_empty(path, ptype);

    else
        switch (ptype)
        {
            case CPT_BOOLEAN:
                if (PyBool_Check(value))
                    param = g_config_param_new(path, CPT_BOOLEAN, (bool)(value == Py_True));
                else
                    param = NULL;
                break;

            case CPT_INTEGER:
                if (PyLong_Check(value))
                    param = g_config_param_new(path, CPT_INTEGER, (int)PyLong_AsLong(value));
                else
                    param = NULL;
                break;

            case CPT_STRING:
                if (PyUnicode_Check(value))
                    param = g_config_param_new(path, CPT_STRING, PyUnicode_DATA(value));
                else
                    param = NULL;
                break;

            default:
                param = NULL;
                break;

        }

    if (param != NULL)
    {
        result = pygobject_new(G_OBJECT(param));
        g_object_unref(param);
    }
    else result = NULL;

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self = paramètre de configuration à manipuler.               *
*                args = non utilisé ici.                                      *
*                                                                             *
*  Description : Efface toute valeur courante d'un paramètre de configuration.*
*                                                                             *
*  Retour      : None.                                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_config_param_make_empty(PyObject *self, PyObject *args)
{
    GCfgParam *param;                       /* Paramètre visé par l'opérat°*/

    param = G_CFG_PARAM(pygobject_get(self));

    g_config_param_make_empty(param);

    Py_RETURN_NONE;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self = paramètre de configuration à manipuler.               *
*                args = non utilisé ici.                                      *
*                                                                             *
*  Description : Réinitialise la valeur d'un paramètre de configuration.      *
*                                                                             *
*  Retour      : None.                                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_config_param_reset(PyObject *self, PyObject *args)
{
    GCfgParam *param;                       /* Paramètre visé par l'opérat°*/

    param = G_CFG_PARAM(pygobject_get(self));

    g_config_param_reset(param);

    Py_RETURN_NONE;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self = paramètre de configuration à manipuler.               *
*                closure = non utilisé ici.                                   *
*                                                                             *
*  Description : Indique le chemin d'accès utilisé pour un paramètre.         *
*                                                                             *
*  Retour      : Chemin d'accès en Python.                                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_config_param_get_path(PyObject *self, void *closure)
{
    GCfgParam *param;                       /* Paramètre visé par l'opérat°*/
    const char *path;                       /* Chemin d'accès à diffuser   */

    param = G_CFG_PARAM(pygobject_get(self));
    path = g_config_param_get_path(param);

    return PyUnicode_FromString(path);

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self = paramètre de configuration à manipuler.               *
*                closure = non utilisé ici.                                   *
*                                                                             *
*  Description : Indique le type de valeur utilisée par un paramètre.         *
*                                                                             *
*  Retour      : Type en Python.                                              *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_config_param_get_type(PyObject *self, void *closure)
{
    GCfgParam *param;                       /* Paramètre visé par l'opérat°*/
    ConfigParamType type;                   /* Type de paramètre           */

    param = G_CFG_PARAM(pygobject_get(self));
    type = g_config_param_get_ptype(param);

    return PyLong_FromLong(type);

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self = paramètre de configuration à manipuler.               *
*                closure = non utilisé ici.                                   *
*                                                                             *
*  Description : Indique le statut d'une valeur utilisée par un paramètre.    *
*                                                                             *
*  Retour      : Etat en Python.                                              *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_config_param_get_state(PyObject *self, void *closure)
{
    GCfgParam *param;                       /* Paramètre visé par l'opérat°*/
    ConfigParamState state;                 /* Statut de paramètre         */

    param = G_CFG_PARAM(pygobject_get(self));
    state = g_config_param_get_state(param);

    return PyLong_FromLong(state);

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self = paramètre de configuration à manipuler.               *
*                closure = non utilisé ici.                                   *
*                                                                             *
*  Description : Indique la valeur courante d'un paramètre de configuration.  *
*                                                                             *
*  Retour      : Etat en Python.                                              *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_config_param_get_value(PyObject *self, void *closure)
{
    PyObject *result;                       /* Valeur à retourner          */
    GCfgParam *param;                       /* Paramètre visé par l'opérat°*/
    ConfigParamType type;                   /* Type de paramètre manipulé  */
    bool boolean;                           /* Valeur booléenne            */
    int integer;                            /* Valeur entière              */
    char *string;                           /* Chaîne de caractères        */

    param = G_CFG_PARAM(pygobject_get(self));
    type = g_config_param_get_ptype(param);

    switch (type)
    {
        case CPT_BOOLEAN:
            g_config_param_get_value(param, &boolean);
            result = (boolean ? Py_True : Py_False);
            Py_INCREF(result);
            break;

        case CPT_INTEGER:
            g_config_param_get_value(param, &integer);
            result = PyLong_FromLong(integer);
            break;

        case CPT_STRING:
            g_config_param_get_value(param, &string);
            if (string != NULL)
                result = PyUnicode_FromString(string);
            else
            {
                result = Py_None;
                Py_INCREF(result);
            }
            break;

        default:
            result = NULL;
            break;

    }

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self    = paramètre de configuration à manipuler.            *
*                value   = nouvelle valeur à convertir et définir.            *
*                closure = non utilisé ici.                                   *
*                                                                             *
*  Description : Modifie la valeur courante d'un paramètre de configuration.  *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static int py_config_param_set_value(PyObject *self, PyObject *value, void *closure)
{
    int result;                             /* Conclusion à remonter       */
    GCfgParam *param;                       /* Paramètre visé par l'opérat°*/
    ConfigParamType type;                   /* Type de paramètre manipulé  */

    result = -1;

    param = G_CFG_PARAM(pygobject_get(self));

    if (value == Py_None)
    {
        g_config_param_make_empty(param);
        result = 0;
    }

    else
    {
        type = g_config_param_get_ptype(param);

        switch (type)
        {
            case CPT_BOOLEAN:
                if (PyBool_Check(value))
                {
                    g_config_param_set_value(param, (bool)(value == Py_True));
                    result = 0;
                }
                break;

            case CPT_INTEGER:
                if (PyLong_Check(value))
                {
                    g_config_param_set_value(param, (int)PyLong_AsLong(value));
                    result = 0;
                }
                break;

            case CPT_STRING:
                if (PyUnicode_Check(value))
                {
                    g_config_param_set_value(param, PyUnicode_DATA(value));
                    result = 0;
                }
                break;

            default:
                break;

        }

    }

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : -                                                            *
*                                                                             *
*  Description : Fournit un accès à une définition de type à diffuser.        *
*                                                                             *
*  Retour      : Définition d'objet pour Python.                              *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

PyTypeObject *get_python_config_param_type(void)
{
    static PyMethodDef py_config_param_methods[] = {
        { "make_empty", py_config_param_make_empty,
          METH_NOARGS,
          "Unset the value of the current parameter."
        },
        { "reset", py_config_param_reset,
          METH_NOARGS,
          "Reset the content of the current parameter."
        },
        { NULL }
    };

    static PyGetSetDef py_config_param_getseters[] = {
        {
            "path", py_config_param_get_path, NULL,
            "Show the path used as key for a configuration parameter.", NULL
        },
        {
            "type", py_config_param_get_type, NULL,
            "Show the type of value provided by a configuration parameter.", NULL
        },
        {
            "state", py_config_param_get_state, NULL,
            "Show the state of a configuration parameter.", NULL
        },
        {
            "value", py_config_param_get_value, py_config_param_set_value,
            "Handle the value of a configuration parameter.", NULL
        },
        { NULL }
    };

    static PyTypeObject py_config_param_type = {

        PyVarObject_HEAD_INIT(NULL, 0)

        .tp_name        = "pychrysalide.glibext.ConfigParam",
        .tp_basicsize   = sizeof(PyGObject),

        .tp_flags       = Py_TPFLAGS_DEFAULT,

        .tp_doc         = "PyChrysalide generic configuration",

        .tp_methods     = py_config_param_methods,
        .tp_getset      = py_config_param_getseters,
        .tp_new         = (newfunc)py_config_param_new

    };

    return &py_config_param_type;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : dict = dictionnaire à compléter.                             *
*                                                                             *
*  Description : Définit les constantes pour les paramètres.                  *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static bool py_config_param_define_constants(PyObject *dict)
{
    int ret;                                /* Bilan d'un ajout            */

#define DEF_ULONG_CONST(name)                                               \
    ret = PyDict_SetItemString(dict, #name, PyLong_FromUnsignedLong(name)); \
    if (ret == -1) return false;

    DEF_ULONG_CONST(CPT_BOOLEAN);
    DEF_ULONG_CONST(CPT_INTEGER);
    DEF_ULONG_CONST(CPT_STRING);
    DEF_ULONG_CONST(CPT_COUNT);

    DEF_ULONG_CONST(CPS_UNDEFINED);
    DEF_ULONG_CONST(CPS_CHANGED);
    DEF_ULONG_CONST(CPS_DEFAULT);
    DEF_ULONG_CONST(CPS_EMPTY);

    return true;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : module = module dont la définition est à compléter.          *
*                                                                             *
*  Description : Prend en charge l'objet 'pychrysalide.glibext.ConfigParam'.  *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bool register_python_config_param(PyObject *module)
{
    PyTypeObject *py_config_param_type;     /* Type Python 'ConfigParam'     */
    int ret;                                /* Bilan d'un appel            */
    PyObject *dict;                         /* Dictionnaire du module      */

    py_config_param_type = get_python_config_param_type();

    py_config_param_type->tp_base = &PyGObject_Type;
    py_config_param_type->tp_basicsize = py_config_param_type->tp_base->tp_basicsize;

    if (PyType_Ready(py_config_param_type) != 0)
        return false;

    if (!py_config_param_define_constants(py_config_param_type->tp_dict))
        return false;

    Py_INCREF(py_config_param_type);
    ret = PyModule_AddObject(module, "ConfigParam", (PyObject *)py_config_param_type);
    if (ret != 0) return false;

    dict = PyModule_GetDict(module);
    pygobject_register_class(dict, "ConfigParam", G_TYPE_CFG_PARAM, py_config_param_type,
                             Py_BuildValue("(O)", py_config_param_type->tp_base));

    return true;

}



/* ---------------------------------------------------------------------------------- */
/*                               PARCOURS DE PARAMETRES                               */
/* ---------------------------------------------------------------------------------- */


/******************************************************************************
*                                                                             *
*  Paramètres  : self = instance Python à libérer de la mémoire.              *
*                                                                             *
*  Description : Prend acte d'un compteur de référence à 0.                   *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void py_config_param_iterator_dealloc(PyObject *self)
{
    pyConfigParamIterator *iterator;        /* Références pour le parcours */

    /**
     * Il aurait été sans doute mieux de reposer ici sur .tp_finalize,
     * mais cela semble impliquer de mettre en place tous les mécanismes de GC...
     *
     * cf. https://docs.python.org/3/extending/newtypes.html#finalization-and-de-allocation
     */

    iterator = (pyConfigParamIterator *)self;

    g_generic_config_runlock(iterator->config);
    g_object_unref(G_OBJECT(iterator->config));

    Py_TYPE(self)->tp_free((PyObject*)self);

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self = itérateur à manipuler.                                *
*                                                                             *
*  Description : Fournit un itérateur pour paramètres de configuration.       *
*                                                                             *
*  Retour      : Instance Python prête à emploi.                              *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_config_param_iterator_iter(PyObject *self)
{
    Py_INCREF(self);

    return self;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self = itérateur à manipuler.                                *
*                                                                             *
*  Description : Fournit un itérateur pour paramètres de configuration.       *
*                                                                             *
*  Retour      : Instance Python prête à emploi.                              *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_config_param_iterator_next(PyObject *self)
{
    PyObject *result;                       /* Instance à retourner        */
    pyConfigParamIterator *iterator;        /* Références pour le parcours */
    GList *item;                            /* Nouvel élément courant      */

    iterator = (pyConfigParamIterator *)self;

    if (iterator->last == NULL) item = iterator->params;
    else item = g_list_next(iterator->last);

    iterator->last = item;

    if (item != NULL)
    {
        result = pygobject_new(G_OBJECT(item->data));
        Py_XINCREF(result);
    }
    else
    {
        PyErr_SetNone(PyExc_StopIteration);
        result = NULL;
    }

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self = objet instancié à initialiser.                        *
*                args = arguments fournis à l'appel.                          *
*                kwds = arguments de type key=val fournis.                    *
*                                                                             *
*  Description : Initialise un objet Python de type 'ConfigParamIterator'.    *
*                                                                             *
*  Retour      : Instance Python mise en place.                               *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static int py_config_param_iterator_init(PyObject *self, PyObject *args, PyObject *kwds)
{
    pyConfigParamIterator *iterator;        /* Références pour le parcours */
    PyObject *config;                       /* Configuration format Python */
    int ret;                                /* Bilan de lecture des args.  */

    ret = PyArg_ParseTuple(args, "O", &config);
    if (!ret) return -1;

    ret = PyObject_IsInstance(config, (PyObject *)get_python_generic_config_type());
    if (!ret) return -1;

    iterator = (pyConfigParamIterator *)self;

    iterator->config = G_GEN_CONFIG(pygobject_get(config));
    g_object_ref(G_OBJECT(iterator->config));

    g_generic_config_rlock(iterator->config);

    iterator->params = g_generic_config_list_params(iterator->config);

    iterator->last = NULL;

    return 0;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : -                                                            *
*                                                                             *
*  Description : Fournit un accès à une définition de type à diffuser.        *
*                                                                             *
*  Retour      : Définition d'objet pour Python.                              *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

PyTypeObject *get_python_config_param_iterator_type(void)
{
    static PyTypeObject py_config_param_iterator_type = {

        PyVarObject_HEAD_INIT(NULL, 0)

        .tp_name        = "pychrysalide.glibext.ConfigParamIterator",
        .tp_basicsize   = sizeof(pyConfigParamIterator),

        .tp_dealloc     = py_config_param_iterator_dealloc,

        .tp_flags       = Py_TPFLAGS_DEFAULT,

        .tp_doc         = "Iterator for configuration parameters",

        .tp_iter        = py_config_param_iterator_iter,
        .tp_iternext    = py_config_param_iterator_next,

        .tp_init        = py_config_param_iterator_init,

        .tp_new         = PyType_GenericNew,

    };

    return &py_config_param_iterator_type;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : module = module dont la définition est à compléter.          *
*                                                                             *
*  Description : Prend en charge l'objet 'pychrysalide...ConfigParamIterator'.*
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bool register_python_config_param_iterator(PyObject *module)
{
    PyTypeObject *py_config_param_iterator_type;    /* Type Python 'ConfigParamIterator' */
    int ret;                                /* Bilan d'un appel            */

    py_config_param_iterator_type = get_python_config_param_iterator_type();

    py_config_param_iterator_type->tp_base = &PyBaseObject_Type;
    py_config_param_iterator_type->tp_basicsize = py_config_param_iterator_type->tp_base->tp_basicsize;

    if (PyType_Ready(py_config_param_iterator_type) != 0)
        return false;

    Py_INCREF(py_config_param_iterator_type);
    ret = PyModule_AddObject(module, "ConfigParamIterator", (PyObject *)py_config_param_iterator_type);
    if (ret != 0) return false;

    return true;

}



/* ---------------------------------------------------------------------------------- */
/*                         GESTION GENERIQUE DE CONFIGURATION                         */
/* ---------------------------------------------------------------------------------- */


/******************************************************************************
*                                                                             *
*  Paramètres  : type = type de l'objet à instancier.                         *
*                args = arguments fournis à l'appel.                          *
*                kwds = arguments de type key=val fournis.                    *
*                                                                             *
*  Description : Crée un nouvel objet Python de type 'GenConfig'.             *
*                                                                             *
*  Retour      : Instance Python mise en place.                               *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_generic_config_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    PyObject *result;                       /* Instance à retourner        */
    char *name;                             /* Nom du fichier à charger    */
    int ret;                                /* Bilan de lecture des args.  */
    GGenConfig *config;                     /* Version GLib du format      */

    ret = PyArg_ParseTuple(args, "s", &name);
    if (!ret) Py_RETURN_NONE;

    config = g_generic_config_new(name);

    result = pygobject_new(G_OBJECT(config));
    g_object_unref(config);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self = configuration à manipuler.                            *
*                args = non utilisé ici.                                      *
*                                                                             *
*  Description : Lit la configuration depuis un fichier.                      *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_generic_config_read(PyObject *self, PyObject *args)
{
    PyObject *result;                       /* Instance à retourner        */
    GGenConfig *config;                     /* Version GLib du format      */
    bool status;                            /* Bilan de l'opération        */

    config = G_GEN_CONFIG(pygobject_get(self));

    status = g_generic_config_read(config);

    result = status ? Py_True : Py_False;
    Py_INCREF(result);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self = configuration à manipuler.                            *
*                args = non utilisé ici.                                      *
*                                                                             *
*  Description : Ecrit la configuration dans un fichier.                      *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_generic_config_write(PyObject *self, PyObject *args)
{
    PyObject *result;                       /* Instance à retourner        */
    GGenConfig *config;                     /* Version GLib du format      */
    bool status;                            /* Bilan de l'opération        */

    config = G_GEN_CONFIG(pygobject_get(self));

    status = g_generic_config_write(config);

    result = status ? Py_True : Py_False;
    Py_INCREF(result);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self = configuration à manipuler.                            *
*                args = indication sur l'élément à retrouver.                 *
*                                                                             *
*  Description : Retrouve un élément de configuration par son chemin.         *
*                                                                             *
*  Retour      : Elément trouvé ou NULL en cas d'échec.                       *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_generic_config_search(PyObject *self, PyObject *args)
{
    PyObject *result;                       /* Instance à retourner        */
    GGenConfig *config;                     /* Version GLib du format      */
    char *path;                             /* Chemin d'accès du paramètre */
    int ret;                                /* Bilan de lecture des args.  */
    GCfgParam *param;                       /* Paramètre trouvé ou NULL    */

    config = G_GEN_CONFIG(pygobject_get(self));

    ret = PyArg_ParseTuple(args, "s", &path);
    if (!ret) Py_RETURN_NONE;

    param = g_generic_config_search(config, path);

    result = pygobject_new(G_OBJECT(param));
    Py_XINCREF(result);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self = configuration à manipuler.                            *
*                args = indication sur l'élément à retrouver.                 *
*                                                                             *
*  Description : Ajoute un paramètre à une configuration.                     *
*                                                                             *
*  Retour      : Elément ajouté ou NULL en cas d'échec.                       *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_generic_config_add(PyObject *self, PyObject *args)
{
    PyObject *result;                       /* Instance à retourner        */
    GGenConfig *config;                     /* Version GLib du format      */
    PyObject *param;                        /* Paramètre transmis          */
    int ret;                                /* Bilan de lecture des args.  */
    GCfgParam *added;                       /* Elément ajouté ou NULL      */

    config = G_GEN_CONFIG(pygobject_get(self));

    ret = PyArg_ParseTuple(args, "O", &param);
    if (!ret) Py_RETURN_NONE;

    ret = PyObject_IsInstance(param, (PyObject *)get_python_config_param_type());
    if (!ret) Py_RETURN_NONE;

    added = g_generic_config_add_param(config, G_CFG_PARAM(pygobject_get(param)));

    if (added != NULL)
    {
        result = pygobject_new(G_OBJECT(added));
        Py_XINCREF(result);
    }
    else
        result = NULL;

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self = configuration à manipuler.                            *
*                args = indication sur l'élément à retrouver.                 *
*                                                                             *
*  Description : Retire un paramètre d'une configuration.                     *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_generic_config_delete(PyObject *self, PyObject *args)
{
    GGenConfig *config;                     /* Version GLib du format      */
    char *path;                             /* Chemin d'accès du paramètre */
    int ret;                                /* Bilan de lecture des args.  */

    config = G_GEN_CONFIG(pygobject_get(self));

    ret = PyArg_ParseTuple(args, "s", &path);
    if (!ret) Py_RETURN_NONE;

    g_generic_config_delete_param(config, path);

    Py_RETURN_NONE;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self = configuration à manipuler.                            *
*                args = non utilisé ici.                                      *
*                                                                             *
*  Description : Renvoie la liste des paramètres de configuration.            *
*                                                                             *
*  Retour      : Itérateur pour la liste des paramètres.                      *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_generic_config_list_params(PyObject *self, PyObject *args)
{
    PyObject *result;                       /* Instance à retourner        */
    PyTypeObject *iterator_type;            /* Type Python de l'itérateur  */
    PyObject *args_list;                    /* Arguments de mise en place  */

    iterator_type = get_python_config_param_iterator_type();
    
    Py_INCREF(self);

    args_list = Py_BuildValue("(O)", self);
    result = PyObject_CallObject((PyObject *)iterator_type, args_list);

    Py_DECREF(args_list);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self    = NULL car méthode statique.                         *
*                closure = non utilisé ici.                                   *
*                                                                             *
*  Description : Fournit le chemin d'accès au binaire représenté.             *
*                                                                             *
*  Retour      : Chemin d'accès en Python.                                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_generic_config_get_filename(PyObject *self, void *closure)
{
    GGenConfig *config;                     /* Version GLib du format      */
    const char *filename;                   /* Chemin d'accès au fichier   */

    config = G_GEN_CONFIG(pygobject_get(self));

    filename = g_generic_config_get_filename(config);

    return PyUnicode_FromString(filename);

}


/******************************************************************************
*                                                                             *
*  Paramètres  : -                                                            *
*                                                                             *
*  Description : Fournit un accès à une définition de type à diffuser.        *
*                                                                             *
*  Retour      : Définition d'objet pour Python.                              *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

PyTypeObject *get_python_generic_config_type(void)
{
    static PyMethodDef py_generic_config_methods[] = {
        { "read", py_generic_config_read,
          METH_NOARGS,
          "Read the configuration from its relative XML file."
        },
        { "write", py_generic_config_write,
          METH_NOARGS,
          "Write the configuration to its relative XML file."
        },
        { "search", py_generic_config_search,
          METH_VARARGS,
          "Look for a given configuration parameter."
        },
        { "add", py_generic_config_add,
          METH_VARARGS,
          "Add an existing parameter to a configuration."
        },
        { "delete", py_generic_config_delete,
          METH_VARARGS,
          "Delete an existing parameter from a configuration."
        },
        { "params", py_generic_config_list_params,
          METH_NOARGS,
          "List all registered configuration parameters."
        },
        { NULL }
    };

    static PyGetSetDef py_generic_config_getseters[] = {
        {
            "filename", py_generic_config_get_filename, NULL,
            "Show the filename of the loaded binary file.", NULL
        },
        { NULL }
    };

    static PyTypeObject py_generic_config_type = {

        PyVarObject_HEAD_INIT(NULL, 0)

        .tp_name        = "pychrysalide.glibext.GenConfig",
        .tp_basicsize   = sizeof(PyGObject),

        .tp_flags       = Py_TPFLAGS_DEFAULT,

        .tp_doc         = "PyChrysalide generic configuration",

        .tp_methods     = py_generic_config_methods,
        .tp_getset      = py_generic_config_getseters,
        .tp_new         = (newfunc)py_generic_config_new

    };

    return &py_generic_config_type;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : module = module dont la définition est à compléter.          *
*                                                                             *
*  Description : Prend en charge l'objet 'pychrysalide.glibext.GenConfig'.    *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bool register_python_generic_config(PyObject *module)
{
    PyTypeObject *py_generic_config_type;   /* Type Python 'GenConfig'     */
    int ret;                                /* Bilan d'un appel            */
    PyObject *dict;                         /* Dictionnaire du module      */

    py_generic_config_type = get_python_generic_config_type();

    py_generic_config_type->tp_base = &PyGObject_Type;
    py_generic_config_type->tp_basicsize = py_generic_config_type->tp_base->tp_basicsize;

    if (PyType_Ready(py_generic_config_type) != 0)
        return false;

    Py_INCREF(py_generic_config_type);
    ret = PyModule_AddObject(module, "GenConfig", (PyObject *)py_generic_config_type);
    if (ret != 0) return false;

    dict = PyModule_GetDict(module);
    pygobject_register_class(dict, "GenConfig", G_TYPE_GEN_CONFIG, py_generic_config_type,
                             Py_BuildValue("(O)", py_generic_config_type->tp_base));

    return true;

}