//import AbsenceSchedules.AbsenceSchedulesArray;

import AbsenceSchedules.AbsenceSchedulesArray;
import ScheduleUtil.SchedulesArray;
import SchedulesRecovery.RecoveredSchedulesArray;
import jdistlib.rng.MersenneTwister;
import jdistlib.rng.RandomEngine;
import org.chocosolver.solver.Solution;
import org.chocosolver.solver.Solver;
import org.chocosolver.solver.exception.ContradictionException;

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



public class MainClass {

    public static void main(String[] args) {

        // Le main ne devrait contenir que les 5 fonctions correspondantes aux etapes du pipeline
        List<SchedulesArray> initialSchedulesArrayList = generateInitialSchedules();

        List<SchedulesArray> absenceSchedulesArrayList = GenerateAbsencesSchedules(initialSchedulesArrayList);

        List<SchedulesArray> recoveredSchedulesArrayList = GenerateRecoveredSchedules(absenceSchedulesArrayList);
        // Algo de recouvrement d'absences. Faire un nouveau package de fonctions.
        // Trouver meilleure solution et l'afficher.
    }

    private static List<SchedulesArray> generateInitialSchedules() {

        List<SchedulesArray> initialSchedulesArrayList = new ArrayList<>();

        InitialSchedules.ParametersInitialSchedules myScheduleParameters
                = new InitialSchedules.ParametersInitialSchedules();

        InitialSchedules.ModelInitialSchedules myModelInitialSchedules
                = new InitialSchedules.ModelInitialSchedules(myScheduleParameters);

        Solver solverInitialSchedules = myModelInitialSchedules.chocoModelInitialSchedules.getSolver();

        try {
            solverInitialSchedules.propagate();
        } catch (ContradictionException e) {
            System.err.println("Caught ContradictionException: " + e.getMessage());
            solverInitialSchedules.getEngine().flush();
        } catch (Exception e) {
            System.err.println("Caught Exception: " + e.getMessage());
        }

        solverInitialSchedules.showDashboard();
        /*solverInitialSchedules.setSearch(Search.domOverWDegSearch(myModelInitialSchedules.allWorkPeriods));*/
//        solverInitialSchedules.setRestartOnSolutions(); /*Sans restart, toutes les horaires sont identiques*/
        solverInitialSchedules.limitSolution(5);
        //solverInitialSchedules.limitTime(10000);
        List<Solution> myInitialSchedulesSolutions;
/*        myInitialSchedulesSolutions = solverInitialSchedules.findAllOptimalSolutions
          (myModelInitialSchedules.TotalEmployeesSalary, Model.MINIMIZE);*/

        //solverInitialSchedules.findSolution();
        myInitialSchedulesSolutions = solverInitialSchedules.findAllSolutions();
        solverInitialSchedules.printStatistics();

        // Création de l'objet banque d'horaire, qui est une liste d'objets de type InitialSchedulesArray, qui contiennent chacun deux tableaux.
        for (Solution CurrentSolution : myInitialSchedulesSolutions) {
            SchedulesArray isa = new SchedulesArray(myModelInitialSchedules, CurrentSolution);
            initialSchedulesArrayList.add(isa);
        }
        
        // Pour afficher les horaires initiales
        SchedulesWindows.ShowSchedulesFrame intialSchedulesViewer = new SchedulesWindows.ShowSchedulesFrame(initialSchedulesArrayList, "Initial Schedules");

        return initialSchedulesArrayList;

    }

    private static List<SchedulesArray> GenerateAbsencesSchedules(List<SchedulesArray> initialSchedulesArrayList) {
        
        RandomEngine r = new MersenneTwister(123456789);
        List<SchedulesArray> absenceSchedulesArrayList = new ArrayList<>();
        for (SchedulesArray initialSchedule : initialSchedulesArrayList) {
            AbsenceSchedulesArray absenceSchedule = new AbsenceSchedulesArray(initialSchedule);
            absenceSchedule.generateAbsences(r);
            absenceSchedulesArrayList.add(absenceSchedule);
        }
        // Pour afficher les horaires avec absence
        SchedulesWindows.ShowSchedulesFrame absenceSchedulesViewer = new SchedulesWindows.ShowSchedulesFrame(absenceSchedulesArrayList, "Absence Schedules");
        
        return absenceSchedulesArrayList;
    }
    
    private static List<SchedulesArray> GenerateRecoveredSchedules(List<SchedulesArray> absenceSchedulesArrayList) {
        
        List<SchedulesArray> recoveredSchedulesArrayList = new ArrayList<>();
        for (SchedulesArray absenceSchedule : absenceSchedulesArrayList) {
            RecoveredSchedulesArray recoveredSchedule = new RecoveredSchedulesArray(absenceSchedule);
            recoveredSchedule.recoverAbsenceScheduleOptimally();
            recoveredSchedulesArrayList.add(recoveredSchedule);
        }
        // Pour afficher les horaires avec absence
        SchedulesWindows.ShowSchedulesFrame recoveredSchedulesViewer = new SchedulesWindows.ShowSchedulesFrame(recoveredSchedulesArrayList, "Recovered Schedules");
        
        return recoveredSchedulesArrayList;
    }
}
