package InitialSchedules;

import org.chocosolver.solver.Model;
import org.chocosolver.solver.Solution;
import org.chocosolver.solver.constraints.nary.automata.FA.FiniteAutomaton;
import org.chocosolver.solver.variables.BoolVar;
import org.chocosolver.solver.variables.IntVar;

import java.util.List;

public class ValidDailySchedules {

    int[][] ValidSchedules;
    private int nbSolutions;

    ValidDailySchedules(int nbPeriodes, int nbPeriodesTravailleesMin, int nbPeriodesTravailleesMax, int p1Min, int p1Max, int p2Min, int p2Max, int nbMaxConsecutif) {

        Model model = new Model("Horaire de " + nbPeriodes + "-periodes");
        BoolVar[] horaire = new BoolVar[nbPeriodes];
        for (int p = 0; p < nbPeriodes; p++) {
            horaire[p] = model.boolVar("P_" + p);
        }

        BoolVar[] horaires1 = new BoolVar[p1Max - p1Min];
        BoolVar[] horaires2 = new BoolVar[p1Max - p1Min];

        IntVar sumhoraire1 = model.intVar("SP_1", 0, nbPeriodes);
        IntVar sumhoraire2 = model.intVar("SP_2", 0, nbPeriodes);

        for (int p = 0; p < p1Max - p1Min; p++) horaires1[p] = horaire[p1Min + p];
        for (int p = 0; p < p2Max - p2Min; p++) horaires2[p] = horaire[p2Min + p];

        /* Travaille entre le nombre minimum et maximum de périodes */
        model.sum(horaire, ">=", nbPeriodesTravailleesMin).post();
        model.sum(horaire, "<=", nbPeriodesTravailleesMax).post();

        /* Travaille autant dans les deux sous-périodes */
        model.sum(horaires1, "=", sumhoraire1).post();
        model.sum(horaires2, "=", sumhoraire2).post();
        model.arithm(sumhoraire1, "=", sumhoraire2).post();

        /*Travaille une fin de semaine sur deux*/
        model.arithm(horaire[5], "=", horaire[6]).post();
        model.arithm(horaire[12], "=", horaire[13]).post();
        model.arithm(horaire[5], "!=", horaire[12]).post();

        /*Respect du maximum consecutif*/
        FiniteAutomaton automatonConsecutif = new FiniteAutomaton("[01]*1{" + (nbMaxConsecutif + 1) + "," + nbPeriodes + "}[01]*");
        BoolVar respecteMaxConsecutif = model.regular(horaire, automatonConsecutif).reify();
        model.arithm(respecteMaxConsecutif, "=", 0).post();

        //System.out.println(automatonConsecutif.toDot());

        /* Trouver les solutions*/
        List<Solution> solutions = model.getSolver().findAllSolutions();

        this.nbSolutions = solutions.size() + 1;

        ValidSchedules = new int[this.nbSolutions][nbPeriodes];

        /* Itérer sur les solutions */
        int iterSolutions = 0;
        for (Solution solution : solutions) {
            if (solution != null) {
                for (int iterPeriod = 0; iterPeriod < nbPeriodes; iterPeriod++) {
                    ValidSchedules[iterSolutions][iterPeriod] = solution.getIntVal(horaire[iterPeriod]);
                }
                iterSolutions++;
            }
        }
        /* La solution additionnelle où le travailleur ne travaille pas*/
        for (int iterPeriod = 0; iterPeriod < nbPeriodes; iterPeriod++) {
            ValidSchedules[this.nbSolutions - 1][iterPeriod] = 0;
        }
    }

    public int getNbSolutions() {
        return this.nbSolutions;
    }

    public int[][] getValidSchedules() {
        return ValidSchedules;
    }
}
