package fr.univ.dblp.analysis;

import fr.univ.dblp.export.DataExporter;
import fr.univ.dblp.export.ResultsPrinter;
import org.graphstream.algorithm.Toolkit;
import org.graphstream.graph.Graph;

/**
 * Analyse la distribution des degrés d'un réseau (Question 4).
 *
 * Cette classe calcule la distribution des degrés, l'exporte pour
 * visualisation avec gnuplot et la compare avec une distribution de Poisson
 * théorique pour identifier si le réseau suit une loi de puissance.
 *
 * @author Hamadou BA
 * @see <a href="https://www-apps.univ-lehavre.fr/forge/bh243413/tp2-ri-mesures-de-reseaux-interaction.git">Dépôt Git</a>
 */
public class DegreeAnalyzer {

    /**
     * Calcule la distribution des degrés du graphe.
     *
     * Retourne un tableau où l'indice représente le degré et la valeur
     * représente le nombre de nœuds ayant ce degré.
     *
     * @param g Le graphe à analyser
     * @return Tableau de la distribution des degrés
     */
    public static int[] getDegreeDistribution(Graph g) {
        return Toolkit.degreeDistribution(g);
    }

    /**
     * Normalise la distribution pour obtenir des probabilités.
     *
     * Chaque valeur est divisée par le nombre total de nœuds pour obtenir
     * la probabilité qu'un nœud ait un degré donné.
     *
     * @param dd Distribution des degrés (nombre de nœuds par degré)
     * @param nodeCount Nombre total de nœuds
     * @return Distribution normalisée (probabilités)
     */
    public static double[] normalizeDistribution(int[] dd, int nodeCount) {
        double[] normalized = new double[dd.length];
        for (int i = 0; i < dd.length; i++) {
            normalized[i] = (double) dd[i] / nodeCount;
        }
        return normalized;
    }

    /**
     * Exporte la distribution des degrés pour visualisation avec gnuplot.
     *
     * @param g Le graphe à analyser
     * @param outputFile Chemin du fichier de sortie
     */
    public static void exportForGnuplot(Graph g, String outputFile) {
        int[] dd = getDegreeDistribution(g);
        int nodeCount = g.getNodeCount();
        DataExporter.exportDegreeDistribution(dd, nodeCount, outputFile);
    }

    /**
     * Exporte la distribution avec comparaison à une distribution de Poisson.
     *
     * Permet de comparer la distribution réelle avec celle d'un réseau
     * aléatoire théorique (distribution de Poisson).
     *
     * @param g Le graphe à analyser
     * @param outputFile Chemin du fichier de sortie
     */
    public static void exportWithPoisson(Graph g, String outputFile) {
        int[] dd = getDegreeDistribution(g);
        int nodeCount = g.getNodeCount();
        double avgDegree = BasicMetrics.getAverageDegree(g);
        DataExporter.exportDegreeDistributionWithPoisson(dd, nodeCount, avgDegree, outputFile);
    }

    /**
     * Analyse la distribution des degrés et affiche les statistiques.
     *
     * @param g Le graphe à analyser
     * @param networkName Nom du réseau (pour l'affichage)
     */
    public static void analyzeDistribution(Graph g, String networkName) {
        ResultsPrinter.printSubHeader("Distribution des degrés - " + networkName);

        int[] dd = getDegreeDistribution(g);
        int nodeCount = g.getNodeCount();

        // Recherche du degré maximum
        int maxDegree = dd.length - 1;
        ResultsPrinter.printMetric("Degré maximum", maxDegree);

        // Comptage des nœuds avec degrés spécifiques
        int degreeZero = dd.length > 0 ? dd[0] : 0;
        ResultsPrinter.printMetric("Nœuds de degré 0", degreeZero);

        if (degreeZero > 0) {
            ResultsPrinter.printWarning(
                String.format("%d nœuds isolés détectés!", degreeZero));
        }
    }

    /**
     * Effectue l'analyse complète de la Question 4.
     *
     * Cette méthode analyse la distribution des degrés, exporte les données
     * pour gnuplot et fournit des indications pour l'interprétation.
     *
     * @param g Le graphe à analyser
     * @param networkName Nom du réseau (pour l'affichage)
     * @param baseFilename Nom de base pour les fichiers de sortie
     */
    public static void analyze(Graph g, String networkName, String baseFilename) {
        long startTime = System.currentTimeMillis();
        ResultsPrinter.printHeader("QUESTION 4: Distribution des degrés - " + networkName);

        analyzeDistribution(g, networkName);

        // Export pour gnuplot
        ResultsPrinter.printInfo("Export des données pour gnuplot...");

        String degreeFile = "output/data/" + baseFilename + "_degree_distribution.dat";
        String comparisonFile = "output/data/" + baseFilename + "_degree_comparison.dat";

        exportForGnuplot(g, degreeFile);
        exportWithPoisson(g, comparisonFile);

        ResultsPrinter.printInfo("Observations attendues en échelle log-log:");
        ResultsPrinter.printInfo("  - Ligne droite = loi de puissance p_k = C * k^(-γ)");
        ResultsPrinter.printInfo("  - Utilisez gnuplot pour tracer et ajuster la loi");

        ResultsPrinter.printElapsedTime(startTime);
    }
}
