/* Chrysalide - Outil d'analyse de fichiers binaires
 * editem.c - prototypes pour l'équivalent Python du fichier "gui/editem.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 "editem.h"


#include <pygobject.h>


#include <gui/editem-int.h>


#include "../helpers.h"
#include "../quirks.h"


#include "../analysis/binary.h"
#include "../gtkext/viewpanel.h"



/* Réagit à un changement du binaire courant. */
static void _update_editor_item_for_binary_python_wrapper(GEditorItem *, GLoadedBinary *);

/* Réagit à un changement de vue. */
static void _update_editor_item_for_view_python_wrapper(GEditorItem *, GtkViewPanel *);

/* Réagit à un changement de contenu. */
static void _update_editor_item_for_view_content_python_wrapper(GEditorItem *, GtkViewPanel *);

/* Réagit à un changement du binaire courant. */
static PyObject *py_editor_item_update_for_binary(PyObject *, PyObject *);

/* Réagit à un changement d'affichage principal de contenu. */
static PyObject *py_editor_item_update_for_view(PyObject *, PyObject *);

/* Réagit à un changement d'affichage principal de contenu. */
static PyObject *py_editor_item_update_for_content(PyObject *, PyObject *);

/* Fournit l'affichage de binaire courant. */
static PyObject *py_editor_item_get_current_view(PyObject *, PyObject *);

/* Procède à l'enregistrement d'un élément reactif de l'éditeur. */
static PyObject *py_editor_item_register(PyObject *, PyObject *);



/******************************************************************************
*                                                                             *
*  Paramètres  : item   = élément à actualiser.                               *
*                binary = nouvelle instance de binaire analysé.               *
*                                                                             *
*  Description : Réagit à un changement du binaire courant.                   *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void _update_editor_item_for_binary_python_wrapper(GEditorItem *item, GLoadedBinary *binary)
{
    PyObject *target;                       /* Version Python de l'élément */
    PyObject *args;                         /* Arguments pour l'appel      */
    PyObject *value;                        /* Retour obtenu               */

    /**
     * Normalement, l'objet Python est enregistré dans la liste de Chrysalide
     * des éléments d'éditeur, via py_editor_item_register(), donc son compteur
     * de références doit le maintenir en vie.
     *
     * On peut donc le récupérer directement depuis l'instance GLib, sans passer
     * par la procédure de pygobject, qui obligerait à connaître le type précis
     * de l'instance GLib manipulée.
     */
    target = pygobject_new(G_OBJECT(item));

    args = PyTuple_New(1);
    PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(binary)));

    value = run_python_method(target, "update_for_binary", args);

    Py_XDECREF(value);
    Py_DECREF(args);
    Py_DECREF(target);

}


/******************************************************************************
*                                                                             *
*  Paramètres  : item = élément à actualiser.                                 *
*                view = nouveau panneau d'affichage actif.                    *
*                                                                             *
*  Description : Réagit à un changement de vue.                               *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void _update_editor_item_for_view_python_wrapper(GEditorItem *item, GtkViewPanel *view)
{
    PyObject *target;                       /* Version Python de l'élément */
    PyObject *args;                         /* Arguments pour l'appel      */
    PyObject *value;                        /* Retour obtenu               */

    /**
     * Normalement, l'objet Python est enregistré dans la liste de Chrysalide
     * des éléments d'éditeur, via py_editor_item_register(), donc son compteur
     * de références doit le maintenir en vie.
     *
     * On peut donc le récupérer directement depuis l'instane GLib, sans passer
     * par la procédure de pygobject, qui obligerait à connaître le type précis
     * de l'instance GLib manipulée.
     */
    target = pygobject_new(G_OBJECT(item));

    args = PyTuple_New(1);
    PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(view)));

    value = run_python_method(target, "update_for_view", args);

    Py_XDECREF(value);
    Py_DECREF(args);
    Py_DECREF(target);

}


/******************************************************************************
*                                                                             *
*  Paramètres  : item = élément à actualiser.                                 *
*                view = nouveau panneau d'affichage actif.                    *
*                                                                             *
*  Description : Réagit à un changement de contenu.                           *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void _update_editor_item_for_view_content_python_wrapper(GEditorItem *item, GtkViewPanel *view)
{
    PyObject *target;                       /* Version Python de l'élément */
    PyObject *args;                         /* Arguments pour l'appel      */
    PyObject *value;                        /* Retour obtenu               */

    /**
     * Normalement, l'objet Python est enregistré dans la liste de Chrysalide
     * des éléments d'éditeur, via py_editor_item_register(), donc son compteur
     * de références doit le maintenir en vie.
     *
     * On peut donc le récupérer directement depuis l'instane GLib, sans passer
     * par la procédure de pygobject, qui obligerait à connaître le type précis
     * de l'instance GLib manipulée.
     */
    target = pygobject_new(G_OBJECT(item));

    args = PyTuple_New(1);
    PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(view)));

    value = run_python_method(target, "update_for_content", args);

    Py_XDECREF(value);
    Py_DECREF(args);
    Py_DECREF(target);

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self = classe représentant un binaire.                       *
*                args = arguments fournis à l'appel.                          *
*                                                                             *
*  Description : Réagit à un changement du binaire courant.                   *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_editor_item_update_for_binary(PyObject *self, PyObject *args)
{
    Py_RETURN_NONE;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self = classe représentant un binaire.                       *
*                args = arguments fournis à l'appel.                          *
*                                                                             *
*  Description : Réagit à un changement d'affichage principal de contenu.     *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_editor_item_update_for_view(PyObject *self, PyObject *args)
{
    Py_RETURN_NONE;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self = classe représentant un binaire.                       *
*                args = arguments fournis à l'appel.                          *
*                                                                             *
*  Description : Réagit à un changement d'affichage principal de contenu.     *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_editor_item_update_for_content(PyObject *self, PyObject *args)
{
    Py_RETURN_NONE;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self = classe représentant un binaire.                       *
*                args = arguments fournis à l'appel.                          *
*                                                                             *
*  Description : Fournit le gestionnaire du binaire courant.                  *
*                                                                             *
*  Retour      : Instance en place ou Py_None si aucune.                      *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_editor_item_get_current_binary(PyObject *self, PyObject *args)
{
    PyObject *result;                       /* Résultat à retourner        */
    GEditorItem *item;                      /* Elément à manipuler         */
    GLoadedBinary *binary;                  /* Instance à convertir        */

    item = G_EDITOR_ITEM(pygobject_get(self));
    binary = g_editor_item_get_current_binary(item);

    if (binary == NULL)
    {
        Py_INCREF(Py_None);
        result = Py_None;
    }
    else
        result = pygobject_new(G_OBJECT(binary));

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self = classe représentant un binaire.                       *
*                args = arguments fournis à l'appel.                          *
*                                                                             *
*  Description : Fournit l'affichage de binaire courant.                      *
*                                                                             *
*  Retour      : Instance en place ou Py_None si aucune.                      *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_editor_item_get_current_view(PyObject *self, PyObject *args)
{
    PyObject *result;                       /* Résultat à retourner        */
    GEditorItem *item;                      /* Elément à manipuler         */
    GtkViewPanel *panel;                    /* Instance à convertir        */

    item = G_EDITOR_ITEM(pygobject_get(self));
    panel = g_editor_item_get_current_view(item);

    if (panel == NULL)
    {
        Py_INCREF(Py_None);
        result = Py_None;
    }
    else
        result = pygobject_new(G_OBJECT(panel));

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : self = classe représentant un binaire.                       *
*                args = arguments fournis à l'appel.                          *
*                                                                             *
*  Description : Procède à l'enregistrement d'un élément reactif de l'éditeur.*
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static PyObject *py_editor_item_register(PyObject *self, PyObject *args)
{
    GEditorItem *item;                      /* Version GLib de l'élément   */

    item = G_EDITOR_ITEM(pygobject_get(self));

    //item->update_binary = _update_editor_item_for_binary_python_wrapper;
    //item->update_view = _update_editor_item_for_view_python_wrapper;
    //item->update_content = _update_editor_item_for_view_content_python_wrapper;

    Py_INCREF(self);
    register_editor_item(item);

    Py_RETURN_NONE;

}


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

PyTypeObject *get_python_editor_item_type(void)
{
    static PyMethodDef py_editor_item_methods[] = {
        {
            "update_for_binary", (PyCFunction)py_editor_item_update_for_binary,
            METH_VARARGS,
            "Called by Chrysalide on each binary change, if the item is registered."
        },
        {
            "update_for_view", (PyCFunction)py_editor_item_update_for_view,
            METH_VARARGS,
            "Called by Chrysalide on each view change, if the item is registered."
        },
        {
            "update_for_content", (PyCFunction)py_editor_item_update_for_content,
            METH_VARARGS,
            "Called by Chrysalide on each view content change, if the item is registered."
        },
        {
            "get_current_binary()", (PyCFunction)py_editor_item_get_current_binary,
            METH_NOARGS,
            "get_current_binary($self, /)\n--\n\nProvide the current binary."
        },
        {
            "get_current_view", (PyCFunction)py_editor_item_get_current_view,
            METH_NOARGS,
            "get_current_view($self, /)\n--\n\nProvide the current binary view."
        },
        {
            "register", (PyCFunction)py_editor_item_register,
            METH_NOARGS,
            "register($self, /)\n--\n\nRegister the item as editor item."
        },
        { NULL }
    };

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

    static PyTypeObject py_editor_item_type = {

        PyVarObject_HEAD_INIT(NULL, 0)

        .tp_name        = "pychrysalide.gui.EditorItem",

        .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,

        .tp_doc         = "PyChrysalide editor item",

        .tp_methods     = py_editor_item_methods,
        .tp_getset      = py_editor_item_getseters,

    };

    return &py_editor_item_type;

}


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

bool register_python_editor_item(PyObject *module)
{
    PyTypeObject *py_editor_item_type;      /* Type Python 'LoadedBinary'  */
    PyObject *dict;                         /* Dictionnaire du module      */

    py_editor_item_type = get_python_editor_item_type();

    dict = PyModule_GetDict(module);

    if (!register_class_for_pygobject(dict, G_TYPE_EDITOR_ITEM, py_editor_item_type, &PyGObject_Type))
        return false;

    return true;

}