import org.graphstream.algorithm.generator.Generator;
import org.graphstream.algorithm.generator.RandomGenerator;
import org.graphstream.graph.Edge;
import org.graphstream.graph.Graph;
import org.graphstream.graph.Node;
import org.graphstream.graph.implementations.SingleGraph;

import java.util.ArrayList;
import java.util.List;

public class SimulationPropagationReseauAleatoire {
    public static void main(String[] args) {
        Graph graph = new SingleGraph("Random");
        Generator gen = new RandomGenerator(3);
        gen.addSink(graph);
        gen.begin();
        for(int i=0; i<100; i++)
            gen.nextEvents();
        gen.end();

        System.out.println("Première simulation pour un noeud aléatoire sur un réseau aléatoire\n");
        SimulationPropagationReseauPreferentiel.simulation1(graph);
        System.out.println();
        System.out.println("Deuxième simulation pour un noeud aléatoire sur un réseau aléatoire\n");
        SimulationPropagationReseauPreferentiel.simulation2(graph);
        System.out.println();
        System.out.println("Troisième simulation pour un noeud aléatoire sur un réseau aléatoire\n");
        SimulationPropagationReseauPreferentiel.simulation2(graph);

    }

    public static void simulation1(Graph g){
        List<Node> lstNodeInfect = new ArrayList<>();
        for(Node n : g){
            n.addAttribute("etat","susceptible");
        }
        int nbInfect = SimulationPropagationReseauAleatoire.nbSusceptible(g);
        Node nTmp = g.getNode((int)(Math.random()*g.getNodeCount()));
        //Node nTmp = g.getNode(1);
        lstNodeInfect.add(nTmp);
        nTmp.setAttribute("etat","infecter");

        // 84 est le nombre total de jours en 3 mois ( 28*3 )
        for(int i = 0; i<84; i++){
            List<Node> lstTmpInfect = new ArrayList<>(lstNodeInfect);
            for(Node n : lstTmpInfect){
                if(Math.random() < 1/7.0 ){
                    for(Edge e : n.getLeavingEdgeSet()){
                        Node voisin = e.getOpposite(n);
                        if (voisin.getAttribute("etat").equals("susceptible")) {
                            lstNodeInfect.add(voisin);
                            voisin.setAttribute("etat","infecter");
                        }
                    }
                }
                if(Math.random() < 1/14.0){
                    n.setAttribute("etat","susceptible");
                    lstNodeInfect.remove(n);
                }
            }
            System.out.println((lstNodeInfect.size()*100.0)/nbInfect);
        }
    }

    public static void simulation2(Graph g){
        List<Node> lstNodeInfect = new ArrayList<>();
        for(Node n : g){
            if(Math.random() < 1/2.0){
                n.addAttribute("etat","Immuniser");
            }else{
                n.addAttribute("etat","susceptible");
            }

        }

        int nbInfect = SimulationPropagationReseauAleatoire.nbSusceptible(g);
        Node nTmp = g.getNode((int)(Math.random()*g.getNodeCount()));
        //Node nTmp = g.getNode(1);
        lstNodeInfect.add(nTmp);
        nTmp.setAttribute("etat","infecter");

        // 84 est le nombre total de jours en 3 mois ( 28*3 )
        for(int i = 0; i<84; i++){
            List<Node> lstTmpInfect = new ArrayList<>(lstNodeInfect);
            for(Node n : lstTmpInfect){
                if(Math.random() < 1/7.0 ){
                    for(Edge e : n.getLeavingEdgeSet()){
                        Node voisin = e.getOpposite(n);
                        if (voisin.getAttribute("etat").equals("susceptible")) {
                            lstNodeInfect.add(voisin);
                            voisin.setAttribute("etat","infecter");
                        }
                    }
                }
                if(Math.random() < 1/14.0){
                    n.setAttribute("etat","susceptible");
                    lstNodeInfect.remove(n);
                }
            }
            System.out.println((lstNodeInfect.size()*100.0)/nbInfect);
        }
    }

    public static void simulation(Graph g){
        List<Node> lstNodeInfect = new ArrayList<>();
        int nbNodeGroupe0 = 0;
        int nbNodeGroupe1 = 0;
        int nbDegreGroupe0 = 0;
        int nbDegreGroupe1 = 0;
        int nbDegreGroupe0_2 = 0;
        int nbDegreGroupe1_2 = 0;

        for(Node n : g){
            if(Math.random() < 1/2.0){
                if(!n.hasAttribute("etat") || n.hasAttribute("etat") && !n.getAttribute("etat").equals("Immuniser"))
                    n.addAttribute("etat","susceptible");
                nbNodeGroupe0++;
                nbDegreGroupe0 += n.getDegree();
                nbDegreGroupe0_2 += Math.pow(n.getDegree(),2);
                if(n.getLeavingEdgeSet().size() > 0){
                    int voisinChoisi = (int)(Math.random()*n.getLeavingEdgeSet().size());
                    Edge[] tabEdge = new Edge[n.getLeavingEdgeSet().size()];
                    n.getLeavingEdgeSet().toArray(tabEdge);
                    tabEdge[voisinChoisi].getOpposite(n).setAttribute("etat","Immuniser");
                    nbNodeGroupe1++;
                    nbDegreGroupe1 += n.getDegree();
                    nbDegreGroupe1_2 += Math.pow(n.getDegree(),2);
                }

            }else{
                n.addAttribute("etat","susceptible");
            }

        }
        double degreMoyenGroupe0 = nbDegreGroupe0/(double)nbNodeGroupe0;
        double degreMoyenGroupe1 = nbDegreGroupe1/(double)nbNodeGroupe1;
        System.out.println("Groupe 0 : " + degreMoyenGroupe0);
        System.out.println("Groupe 1 : " + degreMoyenGroupe1);
        double degreMoyenCarreGroupe0 = nbDegreGroupe0_2/(double)nbNodeGroupe0;
        double degreMoyenCarreGroupe1 = nbDegreGroupe1_2/(double)nbNodeGroupe1;
        System.out.println("Seuil epidémique group 0 : " + degreMoyenGroupe0/degreMoyenCarreGroupe0);
        System.out.println("Seuil epidémique group 1 : " + degreMoyenGroupe1/degreMoyenCarreGroupe1);

        int nbInfect = SimulationPropagationReseauAleatoire.nbSusceptible(g);
        Node nTmp = g.getNode((int)(Math.random()*g.getNodeCount()));
        System.out.println("numero node : " + nTmp.getId());
        lstNodeInfect.add(nTmp);
        nTmp.setAttribute("etat","infecter");

        // 84 est le nombre total de jours en 3 mois ( 28*3 )
        for(int i = 0; i<84; i++){
            List<Node> lstTmpInfect = new ArrayList<>(lstNodeInfect);
            for(Node n : lstTmpInfect){
                if(Math.random() < 1/7.0 ){
                    for(Edge e : n.getLeavingEdgeSet()){
                        Node voisin = e.getOpposite(n);
                        if (voisin.getAttribute("etat").equals("susceptible")) {
                            lstNodeInfect.add(voisin);
                            voisin.setAttribute("etat","infecter");
                        }
                    }
                }
                if(Math.random() < 1/14.0){
                    n.setAttribute("etat","susceptible");
                    lstNodeInfect.remove(n);
                }
            }
            System.out.println((lstNodeInfect.size()*100.0)/nbInfect);
        }
    }

    public static int nbSusceptible(Graph g){

        int nbSusceptible = 0;

        for(Node n : g){
            if(n.getAttribute("etat").equals("susceptible")){
                nbSusceptible++;
            }
        }
        return nbSusceptible;
    }
}
