/* OpenIDA - Outil d'analyse de fichiers binaires
 * ranks.c - calcul de l'ordonnée des différents classements
 *
 * Copyright (C) 2013 Cyrille Bagard
 *
 *  This file 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 Foobar.  If not, see .
 */
#include "ranks.h"
#include 
#include 
#include "params.h"
/* Information relatives à un rang de classement */
typedef struct _rank_props
{
    gint top_margin;                        /* Espace supérieur pour liens */
    gint height;                            /* Hauteur minimale            */
    gint final_y;                           /* Ordonnée finale             */
} rank_props;
/* Calcul de l'ordonnée des différents classements (instance) */
struct _GGraphRanks
{
    GObject parent;                         /* A laisser en premier        */
    rank_props *props;                      /* Propriétés des rangs        */
    unsigned int count;                     /* Nombre de rangs présents    */
};
/* Calcul de l'ordonnée des différents classements (classe) */
struct _GGraphRanksClass
{
    GObjectClass parent;                    /* A laisser en premier        */
};
/* Initialise la classe de calcul de l'ordonnée des classements. */
static void g_graph_ranks_class_init(GGraphRanksClass *);
/* Initialise un calcul de l'ordonnée des classements. */
static void g_graph_ranks_init(GGraphRanks *);
/* Supprime toutes les références externes. */
static void g_graph_ranks_dispose(GGraphRanks *);
/* Procède à la libération totale de la mémoire. */
static void g_graph_ranks_finalize(GGraphRanks *);
/* Indique le type définit par la GLib pour le calcul de l'ordonnée des classements. */
G_DEFINE_TYPE(GGraphRanks, g_graph_ranks, G_TYPE_OBJECT);
/******************************************************************************
*                                                                             *
*  Paramètres  : klass = classe à initialiser.                                *
*                                                                             *
*  Description : Initialise la classe de calcul de l'ordonnée des classements.*
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static void g_graph_ranks_class_init(GGraphRanksClass *klass)
{
    GObjectClass *object;                   /* Autre version de la classe  */
    object = G_OBJECT_CLASS(klass);
    object->dispose = (GObjectFinalizeFunc/* ! */)g_graph_ranks_dispose;
    object->finalize = (GObjectFinalizeFunc)g_graph_ranks_finalize;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : ranks = instance à initialiser.                              *
*                                                                             *
*  Description : Initialise un calcul de l'ordonnée des classements.          *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static void g_graph_ranks_init(GGraphRanks *ranks)
{
}
/******************************************************************************
*                                                                             *
*  Paramètres  : node = instance d'objet GLib à traiter.                      *
*                                                                             *
*  Description : Supprime toutes les références externes.                     *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static void g_graph_ranks_dispose(GGraphRanks *ranks)
{
    G_OBJECT_CLASS(g_graph_ranks_parent_class)->dispose(G_OBJECT(ranks));
}
/******************************************************************************
*                                                                             *
*  Paramètres  : ranks = instance d'objet GLib à traiter.                     *
*                                                                             *
*  Description : Procède à la libération totale de la mémoire.                *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static void g_graph_ranks_finalize(GGraphRanks *ranks)
{
    if (ranks->props != NULL)
        free(ranks->props);
    G_OBJECT_CLASS(g_graph_ranks_parent_class)->finalize(G_OBJECT(ranks));
}
/******************************************************************************
*                                                                             *
*  Paramètres  : count = nombre de rangs dans le classement au total.         *
*                                                                             *
*  Description : Prépare de quoi se définir au mieux les ordonnées des noeuds.*
*                                                                             *
*  Retour      : Adresse de la structure mise en place.                       *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
GGraphRanks *g_graph_ranks_new(unsigned int count)
{
    GGraphRanks *result;                    /* Structure à retourner       */
    size_t i;                               /* Boucle de parcours          */
    result = g_object_new(G_TYPE_GRAPH_RANKS, NULL);
    result->count = count;
    result->props = (rank_props *)calloc(count, sizeof(rank_props));
    for (i = 0; i < count; i++)
        if (i == 0)
            result->props[i].top_margin = GRAPH_TOP_MARGIN;
        else
            result->props[i].top_margin = NODE_TOP_MARGIN;
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : ranks  = ensemble des rangs de classement à manipuler.       *
*                index  = indice du rang visé.                                *
*                height = hauteur minimale requise pour le rang donné.        *
*                                                                             *
*  Description : Note une hauteur minimale requise pour un rang du classement.*
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
void g_graph_ranks_set_min_height(GGraphRanks *ranks, unsigned int index, gint height)
{
    /*BUG_ON(index >= ranks->count) */
    ranks->props[index].height = MAX(ranks->props[index].height, height);
}
/******************************************************************************
*                                                                             *
*  Paramètres  : ranks = ensemble des rangs de classement à manipuler.        *
*                                                                             *
*  Description : Calcule l'ordonnée finale de chaque rang du classement.      *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
void g_graph_ranks_compute_y_line(GGraphRanks *ranks)
{
    size_t i;                               /* Boucle de parcours          */
    for (i = 0; i < ranks->count; i++)
    {
        ranks->props[i].final_y = ranks->props[i].top_margin;
        if (i > 0)
            ranks->props[i].final_y += ranks->props[i - 1].final_y + ranks->props[i - 1].height;
    }
}
/******************************************************************************
*                                                                             *
*  Paramètres  : ranks  = ensemble des rangs de classement à consulter.       *
*                index  = indice du rang visé.                                *
*                                                                             *
*  Description : Fournit la position verticale correspondant à un rang donné. *
*                                                                             *
*  Retour      : Ordonnée à utiliser.                                         *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
gint g_graph_ranks_get_y_for_rank(const GGraphRanks *ranks, unsigned int index)
{
    /*BUG_ON(index >= ranks->count) */
    return ranks->props[index].final_y;
}