package mesures;

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.GraphParseException;
import org.graphstream.stream.file.FileSource;
import org.graphstream.stream.file.FileSourceEdge;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;
import java.util.function.Function;

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

public class DBLP {


    //retourner toutes le mesures d'un graphe
    private static void grapheMesures(Graph graph){
        System.out.println("Le nombre de noeud = : "+graph.getNodeCount());
        System.out.println("Le nombre de lien = : "+graph.getEdgeCount());
        System.out.println("Le Degré moyen = : "+averageDegree(graph));
        System.out.println("Le coefficient de clustering = : "+averageClusteringCoefficient(graph));

        if(isConnected(graph))
            System.out.println("Le graphe est connexe");
        else
            System.out.println("Le graphe est non connexe");

    }

    //retourner la distribution des distances
    public static HashMap<Integer, Double> getDistancesDistribution(Graph g, int nn) {
        List<Node> sample = Toolkit.randomNodeSet(g, nn);
        HashMap<Integer, Double> dist_distances = new HashMap<>();

        int i = 0;
        for (Node n : sample) {
            BreadthFirstIterator<Node> iter = (BreadthFirstIterator<Node>) n.getBreadthFirstIterator();

            while (iter.hasNext()) {
                int depth = iter.getDepthOf(iter.next());
                Double depthSum = dist_distances.get(depth);

                if (depthSum == null)
                    dist_distances.put(depth, 1.0);
                else
                    dist_distances.put(depth, depthSum + 1);
            }

            i++;
            System.out.format("\r%.1f%% complété", ((double) i) / 1000 * 100);
        }

        Double measuresCount = dist_distances.values().stream().reduce(0.0, Double::sum);
        dist_distances.forEach((k, v) -> dist_distances.put(k, v / measuresCount));

        return dist_distances;
    }

    //afficher la distribution des distances
    public static void printDistanceDistribution(Graph graph){
        HashMap<Integer, Double> pp= getDistancesDistribution(graph, 1000);
        for(Map.Entry<Integer, Double> entry : pp.entrySet()) {
            int key = entry.getKey();
            double value = entry.getValue();

            System.out.println(key+"    "+value);
        }
        System.out.println();
    }







    //generer un reseau aleatoire
    private static Graph generateAleatoireGraph(){
        Graph graph2 = new SingleGraph("Random");
        Generator gen = new RandomGenerator(6.990779876708984);
        gen.addSink(graph2);
        gen.begin();
        for(int i=0; i<99992; i++)
            gen.nextEvents();
        gen.end();

        return graph2;
    }

    //generer un reaseau avec la methode pre ...
    private static Graph generateMethodeGraph(){
        Graph graph1 = new SingleGraph("Barabàsi-Albert");
        Generator gen1 = new BarabasiAlbertGenerator(6);
        gen1.addSink(graph1);
        gen1.begin();

        for(int i=0; i<99998; i++) {
            gen1.nextEvents();
        }
        gen1.end();

        return graph1;
    }





    public static void main(String[] args) throws IOException, GraphParseException {
        System.setProperty("org.graphstream.ui", "swing");
        Graph graph = new DefaultGraph("RI");

        String filePath = "src/main/resources/ungraph.txt";
        FileSource fs = new FileSourceEdge();
        fs.addSink(graph);

        try {
            fs.readAll(filePath);

            Graph g=generateAleatoireGraph();
            printDistanceDistribution(g);

        } catch( IOException ignored) {

        } finally {
            fs.removeSink(graph);
        }


    }
}
