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

import java.lang.reflect.InvocationTargetException;
import java.util.List;

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

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

/**
 * This action intend to print the planif week transfert.
 * 
 * @author Patrik Dufresne
 * 
 */
public class PlanifWeekTransfertPrintAction extends PrintAction {

	/**
	 * The maximum number of previous week to search in. (value 5)
	 */
	private static final int MAX_PREVIOUS_WEEK = 6;

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

	/**
	 * Context to use.
	 */
	private GeneratePlanifContext context;

	/**
	 * Create a new print action.
	 * 
	 * @param context
	 * @param shell
	 * @param operation
	 * @param runnableContext
	 */
	public PlanifWeekTransfertPrintAction(GeneratePlanifContext context,
			IShellProvider shell, int operation,
			IRunnableContext runnableContext) {
		super(shell, new PlanifWeekTransfertPrintFactory(), operation,
				runnableContext);
		if (context == null) {
			throw new NullPointerException();
		}
		this.context = context;
		setPrefKey(PREF_KEY);
		setPreferenceStore(PlanimodPreferences.getPreferenceStore());
		setEnabled(canRun());
		if (operation == PRINT_ACTION) {
			setText(Localized.get(PlanifWeekTransfertPrintAction.class,
					"PlanifWeekTransfertPrintAction.print")); //$NON-NLS-1$
		} else {
			setText(Localized.get(PlanifWeekTransfertPrintAction.class,
					"PlanifWeekTransfertPrintAction.preview")); //$NON-NLS-1$
		}
	}

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

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

	/**
	 * This implementation set the employee to print
	 * 
	 * @param factory
	 *            the factory
	 */
	@Override
	protected void initFactory(IPrintFactory factory)
			throws InvocationTargetException {

		// Get date from state
		if (this.context == null) {
			return;
		}

		// Get matching event for the time range.
		try {
			// Sets subtitle
			String customerName = getManagers().getApplicationSettingManager()
					.getByName(ApplicationSetting.CUSTOMER_NAME);
			((PlanimodPrintFactory) factory).setSubTitle(customerName);

			// Query the first day of week
			int firstDayOfWeek = this.context.getManagers()
					.getApplicationSettingManager().getFirstDayOfWeek();

			// The previous week may not have any data to compare with, if so,
			// we still need to find week with previous data. Find the previous
			// week with data. To avoid infinite loop, limit the search to 5
			// weeks. See bug #135.

			int count = 0;
			List<Task> tasks;
			TimeRange range = new ConcreteTimeRange(this.context.getStart(),
					this.context.getEnd());
			do {
				// Increase the week count
				count++;

				range = TimeRanges.previousWeek(range, firstDayOfWeek);

				// Query data
				tasks = this.context.getManagers().getTaskManager()
						.list(range.getStartDate(), range.getEndDate());
				// Continue if their wasn't any data.
			} while (tasks.size() == 0 && count < MAX_PREVIOUS_WEEK);

			// Check if we have found any data in the five previous week.
			if (tasks.size() == 0) {
				// Display an error message ?
				throw new InvocationTargetException(
						new RuntimeException(
								Localized
										.format(PlanifWeekTransfertPrintAction.class,
												"PlanifWeekTransfertPrintAction.noPreviousWeek", //$NON-NLS-1$
												MAX_PREVIOUS_WEEK)));
			}

			// Query the current week.
			tasks.addAll(this.context.getManagers().getTaskManager()
					.list(this.context.getStart(), this.context.getEnd()));

			// Sets the tasks to the print factory
			((PlanifWeekTransfertPrintFactory) factory).setTasks(tasks);

			// Query the non-availabilities for previous week.
			List<NonAvailability> nonAvailabilities = this.context
					.getManagers().getNonAvailabilityManager()
					.list(range.getStartDate(), range.getEndDate());
			// Query non-availabilities for current week
			nonAvailabilities.addAll(this.context.getManagers()
					.getNonAvailabilityManager()
					.list(this.context.getStart(), this.context.getEnd()));

			// Sets the non-availabilities to the print factory
			((PlanifWeekTransfertPrintFactory) factory)
					.setNonAvailabilties(nonAvailabilities);

		} catch (ManagerException e) {
			PlanimodPolicy.showException(e);
		}
	}

}
