package rh213424;

import org.graphstream.algorithm.Toolkit;
import org.graphstream.graph.Edge;
import org.graphstream.graph.Graph;
import org.graphstream.graph.Node;
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.averageDegree;
import static org.graphstream.algorithm.Toolkit.randomNode;

public class Propagation {
  /**
   * graphe du réseau
   */
  private Graph graph;

  public Propagation(Graph graph) {
    this.graph = graph;
  }
  /**
   * calcul la distribution des degrés <k²>
   * @return double
   */
  public  double  distributionDegre(){
    double d = 0.0;
    int[] tabDistributionDegres= Toolkit.degreeDistribution(graph);
    for (int i = 0; i < tabDistributionDegres.length; i++) {
      double moyenneDegre = (double) tabDistributionDegres[i] / graph.getNodeCount();
      if (tabDistributionDegres[i] > 0) {
        d += Math.pow(i, 2) * moyenneDegre;
      }
    }
    return d;
  }

  /**
   * Calcul du taux de propagation λ = β / μ
   */
  public static void tauxPropagation(){
    double beta = 1.0/7.0;
    double gama = 1.0/14.0;
    double taux = beta/gama;
    System.out.println("Le taux de propagation du virus est : "+taux);
  }

  /**
   * Calcule et affiche le seuil épidémique
   */
  public void seuilEpidemique(){
    double k2 = distributionDegre();
    System.out.println("La distribution des degrés <k²> de notre réseau est :"+k2);
    double k = averageDegree(graph);
    double seuil = k/k2;
    System.out.println("Le seuil épidémique du réseau est : "+seuil);
  }

  /**
   * Simulation premier scenario
   */
  public void scenario1() throws IOException {
    //liste pour stocker les infectes
    ArrayList<Node> infectes = new ArrayList<>();
    Random random = new Random();
    //Pour l'ecriture du fichier
    StringBuilder data = new StringBuilder();
    //Tout les noeuds sont sains au debut
    for (Node node : graph) {
      node.setAttribute("santé", "sain");
    }
    //generation d'un random premier infecté
    Node patientZeo = randomNode(graph);
    infectes.add(patientZeo);
    patientZeo.setAttribute("santé", "infecté");
    //Pour stocker le nombre d'infectes par jour
    int[] nbrInfect = new int[84];
    //Pour chaque jour
    for (int i = 0; i < 84; i++) {
      for (Node n : graph) {
        //Si le noeud est infecté on infecte tout les vosins collaborateurs
        if (n.getAttribute("santé") == "infecté") {
          for (Edge e : n) {
            Node voisin = e.getOpposite(n);
            //Probabilité 1/3 pour qu'un noeud soit infecté
            if (random.nextInt(3) == 1)  {
              if (voisin.getAttribute("santé") == "sain") {
                voisin.setAttribute("santé", "infecté");
                infectes.add(voisin);
              }
            }
          }
        }
      }
      Iterator<Node> it = infectes.iterator();
      //Probabilité de 1/14 pour qu'un collaborateur met à jour son antivirus
      while (it.hasNext()) {
        if (random.nextInt(20) == 1)  {
          it.next().setAttribute("santé", "sain");
          it.remove();
        }
        else it.next();
      }
      //On stocke le nombre d'infectés par jour
      nbrInfect[i] = infectes.size();
    }
    for (int i = 0; i < 84; i++) {
      int nb = i+1;
      System.out.println("jour " + nb+ ":" + nbrInfect[i]);
      data.append(nb).append(" ").append(nbrInfect[i]).append(System.getProperty("line.separator"));
    }
    ecrireDataFichier(data,1);
  }
  /**
   * Simulation scénario2
   */
  public void scenario2(){
    int nbImmunise = 0;
    Random random = new Random();
    //Moite du graphe
    List<Node> moitieGraphe = Toolkit.randomNodeSet(graph, graph.getNodeCount()/2);
    //50% du graphe vont etre immunisé
    for(Node n : moitieGraphe) {
      n.setAttribute("santé", "immunisé");
      nbImmunise++;
    }
    Node patient0 = randomNode(graph);
    patient0.setAttribute("santé","infecté");
    for(int jour = 1; jour<=90; jour++){
      int nbrInfecteJour = 1;
      int jourInfection = 1;
      for (Node n : graph){
        if(n.getAttribute("santé") == "infecté"){
          if(random.nextInt(8) == jourInfection) {
            for(Edge e : n){
              Node collaborateur = e.getOpposite(n);
              collaborateur.setAttribute("santé", "infecté");
              nbrInfecteJour++;
            }
          }
        }
        int jourImmunisation = 2;
        if (random.nextInt(15) == jourImmunisation) {
          if(n.getAttribute("santé")=="infecté"){
            n.setAttribute("santé", "sain");
            nbrInfecteJour--;
          }
        }
      }
      System.out.println(jour +" "+ nbrInfecteJour);
    }
  }
  /**
   * Méthode pour l'écriture des données pour chaque scénario
   * @param data
   * @param nbrSce
   * @throws IOException
   */
  public void ecrireDataFichier(StringBuilder data,int nbrSce) throws IOException {
    File fichier = new File("./resources/scenarios/scenario"+nbrSce+".dat");
    if (!fichier.exists()) {
      fichier.createNewFile();
    }
    FileWriter fw = new FileWriter(fichier.getAbsoluteFile(),false);
    BufferedWriter bw = new BufferedWriter(fw);
    bw.write(data.toString());
    bw.close();
  }
}