import org.graphstream.graph.Edge;
import org.graphstream.graph.Graph;
import org.graphstream.graph.Node;
import org.graphstream.graph.implementations.DefaultGraph;
import org.graphstream.stream.file.FileSource;
import org.graphstream.stream.file.FileSourceEdge;

import java.io.IOException;
import java.util.Arrays;


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

public class Propagation {

    public static void main(String[] args) throws IOException {
        Graph g = new DefaultGraph("g");
        FileSource fs = new FileSourceEdge();

        fs.addSink(g);

        try {
            fs.readAll("/home/bryan/IdeaProjects/TP2/src/fichier.txt");
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("Nombre de noeud : " + g.getNodeCount());
        System.out.println("Nombre de liens : " + g.getEdgeCount());
        System.out.println("Degres moyen : " + averageDegree(g));
        System.out.println("Coefficient de Clustering : " + averageClusteringCoefficient(g));

        double somme = 0.0;
        for (Node n : g){
            somme += Math.pow(n.getDegree(),2);
        }

        somme = somme/g.getNodeCount();
        double seuil = averageDegree(g)/somme;

        double b = 1.0/7.0;
        double u = 1.0/14.0;
        System.out.println("Taux de propagation de : "+b/u);
        System.out.println("Moyens des carré des degres : "+somme);
        System.out.println("Seuil de propagation dans un réseau sans échelle : "+seuil);
        System.out.println("Seuil de propagation dans un réseau aléatoire : "+ 1/(averageDegree(g)+1));

        //simulationOne(g);
        //simulationTwo(g);
        simulationThree(g);

    }

    public static void simulationOne(Graph g){
        Node s = g.getNode(0);
        s.addAttribute("infecte", true);
        int nbInfect = 1;
        for(int i = 0; i<84; i++){
            for (Node n : g){
                if(n.hasAttribute("infecte")){
                    for(Edge e : n){
                        nbInfect = estContamine(e.getOpposite(n), nbInfect);
                    }
                }
                nbInfect = estGuerrie(n, nbInfect);
            }
            //System.out.println("Jour "+ i + " nombre infecte : " + nbInfect );
            System.out.println(i +" "+ nbInfect);
        }
    }

    public static void simulationTwo(Graph g){
        int nbImmunise = 0;
        for(Node n : g) {
            if ((int)(Math.random() * 2 + 1) == 1) {
                n.addAttribute("immunise", true);
                nbImmunise += 1;
            }
        }
        Node s = g.getNode(0);
        s.addAttribute("infecte", true);
        int nbInfect = 1;
        for(int i = 0; i<84; i++){
            for (Node n : g){
                if(n.hasAttribute("infecte")){
                    for(Edge e : n){
                        nbInfect = estContamine(e.getOpposite(n), nbInfect);
                    }
                }
                nbInfect = estGuerrie(n, nbInfect);
            }
            //System.out.println("Jour "+ i + " nombre infecte : " + nbInfect + " Nombre d'immunise : " + nbImmunise );
            //System.out.println(i +" "+ nbInfect);

        }
        double moyenneDegre = 0.0;
        double moyenneCarreDegre;
        int somme=0;
        for(Node n : g) {
            if(!n.hasAttribute("immunise")) {
                moyenneDegre += n.getDegree();
                somme += Math.pow(n.getDegree(), 2);
            }
        }
        // Nombre de noeuds à prendre en compte dans le graphe modifié
        int nbNoeuds = g.getNodeCount() - nbImmunise;

        moyenneDegre /= nbNoeuds;
        moyenneCarreDegre = (double)(somme / nbNoeuds);


        System.out.println("Simulation 2 \n");
        System.out.println("Nombre de noeuds non immunisés : " + nbNoeuds);
        System.out.println("Moyenne des degrés du graphe modifié ( <k> ): " + moyenneDegre);
        System.out.println("Moyenne du carré des degrés du graphe modifié ( <k²> ): " + moyenneCarreDegre);
        System.out.println("Seuil épidémique du réseau modifié ( <k> / <k²> ) : " + (moyenneDegre / moyenneCarreDegre));
    }

    public static void simulationThree(Graph g){
        int nbImmunise = 0;
        for(Node n : g) {
            if ((int)(Math.random() * 2 + 1) == 1 && n.getEdgeSet().size() != 0) {
                int voisinAleat = (int)(Math.random() * n.getEdgeSet().size() - 1);
                n.getEdge(voisinAleat).getOpposite(n).addAttribute("immunise", true);
                nbImmunise += 1;
            }
        }
        Node s = g.getNode(0);
        s.addAttribute("infecte", true);
        int nbInfect = 1;
        for(int i = 0; i<84; i++){
            for (Node n : g){
                if(n.hasAttribute("infecte")){
                    for(Edge e : n){
                        nbInfect = estContamine(e.getOpposite(n), nbInfect);
                    }
                }
                nbInfect = estGuerrie(n, nbInfect);
            }
            //System.out.println("Jour "+ i + " nombre infecte : " + nbInfect + " Nombre d'immunise : " + nbImmunise  );
            System.out.println(i +" "+ nbInfect);
        }

        double moyenneDegre = 0.0;
        double moyenneCarreDegre;
        int somme=0;
        for(Node n : g) {
            if(!n.hasAttribute("immunise")) {
                moyenneDegre += n.getDegree();
                somme += Math.pow(n.getDegree(), 2);
            }
        }
        // Nombre de noeuds à prendre en compte dans le graphe modifié
        int nbNoeuds = g.getNodeCount() - nbImmunise;

        moyenneDegre /= nbNoeuds;
        moyenneCarreDegre = (double)(somme / nbNoeuds);


        System.out.println("Simulation 3 \n");
        System.out.println("Nombre de noeuds non immunisés : " + nbNoeuds);
        System.out.println("Moyenne des degrés du graphe modifié ( <k> ): " + moyenneDegre);
        System.out.println("Moyenne du carré des degrés du graphe modifié ( <k²> ): " + moyenneCarreDegre);
        System.out.println("Seuil épidémique du réseau modifié ( <k> / <k²> ) : " + (moyenneDegre / moyenneCarreDegre));
    }

    public static int estContamine(Node n, int nbInfect){
        double p = Math.random();
        if(p < 1.0/7.0 && !n.hasAttribute("immunise")){
            if(!n.hasAttribute("infecte")){
                n.addAttribute("infecte", true);
                nbInfect++;
            }
        }
        return nbInfect;
    }

    public static int estGuerrie(Node n, int nbInfect){
        double p = Math.random();
        if(p < 1.0/14.0){
            if(n.hasAttribute("infecte")){
                n.removeAttribute("infecte");
                nbInfect--;
            }
        }
        return nbInfect;
    }
}
