/* Chrysalide - Outil d'analyse de fichiers binaires
 * quirks.c - transmission du type Python exact aux instances de PyObject
 *
 * Copyright (C) 2012-2013 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 "quirks.h"




#if 0

//#include <pyglib.h>
#include <pygobject.h>


#include "helpers.h"





/* Coordonnées insérées manuellement */
typedef struct _PyGObjectData_fake
{
    PyTypeObject *type;                     /* Type précis pour Python     */
    GSList *closures;                       /* Supports d'appel            */

} PyGObjectData_fake;


/* Clef d'accès réservée */
static GQuark pygobject_instance_data_key_fake = 0;

/* Clef pour l'enregistrement de l'objet Python dans l'objet GLib */
static GQuark pygobject_wrapper_key_fake = 0;




static void pygobject_data_free_fake(PyGObjectData_fake *data)
{
    //PyGILState_STATE state;                 /* Etat interne de Python      */
    GSList *iter;                           /* Boucle de parcours          */
    GSList *old;                            /* Sauvegarde avant libération */

    //state = pyglib_gil_state_ensure();

    Py_DECREF(data->type);

    pyg_begin_allow_threads;

    for (iter = data->closures; iter; )
    {
        /**
         * On obtient le lien avant la libération via
         * pygobject_unwatch_closure()...
         */
        old = iter;
        iter = iter->next;

        g_closure_invalidate((GClosure *)old->data);

    }

    pyg_end_allow_threads;

    g_free(data);

    //pyglib_gil_state_release(state);

}



static PyGObjectData_fake *pygobject_data_new_fake(void)
{
    PyGObjectData_fake *result;             /* Instance à retourner        */

    result = g_new0(PyGObjectData_fake, 1);

    return result;

}


static GObject *_ref = NULL;



/******************************************************************************
*                                                                             *
*  Paramètres  : -                                                            *
*                                                                             *
*  Description : Définit les éléments immuables pour toute association.       *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

void pychrysalide_init_quirks(void)
{
    pygobject_instance_data_key_fake = g_quark_from_static_string("PyGObject::instance-data");
    pygobject_wrapper_key_fake = g_quark_from_static_string("PyGObject::wrapper");

}


/******************************************************************************
*                                                                             *
*  Paramètres  : threshold0 = seuil pour la collecte de niveau 0.             *
*                threshold1 = seuil pour la collecte de niveau 1.             *
*                threshold2 = seuil pour la collecte de niveau 2.             *
*                                                                             *
*  Description : Modifie les seuils de collecte pour le collecteur de Python. *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

void pychrysalide_set_gc_threshold(int threshold0, int threshold1, int threshold2)
{
    PyObject *module;                       /* Module Python "gc"          */
    PyObject *args;                         /* Arguments pour l'appel      */
    PyObject *value;                        /* Valeurs obtenues            */

    module = PyImport_ImportModule("gc");

    if (threshold0 == 0 && threshold1 == 0 && threshold2 == 0)
    {
        args = Py_BuildValue("()");
        value = run_python_method(module, "disable", args);
    }
    else
    {
        args = Py_BuildValue("(iii)", threshold0, threshold1, threshold2);
        value = run_python_method(module, "set_threshold", args);
    }

    Py_DECREF(value);
    Py_DECREF(args);

    Py_DECREF(module);

}


/******************************************************************************
*                                                                             *
*  Paramètres  : obj  = instance GLib crée en C.                              *
*                type = type de l'objet Python correspond.                    *
*                                                                             *
*  Description : Crée l'association précise attendue par Python-GObject.      *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

void pychrysalide_set_instance_data(GObject *obj, PyTypeObject *type)
{
    PyGObjectData_fake *data;

    data = g_object_get_qdata(obj, pygobject_instance_data_key_fake);

    Py_INCREF(type);

    if (data == NULL)
    {
        data = pygobject_data_new_fake();

        /**
         * Dans la majorité des cas, le type est retrouvé depuis un appel à
         * PyObject_GetAttrString(), qui fournit une nouvelle référence.
         * Donc nul besoin d'incrémenter encore cette référence.
         */
        data->type = type;

        g_object_set_qdata_full(obj, pygobject_instance_data_key_fake,
                                data, (GDestroyNotify)pygobject_data_free_fake);

    }
    /**
     * On décharge l'usage du type : le compteur est déjà bien à jour si
     * le (futur) objet est en mémoire.
     */
    else Py_DECREF(type);

}


/******************************************************************************
*                                                                             *
*  Paramètres  : obj = instance existante GLib.                               *
*                                                                             *
*  Description : Fournit l'instance Python d'une instance GLib, si existante. *
*                                                                             *
*  Retour      : Instance Python mise en place ou NULL.                       *
*                                                                             *
*  Remarques   : Les retours non nuls voient leur compteur incrémenté.        *
*                                                                             *
******************************************************************************/

PyObject *pychrysalide_get_pygobject(GObject *obj)
{
    PyObject *result;                       /* Objet en place à renvoyer   */

    result = (PyObject *)g_object_get_qdata(obj, pygobject_wrapper_key_fake);

    if (result != NULL)
        Py_INCREF(result);

    return result;

}


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

int pychrysalide_allow_args_for_gobjects(PyObject *self, PyObject *args, PyObject *kwds)
{
    return 0;

}
#endif





/* Mémorisation de l'espace de référencement global */
static GObject *_ref = NULL;



/******************************************************************************
*                                                                             *
*  Paramètres  : ref = espace de référencement global à utiliser.             *
*                                                                             *
*  Description : Evite à Python d'avoir à manipuler les références internes.  *
*                                                                             *
*  Retour      : Adresse de l'espace de référencement global.                 *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

GObject *_get_internal_ref(GObject *ref)
{
    if (ref != NULL)
    {
        g_object_ref(ref);
        _ref = ref;
    }

    return _ref;

}