/**
 * 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.ui.views.employees;

import static com.planimod.ui.Localized._;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.eclipse.jface.action.Action;

import com.patrikdufresne.managers.ManagerException;
import com.planimod.core.EmployeePreference;
import com.planimod.core.PlanimodManagers;
import com.planimod.core.Team;
import com.planimod.ui.PlanimodPolicy;
import com.planimod.ui.theme.Resources;

/**
 * This class is used to change the order of the preferred team of an employee. This action required to be disposed.
 * 
 * @author Patrik Dufresne
 * 
 */
public class EmployeePreferredTeamMoveAction extends Action {

    private int direction;

    /**
     * Define the shift to be moved.
     */
    private Team shift;
    /**
     * The employee preference.
     */
    private EmployeePreference employeePreference;

    /**
     * Direction up (reduce index).
     */
    public static final int DIRECTION_UP = 1;
    /**
     * Direction down (increase index).
     */
    public static final int DIRECTION_DOWN = 2;
    /**
     * The shift property.
     */
    public static final String SHIFT = "shift";
    /**
     * The employee preference property.
     */
    public static final String EMPLOYEE_PREFERENCE = "employeePreference";
    /**
     * Managers to use.
     */
    private PlanimodManagers managers;

    private PropertyChangeListener listener = new PropertyChangeListener() {

        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            setEnabled(canRun());
        }

    };

    /**
     * Create a new action.
     * 
     * @param direction
     *            the direction of the move
     */
    public EmployeePreferredTeamMoveAction(PlanimodManagers managers, int direction) {
        if (managers == null) {
            throw new NullPointerException();
        }
        this.managers = managers;
        this.direction = direction;
        if (direction == DIRECTION_UP) {
            setText(_("Haut"));
            setToolTipText(_("Déplace l'équipe vers le haut"));
            setImageDescriptor(Resources.getImageDescriptor(Resources.ICON_GO_UP_16));
        } else {
            setText(_("Bas"));
            setToolTipText(_("Déplace l'équipe vers le bas"));
            setImageDescriptor(Resources.getImageDescriptor(Resources.ICON_GO_DOWN_16));
        }
        setEnabled(canRun());
    }

    /**
     * Returns the current shift.
     * 
     * @return the shift or null is note set.
     */
    public Team getShift() {
        return this.shift;
    }

    /**
     * Sets the current shift to be moved.
     * 
     * @param shift
     *            the shift or null.
     */
    public void setShift(Team shift) {
        firePropertyChange(SHIFT, this.shift, this.shift = shift);
        setEnabled(canRun());
    }

    protected boolean canRun() {
        int index;
        List<Team> shifts;
        return this.shift != null
                && this.employeePreference != null
                && ((shifts = this.employeePreference.getPreferredTeam()) != null)
                && ((index = shifts.indexOf(this.shift)) != -1)
                && (this.direction == DIRECTION_UP ? index > 0 : index < shifts.size() - 1);
    }

    /**
     * Returns the current employee preference.
     * 
     * @return
     */
    public EmployeePreference getEmployeePreference() {
        return this.employeePreference;
    }

    /**
     * Sets the employee preference to update.
     * 
     * @param employeePreference
     */
    public void setEmployeePreference(EmployeePreference employeePreference) {
        // Remove previous listener
        if (this.employeePreference != null) {
            this.employeePreference.removePropertyChangeListener(EmployeePreference.PREFERRED_TEAM, this.listener);
        }
        // Attach listener
        if (employeePreference != null) {
            employeePreference.addPropertyChangeListener(EmployeePreference.PREFERRED_TEAM, this.listener);
        }
        firePropertyChange(EMPLOYEE_PREFERENCE, this.employeePreference, this.employeePreference = employeePreference);
        setEnabled(canRun());
    }

    @Override
    public void run() {
        if (!canRun()) {
            return;
        }

        // Retrieve the current preferred shift list.
        List<Team> preferredTeams = this.employeePreference.getPreferredTeam();
        if (preferredTeams == null) {
            return;
        }
        preferredTeams = new ArrayList<Team>(preferredTeams);

        // Find the shift to be move
        int i = 0;
        while (i < preferredTeams.size() && !preferredTeams.get(i).equals(this.shift)) {
            i++;
        }
        if (i >= preferredTeams.size()) {
            return;
        }

        int index = preferredTeams.indexOf(this.shift);
        if (this.direction == DIRECTION_UP && index > 0) {
            Team previous = preferredTeams.set(i - 1, this.shift);
            preferredTeams.set(i, previous);
        } else if (this.direction == DIRECTION_DOWN && index < preferredTeams.size() - 1) {
            Team previous = preferredTeams.set(i + 1, this.shift);
            preferredTeams.set(i, previous);
        }
        this.employeePreference.setPreferredTeam(preferredTeams);

        // Persist the modification
        try {
            this.managers.updateAll(Arrays.asList(this.employeePreference));
        } catch (ManagerException e) {
            PlanimodPolicy.showException(e);
        }

        setEnabled(canRun());
    }

    public void dispose() {
        // Remove listener
        if (this.employeePreference != null) {
            this.employeePreference.removePropertyChangeListener(EmployeePreference.PREFERRED_TEAM, this.listener);
        }
        this.employeePreference = null;
        this.managers = null;
        this.listener = null;
        this.shift = null;
    }

}
