package propagation;

import org.graphstream.algorithm.generator.BarabasiAlbertGenerator;
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.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 org.graphstream.algorithm.Toolkit;

import java.io.IOException;
import java.util.*;
import java.util.stream.Stream;

public class Propagation {

    private LinkedList<Node> infected;
    private Graph graph;
    private LinkedList<Node> lesSusceptibles;
    private double beta=1/7D;
    private double mu=1/14D;
    private int periode=84;

    public Propagation(Graph graph){
        this.graph=graph;
    }

    //ajouter l'attribut state=""===> en bonne etat
    public void addState(){
        for(Node node:this.getGraph().getEachNode()){
            node.addAttribute("state","");
        }
    }

    //add susceptibles
    public void susceptibles(Node node,int day){

        //add its neighbors in susceptible
        Iterator<Node> iterator=node.getNeighborNodeIterator();
        while (iterator.hasNext()){
            Node n=iterator.next();
            String state=n.getAttribute("state");
            if( !state.equals("infected")){
                n.setAttribute("state","susceptible"+day);
            }
        }
    }

    //patient0
    public void patient0(){
        Node node=Toolkit.randomNode(this.getGraph());
        node.setAttribute("state","infected");
        susceptibles(node,0);
    }

    //outbreak
    public void outBreak(int day){
        Random random =new Random();

        for(Node node:getGraph().getEachNode()){
            String state=node.getAttribute("state");
            if( state.equals("susceptible"+(day-1))) {
                if (beta < random.nextDouble()) {
                    node.setAttribute("state", "infected");
                    susceptibles(node,day);
                }
            }
        }
        for(Node node:getGraph().getEachNode()){
            String state=node.getAttribute("state");
            if(  state.length()!=0) {
                if (state.charAt(0) == 's' ) {
                    node.setAttribute("state", "susceptible" +day);
                }
            }
        }

    }

    //
    public void scenarion1(){
        addState();
        patient0();

        int day=1;
        double percent=0;
        int count=getGraph().getNodeCount();
        while(day<=84){
            System.out.format("\r%.1f%%",percent+=100/84D);
            outBreak(day);
            int i=0;
            for(Node node:getGraph().getEachNode()){
                if(node.getAttribute("state").toString().equals("infected"))i++;
            }
            System.out.println(i/(double)count);
            day++;
        }
    }

    public  void cinquante(){
        int count=getGraph().getNodeCount();
        Random random=new Random();
        for(Node node:getGraph().getEachNode()) {
            if(0.5D<=random.nextDouble()){
                node.addAttribute("percent","");
            }
        }
    }

    public void immunisation(int day){
        int nombre=getGraph().getNodeCount()/2;

        Random random=new Random();
        String state;

        for(Node node:getGraph().getEachNode()) {
            state=node.getAttribute("state");
            if(node.hasAttribute("percent")&&state.equals("infected")) {
                if (mu < random.nextDouble()) {
                    node.setAttribute("state", "susceptible" + (day));
                }
            }
        }
    }

    //
    public void scenarion2(){
        addState();
        patient0();

        cinquante();//50%
        int day=1;
        double percent=0;
        int count=getGraph().getNodeCount();
        while(day<=84){
            System.out.format("\r%.1f%%",percent+=100/84D);
            outBreak(day);
            int i=0;
            for(Node node:getGraph().getEachNode()){
                if(node.getAttribute("state").toString().equals("infected"))i++;
            }
            System.out.println(i);
            immunisation(day);

            i=0;
            for(Node node:getGraph().getEachNode()){
                if(node.getAttribute("state").toString().equals("infected"))i++;
            }
            System.out.println(i);
            day++;
        }
    }

    public void immunisation3(int day){
        int nombre=getGraph().getNodeCount()/2;

        int i=0;

        Random random=new Random();
        String state;
        for(Node node:getGraph().getEachNode()) {
            state=node.getAttribute("state");
            if (node.hasAttribute("percent") && state.equals("infected")) {
                if (mu < random.nextDouble()) {
                    Iterator<Node> iterator=node.getNeighborNodeIterator();
                    while(iterator.hasNext()){
                        iterator.next().setAttribute("state","susceptible"+day);
                        break;
                    }
                }
            }
        }
    }

    public void scenarion3(){
        addState();
        patient0();

        cinquante();//50%
        int day=1;
        double percent=0;
        int count=getGraph().getNodeCount();
        while(day<=84){
            System.out.format("\r%.1f%%",percent+=100/84D);
            outBreak(day);
            immunisation3(day);

            int i=0;
            for(Node node:getGraph().getEachNode()){
                if(node.getAttribute("state").toString().equals("infected"))i++;
            }
            System.out.println(i);
            day++;
        }
    }







    public Graph getGraph() {
        return graph;
    }

    public void setGraph(Graph graph) {
        this.graph = graph;
    }


    public void setInfected(LinkedList<Node> infected) {
        this.infected = infected;
    }

    public void setLesSusceptibles(LinkedList<Node> lesSusceptibles) {
        this.lesSusceptibles = lesSusceptibles;
    }

    public LinkedList<Node> getInfected() {
        return infected;
    }

    public LinkedList<Node> getLesSusceptibles() {
        return lesSusceptibles;
    }


    public static Graph graphColaboration(){
        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);

        } catch( IOException ignored) {

        } finally {
            fs.removeSink(graph);
        }
        return graph;
    }

    public double seuil(){
        double k=Toolkit.averageDegree(getGraph());
        double kk=0;
        for (Node node:getGraph().getEachNode()){
            kk+=Math.pow(node.getDegree(),2);
        }
        kk=kk/(double)getGraph().getNodeCount();

        return k/kk;
    }


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

        return graph2;
    }

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

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

        return graph1;
    }


    public static void main(String[] args) throws IOException, GraphParseException {

        Propagation pro=new Propagation(graphColaboration());

    }
}
