package test;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;

import impl.Afficheur;
import impl.Canal;
import impl.CapteurImpl;
import impl.DiffusionAtomique;
import impl.Scheduler;

public class TestAlgoDiffusionAtom {

    static int NB_CANAUX = 3;
    static int TEST_TIME = 30; // TEST_TIME/6 + 5*TEST_TIME/6
    public static List<Integer>[] rAtom;


    private static void display(List<Integer>[] res){
        for(int i = 0; i< NB_CANAUX; i++){
            System.out.println("canal " + i + ":");
            for(int j = 0; j< res[i].size(); j++){
                System.out.print(res[i].get(j));
                if(j<res[i].size()-1) System.out.print(", ");
            }
            System.out.println(" ");
        }
    }

    @BeforeAll
    public static void testAtom() throws InterruptedException{

        ArrayList<Integer>[] r = new ArrayList[NB_CANAUX];
        for(int i = 0; i<NB_CANAUX; i++){
            r[i] = new ArrayList<Integer>();
        }

        Afficheur[] a = new Afficheur[NB_CANAUX];

        Scheduler scheduler = new Scheduler(NB_CANAUX);
        CapteurImpl c = new CapteurImpl();

        DiffusionAtomique algo = new DiffusionAtomique(c);
        c.setAlgoDiffusion(algo);

        for(int i = 0; i<NB_CANAUX; i++){
            Afficheur afficheur = new Afficheur();
            afficheur.setId(i);
            a[i] = afficheur;
            Canal canal = new Canal(c, scheduler, afficheur);
            c.attach(canal);
        }
         
        ScheduledExecutorService clock =  scheduler.getScheduler();
        ScheduledFuture<?> future = clock.scheduleAtFixedRate(() -> c.tick(), 0, 500, TimeUnit.MILLISECONDS);

        for(int i = TEST_TIME/6; i>0; i--){ //attend que le capteur génère des valeurs
            System.out.println("restant " + i + "s");
            Thread.sleep(1000); 
        }

        System.out.println("STOP");
        c.stop(); //arrête la mise à jour du capteur (mais stop pas le tick)
        System.out.println("waitting for lasts display...");

        for(int i =  5*TEST_TIME/6; i>0; i--){
            System.out.println("restant " + i + "s");
            Thread.sleep(1000); 
        }

        future.cancel(false);
        
        clock.shutdown();
        
        for(int i = 0; i<NB_CANAUX; i++){
            r[i] = a[i].vals;
        }
        rAtom = r;

        display(rAtom);
    }


    // ORACLE 

    @Test
    void testHaveAllElement(){
        boolean r = true;

        for(int i = 0; i< NB_CANAUX && r; i++){
            int valTest = 1;
            for(int j = 0; j< rAtom[i].size() && r; j++){
                r = r && rAtom[i].get(j)==valTest;
                valTest++;
            }
        }
        assertTrue(r);
    }


    @Test
    void sameElements(){
        boolean r = true;

        for(int i = 0; i< NB_CANAUX-1 && r; i++){
            r = rAtom[i].size()==rAtom[i+1].size();
        }
        if(!r){
            System.err.println("Pas de la même taille !");
        }
        else{
            for(int j = 0; j< rAtom[0].size() && r; j++){
                int temp = rAtom[0].get(j);
                for(int i = 1; i< NB_CANAUX && r; i++){
                    r = r && rAtom[i].get(j)==temp;
                }
            }
        }
        assertTrue(r);
    }

}
