package rh213424;

import org.graphstream.algorithm.Toolkit;
import org.graphstream.algorithm.generator.BarabasiAlbertGenerator;
import org.graphstream.algorithm.generator.Generator;
import org.graphstream.algorithm.generator.RandomGenerator;
import org.graphstream.graph.BreadthFirstIterator;
import org.graphstream.graph.Graph;
import org.graphstream.graph.Node;
import org.graphstream.graph.implementations.DefaultGraph;
import org.graphstream.graph.implementations.SingleGraph;
import org.graphstream.stream.file.FileSource;
import org.graphstream.stream.file.FileSourceEdge;
import org.graphstream.stream.file.FileSourceFactory;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;

import static org.graphstream.algorithm.Toolkit.*;

public class MesuresRI {
    /**
     * afficher les mesures d'un graphe
     * @param g
     */
    public static void afficherMesures(Graph g){

        System.out.println("Le nombre des noeuds du graphe "+g.getNodeCount());
        System.out.println("Le nombre des liens du graphe "+g.getEdgeCount());
        System.out.println("Le degré moyen est : "+averageDegree(g));
        System.out.println("Le coefficient de clustering est : "+averageClusteringCoefficient(g));
        System.out.println("Le réseau est il connexe ? "+isConnected(g));
    }

    /**
     * Générer un graphe avec la méthode d'attachement préférentiel (Barabasi-Albert)
     * @param nbNoeuds
     * @param degreeMoyen
     * @return
     */
    public static Graph genererBarabasi(int nbNoeuds, float degreeMoyen) {
        System.setProperty("org.graphstream.ui", "swing");
        SingleGraph graphBarabasi = new SingleGraph("graphe barabasi");
        Generator gen = new BarabasiAlbertGenerator((int) degreeMoyen);
        gen.addSink(graphBarabasi);
        gen.begin();
        for (int i = 0; i < nbNoeuds; i++){
            gen.nextEvents();
        }
        gen.end();

        return graphBarabasi;
    }

    /**
     * Générer un graphe aléatoire d'une taille et degre moyen donnée
     * @param nbNoeuds
     * @param degreeMoyen
     * @return
     */
    public static Graph genererGrapheAleatoire(int nbNoeuds, float degreeMoyen){
        Graph grapheAleatoire = new SingleGraph("Random");
        Generator gen = new RandomGenerator(6.62208890914917);
        gen.addSink(grapheAleatoire);
        gen.begin();
        for(int i=0; i<317080; i++)
            gen.nextEvents();
        gen.end();
        return grapheAleatoire;
    }
    public static void main(String ... args) throws IOException {
        String filePath = "./resources/com-dblp.ungraph.txt";
        Graph g = new DefaultGraph("g");
        FileSource fs = new FileSourceEdge();
        fs.addSink(g);
        System.setProperty("org.graphstream.ui", "swing");

        try {
            fs.readAll(filePath);
            //Affichage des données sur le réseau
            afficherMesures(g);
            System.out.println("La distribution des degrés ");
            int[] dd = Toolkit.degreeDistribution(g);
            StringBuilder r = new StringBuilder();
            for (int k = 0; k < dd.length; k++) {
                if (dd[k] != 0) {
                    System.out.printf(Locale.US, "%6d%20.8f%n", k, (double)dd[k] / g.getNodeCount());
                    r.append(k).append(" ").append((double) dd[k] / g.getNodeCount()).append(System.getProperty("line.separator"));
                }
            }
            //fichier de données de sitribution des degrés
            File distDegres = new File("./resources/distributionDegres.dat");
            if (!distDegres.exists()) {
                distDegres.createNewFile();
            }
            FileWriter fw = new FileWriter(distDegres.getAbsoluteFile());
            BufferedWriter bw = new BufferedWriter(fw);
            bw.write(r.toString());
            bw.close();
            /* ----------------------------------------Question 5 --------------------------------*/
            HashMap<Integer,Integer> distributionDistances = new HashMap<>();
            double sommeDistances = 0;
            int nbr=0;
            //parcours en largeur
            for(int i = 0 ; i < 1000 ; i++){
                Node depart = randomNode(g);
                BreadthFirstIterator it = new BreadthFirstIterator(depart);
                while(it.hasNext()){
                    Node next = it.next();
                    int dist = it.getDepthOf(next);
                    int occ = distributionDistances.get(dist)==null?0:distributionDistances.get(dist);
                    distributionDistances.put(dist,occ+1);
                    sommeDistances += it.getDepthOf(next);
                    nbr++;
                }
            }
            //fichier de distribution des distances
            File distDistances = new File("./resources/distributionDistances.dat");
            if (!distDegres.exists()) {
                distDistances.createNewFile();
            }
            FileWriter fw2 = new FileWriter(distDistances.getAbsoluteFile());
            BufferedWriter bw2 = new BufferedWriter(fw2);
            for (int dist: distributionDistances.keySet()){
                bw2.write(String.format(Locale.US, "%6d%20.8f%n", dist, (double)distributionDistances.get(dist) / nbr));
            }
            bw2.close();
            System.out.println("la distance moyenne est :"+(sommeDistances/nbr));
            /*---------------------------------------- Question 6---------------------------------------- */
            System.out.println("----------Graphe aléatoire--------------");
            Graph grapheAleatoire = genererGrapheAleatoire(317080, 6.62208890914917F);
            afficherMesures(grapheAleatoire);
            System.out.println("----------Graphe généré avec la méthode d'attachement préférentiel (Barabasi-Albert)--------------");
            Graph graphBarabasi = genererBarabasi(317080, 6.62208890914917F);
            afficherMesures(graphBarabasi);

        } catch (IOException e) {
            e.printStackTrace();
        }
        fs.removeSink(g);
    }
}
//gnuplot nonFichier.gnu