/* Chrysalide - Outil d'analyse de fichiers binaires
 * operand.c - équivalent Python du fichier "arch/operand.h"
 *
 * Copyright (C) 2018-2019 Cyrille Bagard
 *
 *  This file is part of Chrysalide.
 *
 *  Chrysalide 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.
 *
 *  Chrysalide 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 "operand.h"


#include <pygobject.h>


#include <i18n.h>
#include <arch/operand-int.h>
#include <glibext/strbuilder-int.h>


#include "../access.h"
#include "../helpers.h"
#include "../glibext/comparable.h"
#include "../glibext/hashable.h"
#include "../glibext/objhole.h"
#include "../glibext/serialize.h"
#include "../glibext/singleton.h"
#include "../glibext/strbuilder.h"



/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */


/* Initialise la classe générique des opérandes. */
static int py_arch_operand_init_gclass(GArchOperandClass *, PyTypeObject *);

CREATE_DYN_ABSTRACT_CONSTRUCTOR(arch_operand, G_TYPE_ARCH_OPERAND);

/* Initialise une instance sur la base du dérivé de GObject. */
static int py_arch_operand_init(PyObject *, PyObject *, PyObject *);

#if 0

/* Compare un opérande avec un autre. */
static int py_arch_operand___cmp___wrapper(const GArchOperand *, const GArchOperand *, bool);

/* Détermine le chemin conduisant à un opérande interne. */
static char *py_arch_operand_find_inner_operand_path_wrapper(const GArchOperand *, const GArchOperand *);

/* Obtient l'opérande correspondant à un chemin donné. */
static GArchOperand *py_arch_operand_get_inner_operand_from_path_wrapper(const GArchOperand *, const char *);

#endif



/* ------------------------ DEFINITION D'OPERANDE QUELCONQUE ------------------------ */


#if 0


/* Effectue une comparaison avec un objet Python 'ArchOperand'. */
static PyObject *py_arch_operand_richcompare(PyObject *, PyObject *, int);

/* Détermine le chemin conduisant à un opérande interne. */
static PyObject *py_arch_operand_find_inner_operand_path(PyObject *, PyObject *);

/* Obtient l'opérande correspondant à un chemin donné. */
static PyObject *py_arch_operand_get_inner_operand_from_path(PyObject *, PyObject *);

#endif


/* Ajoute une information complémentaire à un opérande. */
static PyObject *py_arch_operand_set_flag(PyObject *, PyObject *);

/* Retire une information complémentaire à un opérande. */
static PyObject *py_arch_operand_unset_flag(PyObject *, PyObject *);



/* ---------------------------------------------------------------------------------- */
/*                          GLUE POUR CREATION DEPUIS PYTHON                          */
/* ---------------------------------------------------------------------------------- */


/******************************************************************************
*                                                                             *
*  Paramètres  : gclass  = classe GLib à initialiser.                         *
*                pyclass = classe Python à initialiser.                       *
*                                                                             *
*  Description : Initialise la classe générique des opérandes.                *
*                                                                             *
*  Retour      : 0 pour indiquer un succès de l'opération.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static int py_arch_operand_init_gclass(GArchOperandClass *gclass, PyTypeObject *pyclass)
{

#if 0
    GStringBuilderInterface *iface;     /* Interface utilisée              */

    iface = g_type_interface_peek(gclass, G_TYPE_STRING_BUILDER);


    /*
    printf("???????? init Python Operand ??????????????  ->  class: %p '%s'  -  strbuilder iface: %p\n",
           gclass, g_type_name(G_TYPE_FROM_CLASS(gclass)), iface);
    */

#endif

#if 0

    class->compare = py_arch_operand___cmp___wrapper;
    class->find_inner = py_arch_operand_find_inner_operand_path_wrapper;
    class->get_inner = py_arch_operand_get_inner_operand_from_path_wrapper;


#endif



    //PY_CLASS_SET_WRAPPER(gclass->xxx, py_arch_operand_xxx_wrapper);

    return 0;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self = objet à initialiser (théoriquement).                  *
*                args = arguments fournis à l'appel.                          *
*                kwds = arguments de type key=val fournis.                    *
*                                                                             *
*  Description : Initialise une instance sur la base du dérivé de GObject.    *
*                                                                             *
*  Retour      : 0.                                                           *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static int py_arch_operand_init(PyObject *self, PyObject *args, PyObject *kwds)
{
    //unsigned int endianness;                /* Boutisme du processeur      */
    int ret;                                /* Bilan de lecture des args.  */
    //GArchProcessor *proc;                   /* Processeur à manipuler      */

#define ARCH_OPERAND_DOC                                                \
    "The ArchOperand object aims to get subclassed to create"           \
    " operands of any kind for new architectures.\n"                    \
    "\n"                                                                \
    "Calls to the *__init__* constructor of this abstract object expect"\
    " no particular argument.\n"                                        \
    "\n"                                                                \
    "The following methods have to be defined for new classes:\n"       \
    "* pychrysalide.arch.ArchRegister.__cmp__();\n"                     \
    "* pychrysalide.arch.ArchRegister._print();\n"                      \
    "* pychrysalide.arch.ArchRegister._build_tooltip().\n"              \
    "\n"                                                                \
    "Some extra method definitions are optional for new classes:\n"     \
    "* pychrysalide.arch.ArchRegister._find_inner_operand_path();\n"    \
    "* pychrysalide.arch.ArchRegister._get_inner_operand_from_path().\n"\
    "\n"                                                                \
    "Chrysalide creates an internal glue to provide rich comparisons"   \
    " for operands based on the old-style *__cmp__* function."

    /* Initialisation d'un objet GLib */

    ret = forward_pygobjet_init(self);
    if (ret == -1) return -1;

    /* Eléments de base */

    //proc = G_ARCH_PROCESSOR(pygobject_get(self));

    //proc->endianness = endianness;

    return 0;

}



#if 0

/******************************************************************************
*                                                                             *
*  Paramètres  : a    = premier opérande à consulter.                         *
*                b    = second opérande à consulter.                          *
*                lock = précise le besoin en verrouillage.                    *
*                                                                             *
*  Description : Compare un opérande avec un autre.                           *
*                                                                             *
*  Retour      : Bilan de la comparaison.                                     *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static int py_arch_operand___cmp___wrapper(const GArchOperand *a, const GArchOperand *b, bool lock)
{
    int result;                             /* Empreinte à retourner       */
    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
    PyObject *pyobj;                        /* Objet Python concerné       */
    PyObject *args;                         /* Arguments pour l'appel      */
    PyObject *pyret;                        /* Bilan de consultation       */

#define ARCH_OPERAND_CMP_WRAPPER PYTHON_WRAPPER_DEF             \
(                                                               \
    __cmp__, "$self, other, /",                                 \
    METH_VARARGS,                                               \
    "Abstract method used to compare the operand with another"  \
    " one. This second object is always an"                     \
    " pychrysalide.arch.ArchOperand instance.\n"                \
    "\n"                                                        \
    " This is the Python old-style comparison method, but"      \
    " Chrysalide provides a glue to automatically build a rich" \
    " version of this function."                                \
)

    result = 0;

    gstate = PyGILState_Ensure();

    pyobj = pygobject_new(G_OBJECT(a));

    if (has_python_method(pyobj, "__cmp__"))
    {
        args = PyTuple_New(1);
        PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(b)));

        pyret = run_python_method(pyobj, "__cmp__", args);

        if (pyret != NULL)
        {
            if (PyLong_Check(pyret))
                result = PyLong_AsLong(pyret);
        }

        Py_XDECREF(pyret);

        Py_DECREF(args);

    }

    Py_DECREF(pyobj);

    PyGILState_Release(gstate);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : operand = opérande à consulter.                              *
*                target  = instruction à venir retrouver.                     *
*                                                                             *
*  Description : Détermine le chemin conduisant à un opérande interne.        *
*                                                                             *
*  Retour      : Chemin d'accès à l'opérande ou NULL en cas d'absence.        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static char *py_arch_operand_find_inner_operand_path_wrapper(const GArchOperand *operand, const GArchOperand *target)
{
    char *result;                           /* Chemin à retourner          */
    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
    PyObject *pyobj;                        /* Objet Python concerné       */
    PyObject *args;                         /* Arguments pour l'appel      */
    PyObject *pyret;                        /* Bilan de consultation       */

#define ARCH_OPERAND_FIND_INNER_OPERAND_PATH_WRAPPER PYTHON_WRAPPER_DEF     \
(                                                                           \
    _find_inner_operand_path, "$self, target, /",                           \
    METH_VARARGS,                                                           \
    "Abstract method used to compute the path leading to an inner"          \
    " operand.\n"                                                           \
    "\n"                                                                    \
    "The *target* has to be an instance of pychrysalide.arch.ArchOperand"   \
    " included in the operand.\n"                                           \
    "\n"                                                                    \
    "The result is a string of the form 'n[:n:n:n]', where n is an"         \
    " internal index, or None if the *target* is not found. This kind of"   \
    " path is aimed to be built for the"                                    \
    " pychrysalide.arch.ArchInstruction.find_operand_path() function."      \
)

    result = NULL;

    gstate = PyGILState_Ensure();

    pyobj = pygobject_new(G_OBJECT(operand));

    if (has_python_method(pyobj, "_find_inner_operand_path"))
    {
        args = PyTuple_New(1);
        PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(target)));

        pyret = run_python_method(pyobj, "_find_inner_operand_path", args);

        if (pyret != NULL)
        {
            if (PyUnicode_Check(pyret))
                result = strdup(PyUnicode_AsUTF8(pyret));
        }

        Py_XDECREF(pyret);

        Py_DECREF(args);

    }

    Py_DECREF(pyobj);

    PyGILState_Release(gstate);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : operand = opérande à consulter.                              *
*                path  = chemin d'accès à un opérande à retrouver.            *
*                                                                             *
*  Description : Obtient l'opérande correspondant à un chemin donné.          *
*                                                                             *
*  Retour      : Opérande trouvé ou NULL en cas d'échec.                      *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static GArchOperand *py_arch_operand_get_inner_operand_from_path_wrapper(const GArchOperand *operand, const char *path)
{
    GArchOperand *result;                   /* Opérande trouvée à renvoyer */
    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
    PyObject *pyobj;                        /* Objet Python concerné       */
    PyObject *args;                         /* Arguments pour l'appel      */
    PyObject *pyret;                        /* Bilan de consultation       */

#define ARCH_OPERAND_GET_INNER_OPERAND_FROM_PATH_WRAPPER PYTHON_WRAPPER_DEF \
(                                                                           \
    _get_inner_operand_from_path, "$self, path, /",                         \
    METH_VARARGS,                                                           \
    "Abstract method used to retrieve an inner operand by its path.\n"      \
    "\n"                                                                    \
    "This *path* is a string of the form 'n[:n:n:n]', where n is an"        \
    " internal index. Such a path is usually built by the"                  \
    " pychrysalide.arch.ArchInstruction.find_operand_path() function.\n"    \
    "\n"                                                                    \
    "The result is an pychrysalide.arch.ArchOperand instance, or"           \
    " None if no operand was found."                                        \
)

    result = NULL;

    gstate = PyGILState_Ensure();

    pyobj = pygobject_new(G_OBJECT(operand));

    if (has_python_method(pyobj, "_get_inner_operand_from_path"))
    {
        args = PyTuple_New(1);
        PyTuple_SetItem(args, 0, PyUnicode_FromString(path));

        pyret = run_python_method(pyobj, "_get_inner_operand_from_path", args);

        if (pyret != NULL)
        {
            if (PyObject_TypeCheck(pyret, get_python_arch_operand_type()))
            {
                result = G_ARCH_OPERAND(pygobject_get(pyret));
                g_object_ref(G_OBJECT(result));
            }

        }

        Py_XDECREF(pyret);

        Py_DECREF(args);

    }

    Py_DECREF(pyobj);

    PyGILState_Release(gstate);

    return result;

}



#endif



/* ---------------------------------------------------------------------------------- */
/*                          DEFINITION D'OPERANDE QUELCONQUE                          */
/* ---------------------------------------------------------------------------------- */



#if 0

/******************************************************************************
*                                                                             *
*  Paramètres  : a  = premier object Python à consulter.                      *
*                b  = second object Python à consulter.                       *
*                op = type de comparaison menée.                              *
*                                                                             *
*  Description : Effectue une comparaison avec un objet Python 'ArchOperand'. *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_arch_operand_richcompare(PyObject *a, PyObject *b, int op)
{
    PyObject *result;                       /* Bilan à retourner           */
    int ret;                                /* Bilan de lecture des args.  */
    const GArchOperand *reg_a;              /* Premier élément à traiter   */
    const GArchOperand *reg_b;              /* Second élément à traiter    */
    int status;                             /* Résultat d'une comparaison  */

    ret = PyObject_IsInstance(b, (PyObject *)get_python_arch_operand_type());
    if (!ret)
    {
        result = Py_NotImplemented;
        goto cmp_done;
    }

    reg_a = G_ARCH_OPERAND(pygobject_get(a));
    reg_b = G_ARCH_OPERAND(pygobject_get(b));

    status = py_arch_operand___cmp___wrapper(reg_a, reg_b, true);

    result = status_to_rich_cmp_state(status, op);

 cmp_done:

    Py_INCREF(result);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self = architecture concernée par la procédure.              *
*                args = instruction représentant le point de départ.          *
*                                                                             *
*  Description : Détermine le chemin conduisant à un opérande interne.        *
*                                                                             *
*  Retour      : Chemin d'accès à l'opérande ou None en cas d'absence.        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_arch_operand_find_inner_operand_path(PyObject *self, PyObject *args)
{
    PyObject *result;                       /* Chemin à retourner          */
    GArchOperand *target;                   /* Opérande ciblé par l'action */
    int ret;                                /* Bilan de lecture des args.  */
    GArchOperand *operand;                  /* Opérande manipulé           */
    char *path;                             /* Chemin déterminé            */

#define ARCH_OPERAND_FIND_INNER_OPERAND_PATH_METHOD PYTHON_METHOD_DEF       \
(                                                                           \
    find_inner_operand_path, "$self, target, /",                            \
    METH_VARARGS, py_arch_operand,                                          \
    "Compute the path leading to an inner operand.\n"                       \
    "\n"                                                                    \
    "The *target* has to be an instance of pychrysalide.arch.ArchOperand"   \
    " included in the operand.\n"                                           \
    "\n"                                                                    \
    "The result is a string of the form 'n[:n:n:n]', where n is an"         \
    " internal index, or None if the *target* is not found. This kind of"   \
    " path is aimed to be built for the"                                    \
    " pychrysalide.arch.ArchInstruction.find_operand_path() function."      \
)

    ret = PyArg_ParseTuple(args, "O&", convert_to_arch_operand, &target);
    if (!ret) return NULL;

    operand = G_ARCH_OPERAND(pygobject_get(self));

    path = g_arch_operand_find_inner_operand_path(operand, target);

    if (path != NULL)
    {
        result = PyUnicode_FromString(path);
        free(path);
    }
    else
    {
        result = Py_None;
        Py_INCREF(result);
    }

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self = architecture concernée par la procédure.              *
*                args = instruction représentant le point de départ.          *
*                                                                             *
*  Description : Obtient l'opérande correspondant à un chemin donné.          *
*                                                                             *
*  Retour      : Opérande trouvé ou None en cas d'échec.                      *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_arch_operand_get_inner_operand_from_path(PyObject *self, PyObject *args)
{
    PyObject *result;                       /* Trouvaille à retourner      */
    const char *path;                       /* Chemin à parcourir          */
    int ret;                                /* Bilan de lecture des args.  */
    GArchOperand *operand;                  /* Opérande manipulé           */
    GArchOperand *op;                       /* Opérande retrouvé           */

#define ARCH_OPERAND_GET_INNER_OPERAND_FROM_PATH_METHOD PYTHON_METHOD_DEF   \
(                                                                           \
    get_inner_operand_from_path, "$self, path, /",                          \
    METH_VARARGS, py_arch_operand,                                          \
    "Retrieve an inner operand by its path.\n"                              \
    "\n"                                                                    \
    "This *path* is a string of the form 'n[:n:n:n]', where n is an"        \
    " internal index. Such a path is usually built by the"                  \
    " pychrysalide.arch.ArchInstruction.find_operand_path() function.\n"    \
    "\n"                                                                    \
    "The result is an pychrysalide.arch.ArchOperand instance, or"           \
    " None if no operand was found."                                        \
)

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

    operand = G_ARCH_OPERAND(pygobject_get(self));

    op = g_arch_operand_get_inner_operand_from_path(operand, path);

    if (op != NULL)
    {
        result = pygobject_new(G_OBJECT(op));
        g_object_unref(G_OBJECT(op));
    }
    else
    {
        result = Py_None;
        Py_INCREF(result);
    }

    return result;

}

#endif











/******************************************************************************
*                                                                             *
*  Paramètres  : self = architecture concernée par la procédure.              *
*                args = instruction représentant le point de départ.          *
*                                                                             *
*  Description : Ajoute une information complémentaire à un opérande.         *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_arch_operand_set_flag(PyObject *self, PyObject *args)
{
    PyObject *result;                       /* Bilan à retourner           */
    unsigned int flag;                      /* Fanion(s) à appliquer       */
    int ret;                                /* Bilan de lecture des args.  */
    GArchOperand *operand;                  /* Opérande manipulé           */
    bool status;                            /* Bilan à transmettre         */

#define ARCH_OPERAND_SET_FLAG_METHOD PYTHON_METHOD_DEF      \
(                                                           \
    set_flag, "$self, flag, /",                             \
    METH_VARARGS, py_arch_operand,                          \
    "Add some flags to the operand.\n"                      \
    "\n"                                                    \
    "This *flag* argument is an integer value containing"   \
    " bits to apply to the operand state.\n"                \
    "\n"                                                    \
    "The result is an boolean status: *True* for operation" \
    " success, *False* otherwise."                          \
)

    ret = PyArg_ParseTuple(args, "I", &flag);
    if (!ret) return NULL;

    operand = G_ARCH_OPERAND(pygobject_get(self));

    status = g_arch_operand_set_flag(operand, flag);

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

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self = architecture concernée par la procédure.              *
*                args = instruction représentant le point de départ.          *
*                                                                             *
*  Description : Retire une information complémentaire à un opérande.         *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_arch_operand_unset_flag(PyObject *self, PyObject *args)
{
    PyObject *result;                       /* Bilan à retourner           */
    unsigned int flag;                      /* Fanion(s) à appliquer       */
    int ret;                                /* Bilan de lecture des args.  */
    GArchOperand *operand;                  /* Opérande manipulé           */
    bool status;                            /* Bilan à transmettre         */

#define ARCH_OPERAND_UNSET_FLAG_METHOD PYTHON_METHOD_DEF    \
(                                                           \
    unset_flag, "$self, flag, /",                           \
    METH_VARARGS, py_arch_operand,                          \
    "Remove some flags from the operand.\n"                 \
    "\n"                                                    \
    "This *flag* argument is an integer value containing"   \
    " bits to delete from the operand state.\n"             \
    "\n"                                                    \
    "The result is an boolean status: *True* for operation" \
    " success, *False* otherwise."                          \
)

    ret = PyArg_ParseTuple(args, "I", &flag);
    if (!ret) return NULL;

    operand = G_ARCH_OPERAND(pygobject_get(self));

    status = g_arch_operand_unset_flag(operand, flag);

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

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self = architecture concernée par la procédure.              *
*                args = instruction représentant le point de départ.          *
*                                                                             *
*  Description : Détermine si un opérande possède un fanion particulier.      *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_arch_operand_has_flag(PyObject *self, PyObject *args)
{
    PyObject *result;                       /* Bilan à retourner           */
    unsigned int flag;                      /* Fanion(s) à appliquer       */
    int ret;                                /* Bilan de lecture des args.  */
    GArchOperand *operand;                  /* Opérande manipulé           */
    bool status;                            /* Bilan à transmettre         */

#define ARCH_OPERAND_HAS_FLAG_METHOD PYTHON_METHOD_DEF      \
(                                                           \
    has_flag, "$self, flag, /",                             \
    METH_VARARGS, py_arch_operand,                          \
    "Tell if some flags are set for the operand.\n"         \
    "\n"                                                    \
    "This *flag* argument is an integer value containing"   \
    " bits to test for the operand state.\n"                \
    "\n"                                                    \
    "The result is an boolean status: *True* if the bits"   \
    " are active, *False* otherwise."                       \
)

    ret = PyArg_ParseTuple(args, "I", &flag);
    if (!ret) return NULL;

    operand = G_ARCH_OPERAND(pygobject_get(self));

    status = g_arch_operand_has_flag(operand, flag);

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

    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_arch_operand_type(void)
{
    static PyMethodDef py_arch_operand_methods[] = {
        ARCH_OPERAND_SET_FLAG_METHOD,
        ARCH_OPERAND_UNSET_FLAG_METHOD,
        ARCH_OPERAND_HAS_FLAG_METHOD,

        /*
        ARCH_OPERAND_CMP_WRAPPER,
        ARCH_OPERAND_FIND_INNER_OPERAND_PATH_WRAPPER,
        ARCH_OPERAND_GET_INNER_OPERAND_FROM_PATH_WRAPPER,
        ARCH_OPERAND_PRINT_WRAPPER,
#ifdef INCLUDE_GTK_SUPPORT
        ARCH_OPERAND_BUILD_TOOLTIP_WRAPPER,
#endif
        ARCH_OPERAND_FIND_INNER_OPERAND_PATH_METHOD,
        ARCH_OPERAND_GET_INNER_OPERAND_FROM_PATH_METHOD,
        */
        { NULL }
    };

    static PyGetSetDef py_arch_operand_getseters[] = {
        { NULL }
    };

    static PyTypeObject py_arch_operand_type = {

        PyVarObject_HEAD_INIT(NULL, 0)

        .tp_name        = "pychrysalide.arch.ArchOperand",
        .tp_basicsize   = sizeof(PyGObject),

        .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_BASETYPE,

        .tp_doc         = ARCH_OPERAND_DOC,

        //.tp_richcompare = py_arch_operand_richcompare,

        .tp_methods     = py_arch_operand_methods,
        .tp_getset      = py_arch_operand_getseters,

        .tp_init        = py_arch_operand_init,
        .tp_new         = py_arch_operand_new,

    };

    return &py_arch_operand_type;

}


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

bool ensure_python_arch_operand_is_registered(void)
{
    PyTypeObject *type;                     /* Type Python 'ArchOperand'   */
    PyObject *module;                       /* Module à recompléter        */
    PyObject *dict;                         /* Dictionnaire du module      */

    type = get_python_arch_operand_type();

    if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
    {
        module = get_access_to_python_module("pychrysalide.arch");

        dict = PyModule_GetDict(module);

        if (!ensure_python_thick_object_is_registered())
            return false;

        if (!ensure_python_comparable_object_is_registered())
            return false;

        if (!ensure_python_hashable_object_is_registered())
            return false;

        if (!ensure_python_serializable_object_is_registered())
            return false;

        if (!ensure_python_singleton_candidate_is_registered())
            return false;

        if (!ensure_python_string_builder_is_registered())
            return false;

        pyg_register_class_init(G_TYPE_ARCH_OPERAND, (PyGClassInitFunc)py_arch_operand_init_gclass);

        if (!register_class_for_pygobject(dict, G_TYPE_ARCH_OPERAND, type))
            return false;

    }

    return true;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : arg = argument quelconque à tenter de convertir.             *
*                dst = destination des valeurs récupérées en cas de succès.   *
*                                                                             *
*  Description : Tente de convertir en opérande d'architecture.               *
*                                                                             *
*  Retour      : Bilan de l'opération, voire indications supplémentaires.     *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

int convert_to_arch_operand(PyObject *arg, void *dst)
{
    int result;                             /* Bilan à retourner           */

    result = PyObject_IsInstance(arg, (PyObject *)get_python_arch_operand_type());

    switch (result)
    {
        case -1:
            /* L'exception est déjà fixée par Python */
            result = 0;
            break;

        case 0:
            PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to arch operand");
            break;

        case 1:
            *((GArchOperand **)dst) = G_ARCH_OPERAND(pygobject_get(arg));
            break;

        default:
            assert(false);
            break;

    }

    return result;

}