package InitialSchedules;

import org.chocosolver.solver.Model;
import org.chocosolver.solver.variables.BoolVar;
import org.chocosolver.solver.variables.IntVar;

public class ModelPartTimeEmployeesInitialSchedules {

    public final ParametersInitialSchedules myScheduleParameters;

    public final int maxPartTimeEmployee;

    public BoolVar workPeriodsSchedulesOfPartTimeEmployees[][];
    private BoolVar transposeWorkPeriodsSchedulesOfPartTimeEmployees[][];

    private IntVar partTimeEmployeesPerWorkPeriods[];

    public final Model chocoModelInitialSchedules;

    public ModelPartTimeEmployeesInitialSchedules(ParametersInitialSchedules myScheduleParameters) {

        this.myScheduleParameters = myScheduleParameters;
        
        this.chocoModelInitialSchedules = new Model("Model Part Time Employees Initial Schedules");
                
        this.maxPartTimeEmployee = (int) Math.ceil((double) myScheduleParameters.getTotalWorkedPeriodsInSchedule()
                                        / myScheduleParameters.getMinWorkingPeriodsOfPartTimeEmployeesPerSchedule());
        
        this.createScheduleVariables();
        this.createModelConstraints();

    }

    private void createScheduleVariables() {

        // Variable pour l'horaire des employes
        this.workPeriodsSchedulesOfPartTimeEmployees = chocoModelInitialSchedules.boolVarMatrix(this.maxPartTimeEmployee, this.myScheduleParameters.getWorkPeriodsPerSchedule());

        // Creer la transpose des horaires pour compter les elements des colonnes
        this.transposeWorkPeriodsSchedulesOfPartTimeEmployees = chocoModelInitialSchedules.boolVarMatrix(this.myScheduleParameters.getWorkPeriodsPerSchedule(), this.maxPartTimeEmployee);
        for (int workPeriod = 0; workPeriod < this.myScheduleParameters.getWorkPeriodsPerSchedule(); workPeriod++) {
            for (int employee = 0; employee < this.maxPartTimeEmployee; employee++) {
                this.transposeWorkPeriodsSchedulesOfPartTimeEmployees[workPeriod][employee]
                        = this.workPeriodsSchedulesOfPartTimeEmployees[employee][workPeriod];
            }
        }
        
        // Variable pour faire le compte du nombre d'employes par periode de travail
        this.partTimeEmployeesPerWorkPeriods = chocoModelInitialSchedules.intVarArray(this.myScheduleParameters.getWorkPeriodsPerSchedule(), 0, this.maxPartTimeEmployee, true);
        
    }

    private void createModelConstraints() {

        // Constraintes tableau pour choisir un type d'horaire dans les horaires possibles
        for (int employee = 0; employee < this.maxPartTimeEmployee; employee++) {
            chocoModelInitialSchedules.table(this.workPeriodsSchedulesOfPartTimeEmployees[employee],
                    this.myScheduleParameters.enumerationWorkPeriodsSchedulesOfPartTimeEmployees).post();
        }

        // Constraintes pour compter le nombre d'employes par periode de travail et s'assurer qu'il
        // satisfait la demande en employes
        for (int workPeriod = 0; workPeriod < this.myScheduleParameters.getWorkPeriodsPerSchedule(); workPeriod++) {
            chocoModelInitialSchedules.count(chocoModelInitialSchedules.intVar(1),
                    transposeWorkPeriodsSchedulesOfPartTimeEmployees[workPeriod],
                    this.partTimeEmployeesPerWorkPeriods[workPeriod]).post();
            chocoModelInitialSchedules.arithm(this.partTimeEmployeesPerWorkPeriods[workPeriod], "=",
                    this.myScheduleParameters.getRequiredWorkForce(workPeriod)).post();
        }

        // Contrainte de bris de symétrie:
        // chaque horaire d'employé est léxicographiquement inférieure à la suivante, par type d'employé
        // Ne fonctionne pas avec l'heuristique par défaut
        for (int employee = 0; employee < (this.maxPartTimeEmployee-1); employee++){
            chocoModelInitialSchedules.lexLessEq(this.workPeriodsSchedulesOfPartTimeEmployees[employee],
                    this.workPeriodsSchedulesOfPartTimeEmployees[employee+1]).post();
        }
        
    }

}
