/**
 * Copyright (C) 2019 Patrik Dufresne Service Logiciel <info@patrikdufresne.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package com.planimod.core.planif;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.planimod.core.EmployeePreference;
import com.planimod.core.Team;

/**
 * Used to maximize the employee preferred team.
 * 
 * @author Patrik Dufresne
 */
@SuppressWarnings("unqualified-field-access")
public class MaxPreferredTeams extends SolveRunnable {

    private static final transient Logger LOGGER = LoggerFactory.getLogger(MaxPreferredTeams.class);

    /**
     * The employee.
     */
    private int i;

    /**
     * The employee's preferred teams.
     */
    private List<Team> preferredTeams;

    /**
     * Create a new instance to maximize preferred team of the employee <code>i</code>.
     * 
     * @param problem
     *            reference to ProblemBuilder
     * 
     * @param i
     *            the employee
     */
    public MaxPreferredTeams(ProblemBuilder problem, int i) {
        super(problem);
        this.i = i;
    }

    @Override
    protected boolean runSolver() throws GeneratePlanifException {
        // Loop on preferred team
        for (int a = 0; a < preferredTeams.size(); a++) {
            // Check if the employee can be assign to team j
            int j = pb.table.indexOf(preferredTeams.get(a));
            if (j != -1) {
                // Check if there is a feasible solution where employee i is
                // assigned to team j.
                CheckPreferredTeam solve1 = new CheckPreferredTeam(pb, i, j);
                solve1.run();
                if (solve1.isFeasible()) {
                    return true;
                }
                // FIXME if we determine it's not possible to assign the
                // employee to the given team, we should fix all the
                // variable to zero.
            }
        }
        // FIXME if the employee can't be assigned to any preferred team, it
        // might be required to create a constraint for this employee to
        // work at least once. Otherwise, if this employee is not available,
        // most likely he will not be required to work and he will be
        // replace by another employee.
        return false;
    }

    @Override
    protected boolean setUp() {
        // Check if the employee is schedule to work according to snapshot
        if (pb.snapshot != null && (pb.xi[i] == null || ZERO.equals(pb.snapshot.get(pb.xi[i])))) {
            feasible = false;
            return false;
        }
        // Check if employee as preference
        EmployeePreference pref = pb.preferences.get(i);
        if (pref == null || (this.preferredTeams = pref.getPreferredTeam()) == null || this.preferredTeams.size() == 0) {
            // No preference for this employee, leave the function
            feasible = false;
            return false;
        }
        LOGGER.debug("Maximize employee {} preferred team.", pb.employeeToString(i));
        return true;
    }
}