/* OpenIDA - Outil d'analyse de fichiers binaires
 * project.c - gestion du menu 'Projet'
 *
 * Copyright (C) 2012 Cyrille Bagard
 *
 *  This project is part of OpenIDA.
 *
 *  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 "project.h"


#include <i18n.h>
#include <libgen.h>
#include <malloc.h>
#include <string.h>


#include "../editem-int.h"
#include "../../analysis/binaries/file.h"
#include "../../gtkext/easygtk.h"



/* Affiche la boîte d'ajout d'un binaire au projet courant. */
static void mcb_project_add_binary_file(GtkMenuItem *, GMenuBar *);

/* Retire un binaire du projet indiqué. */
static void mcb_project_remove_binary(GtkMenuItem *, GStudyProject *);



/******************************************************************************
*                                                                             *
*  Paramètres  : ref      = espace de référencement global.                   *
*                accgroup = groupe d'accélérateurs pour les menus.            *
*                bar      = barre de menu parente.                            *
*                                                                             *
*  Description : Construit le menu "Projet".                                  *
*                                                                             *
*  Retour      : Panneau de menus mis en place.                               *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

GtkWidget *build_menu_project(GObject *ref, GtkAccelGroup *accgroup, GMenuBar *bar)
{
    GtkWidget *result;                      /* Support à retourner         */
    GtkWidget *menubar;                     /* Support pour éléments       */
    GtkWidget *submenuitem;                 /* Sous-élément de menu #1     */
    GtkWidget *deepmenubar;                 /* Support pour éléments #2    */
    GtkWidget *deepmenuitem;                /* Sous-élément de menu #2     */

    result = gtk_menu_item_new_with_mnemonic(_("_Project"));
    gtk_widget_show(result);

    menubar = gtk_menu_new();
    gtk_menu_item_set_submenu(GTK_MENU_ITEM(result), menubar);

    submenuitem = qck_create_menu_item(NULL, NULL, _("Add a binary..."), NULL, NULL);
    gtk_container_add(GTK_CONTAINER(menubar), submenuitem);

    deepmenubar = gtk_menu_new();
    gtk_menu_item_set_submenu(GTK_MENU_ITEM(submenuitem), deepmenubar);

    deepmenuitem = qck_create_menu_item(NULL, NULL, _("File"),
                                        G_CALLBACK(mcb_project_add_binary_file), bar);
    gtk_container_add(GTK_CONTAINER(deepmenubar), deepmenuitem);

    submenuitem = qck_create_menu_item(G_OBJECT(result), "menu_prj_remove_bin", _("Remove a binary"),
                                       NULL, NULL);
    gtk_container_add(GTK_CONTAINER(menubar), submenuitem);

    deepmenubar = gtk_menu_new();
    gtk_menu_item_set_submenu(GTK_MENU_ITEM(submenuitem), deepmenubar);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : widget = menu principal à actualiser.                        *
*                project = projet visé par la procédure.                      *
*                bar    = barre de menu parente.                              *
*                                                                             *
*  Description : Lance une actualisation relative à l'étendue du projet.      *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

void update_menu_project_for_project(GtkWidget *widget, GStudyProject *project, GMenuBar *bar)
{
    GtkWidget *menuitem;                    /* Menu principal à compléter  */
    GtkWidget *menubar;                     /* Support pour éléments       */
    GList *list;                            /* Liste des éléments en place */
    GList *iter;                            /* Boucle de parcours #1       */
    size_t count;                           /* Nombre de binaires attachés */
    GLoadedBinary **binaries;               /* Liste de ces binaires       */
    size_t i;                               /* Boucle de parcours #2       */
    const char *desc;                       /* Description à afficher      */
    GtkWidget *submenuitem;                 /* Sous-menu à ajouter         */

    menuitem = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "menu_prj_remove_bin"));
    menubar = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menuitem));

    /* Remise à zéro */

    list = gtk_container_get_children(GTK_CONTAINER(menubar));

    for (iter = list; iter != NULL; iter = g_list_next(iter))
        gtk_container_remove(GTK_CONTAINER(menubar), GTK_WIDGET(iter->data));

    g_list_free(list);

    /* Ajout des entrées */ 

    binaries = g_study_project_get_binaries(project, &count);

    for (i = 0; i < count; i++)
    {
        desc = g_loaded_binary_get_filename(binaries[i], true);

        submenuitem = qck_create_menu_item(NULL, NULL, desc,
                                           G_CALLBACK(mcb_project_remove_binary), project);
        g_object_set_data(G_OBJECT(submenuitem), "binary", binaries[i]);
        gtk_container_add(GTK_CONTAINER(menubar), submenuitem);

        g_object_unref(G_OBJECT(binaries[i]));

    }

    if (binaries != NULL)
        free(binaries);

    gtk_widget_set_sensitive(menuitem, count > 0);

}


/******************************************************************************
*                                                                             *
*  Paramètres  : menuitem = élément de menu sélectionné.                      *
*                bar      = barre de menu parente.                            *
*                                                                             *
*  Description : Affiche la boîte d'ajout d'un binaire au projet courant.     *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void mcb_project_add_binary_file(GtkMenuItem *menuitem, GMenuBar *bar)
{
    GtkWidget *dialog;                      /* Boîte à afficher            */
    char *dir;                              /* Répertoire courant          */
    gchar *filename;                        /* Nom du fichier à intégrer   */
    GLoadedBinary *binary;                  /* Représentation chargée      */

    dialog = gtk_file_chooser_dialog_new(_("Open a binary file"),
                                         GTK_WINDOW(G_EDITOR_ITEM(bar)->ref),
                                         GTK_FILE_CHOOSER_ACTION_OPEN,
                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                                         GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
                                         NULL);

    if (g_study_project_get_filename(get_current_project()) != NULL)
    {
        dir = strdup(g_study_project_get_filename(get_current_project()));
        dir = dirname(dir);
        gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), dir);
        free(dir);
    }

    if (g_study_project_get_filename(get_current_project()) != NULL)
    {
        dir = strdup(g_study_project_get_filename(get_current_project()));
        dir = dirname(dir);
        gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), dir);
        free(dir);
    }

    if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
    {
        filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));

        binary = g_file_binary_new_from_file(filename);

        if (binary != NULL)
        {
            g_signal_connect(binary, "disassembly-done",
                             G_CALLBACK(g_study_project_add_loaded_binary), get_current_project());
            g_loaded_binary_analyse(binary);
        }

        g_free(filename);

    }

    gtk_widget_destroy(dialog);

}


/******************************************************************************
*                                                                             *
*  Paramètres  : menuitem = élément de menu sélectionné.                      *
*                project  = projet d'appartenance du binaire à traiter.       *
*                                                                             *
*  Description : Retire un binaire du projet indiqué.                         *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void mcb_project_remove_binary(GtkMenuItem *menuitem, GStudyProject *project)
{
    GLoadedBinary *binary;                  /* Binaire à retirer           */

    binary = G_LOADED_BINARY(g_object_get_data(G_OBJECT(menuitem), "binary"));

    g_study_project_detach_binary(project, binary);
    g_object_unref(G_OBJECT(binary));

}