/*
 * Copyright (c) 2011, Patrik Dufresne. All rights reserved.
 * Patrik Dufresne PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package com.planimod.ui.views.employees;

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.patrikdufresne.util.Localized;
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"; //$NON-NLS-1$
	/**
	 * The employee preference property.
	 */
	public static final String EMPLOYEE_PREFERENCE = "employeePreference"; //$NON-NLS-1$
	/**
	 * 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(Localized.get(EmployeePreferredTeamMoveAction.class,
					"EmployeeEditor.preferredTeamMoveUpAction.text")); //$NON-NLS-1$
			setToolTipText(Localized.get(EmployeePreferredTeamMoveAction.class,
					"EmployeeEditor.preferredTeamMoveUpAction.toolTipText")); //$NON-NLS-1$
			setImageDescriptor(Resources
					.getImageDescriptor(Resources.ICON_GO_UP_16));
		} else {
			setText(Localized.get(EmployeePreferredTeamMoveAction.class,
					"EmployeeEditor.preferredTeamMoveDownAction.text")); //$NON-NLS-1$
			setToolTipText(Localized.get(EmployeePreferredTeamMoveAction.class,
					"EmployeeEditor.preferredTeamMoveDownAction.toolTipText")); //$NON-NLS-1$
			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;
	}

}
