package com.planimod.ui.views.nonavailabilities;

import java.util.Date;
import java.util.List;

import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.window.IShellProvider;
import org.eclipse.jface.window.Window;

import com.patrikdufresne.managers.ManagerException;
import com.patrikdufresne.printing.IPrintFactory;
import com.patrikdufresne.printing.PrintAction;
import com.patrikdufresne.util.Localized;
import com.planimod.core.ConcreteTimeRange;
import com.planimod.core.NonAvailability;
import com.planimod.core.PlanimodManagers;
import com.planimod.core.TimeRange;
import com.planimod.core.TimeRanges;
import com.planimod.ui.PlanimodPolicy;
import com.planimod.ui.preference.PlanimodPreferences;

/**
 * This action intend to print the qualification.
 * 
 * @author patapouf
 * 
 */
public class NonAvailabilityPrintAction extends PrintAction {
	/**
	 * Property name of an action's date (value <code>"date"</code>). The date
	 * property is used to know the time range to be printed by this action.
	 */
	public static final String DATE = "date"; //$NON-NLS-1$

	/**
	 * Define the preference key for this action
	 */
	private static final String PREF_KEY = "NonAvailabilityPrintAction.printPreference"; //$NON-NLS-1$

	/**
	 * Define the date state to update.
	 */
	private Date date;

	/**
	 * Managers to use.
	 */
	private PlanimodManagers managers;

	private TimeRange range;

	/**
	 * Create a new Print Employee Action
	 * 
	 * @param shell
	 *            A Shell provider used to create new windows
	 * @param operation
	 *            type of operation : PRINT or PREVIEW
	 */
	public NonAvailabilityPrintAction(PlanimodManagers managers,
			IShellProvider shell, int operation, IRunnableContext context) {
		super(shell, new NonAvailabilityPrintFactory(), operation, context);
		if (managers == null) {
			throw new IllegalArgumentException();
		}
		this.managers = managers;
		setPrefKey(PREF_KEY);
		setPreferenceStore(PlanimodPreferences.getPreferenceStore());
		setEnabled(canRun());
		if (operation == PrintAction.PRINT_ACTION) {
			setText(Localized.get(NonAvailabilityPrintAction.class,
					"NonAvailabilityPrintAction.print")); //$NON-NLS-1$
		} else {
			setText(Localized.get(NonAvailabilityPrintAction.class,
					"NonAvailabilityPrintAction.preview")); //$NON-NLS-1$
		}
	}

	/**
	 * Returns True if the action can be run.
	 * 
	 * @return
	 */
	protected boolean canRun() {
		return this.date != null;
	}

	/**
	 * Returns the current date state of null if not define.
	 * 
	 * @return the date state or null.
	 */
	public Date getDate() {
		return this.date;
	}

	/**
	 * Returns the managers used by this action.
	 * 
	 * @return
	 */
	protected PlanimodManagers getManagers() {
		return this.managers;
	}

	/**
	 * This implementation set the employee to print
	 * 
	 * @param factory
	 *            the factory
	 */
	@Override
	protected void initFactory(IPrintFactory factory) {
		// Get date from state
		if (this.date == null) {
			return;
		}

		// Get matching event for the time range.
		List<NonAvailability> events;
		try {
			events = this.managers.getNonAvailabilityManager().list(
					this.range.getStartDate(), this.range.getEndDate());
		} catch (ManagerException e) {
			PlanimodPolicy.showException(e);
			return;
		}
		((NonAvailabilityPrintFactory) factory).setTimeRange(this.range);
		((NonAvailabilityPrintFactory) factory).setCalendarEvents(events);
	}

	@Override
	public void run() {

		// Query the first day of week data.
		int firstDayOfWeek;
		try {
			firstDayOfWeek = this.managers.getApplicationSettingManager()
					.getFirstDayOfWeek();
		} catch (ManagerException e) {
			PlanimodPolicy.showException(e);
			return;
		}

		// Open a dialog to let the user select the printing time range.
		NonAvailabilityPrintDialog dlg = new NonAvailabilityPrintDialog(
				getShellProvider().getShell());
		dlg.setStart(TimeRanges.getMonthStart(this.date));
		dlg.setEnd(TimeRanges.getMonthStart(this.date));

		if (dlg.open() != Window.OK) {
			// Operation cancel by user.
			return;
		}
		if (dlg.getStart() == null || dlg.getEnd() == null) {
			return;
		}

		this.range = new ConcreteTimeRange(
				TimeRanges.getFirstDayOfFirstWeekOfMonth(dlg.getStart(),
						firstDayOfWeek),
				TimeRanges.getLastDayOfLastWeekOfMonth(dlg.getEnd(),
						firstDayOfWeek));

		super.run();
	}

	/**
	 * Sets the date state to be updated.
	 * 
	 * @param date
	 *            the state.
	 */
	public void setDate(Date date) {
		if ((this.date == null && date != null)
				|| (this.date != null && date == null)
				|| (this.date != null && date != null && !date
						.equals(this.date))) {
			Date oldValue = this.date;
			this.date = date;
			firePropertyChange(DATE, oldValue, this.date);
			setEnabled(canRun());
		}
	}
}
