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

import java.util.Date;

import org.eclipse.core.databinding.BindingProperties;
import org.eclipse.core.databinding.beans.BeanProperties;
import org.eclipse.core.databinding.observable.map.IObservableMap;
import org.eclipse.core.databinding.observable.set.IObservableSet;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.databinding.observable.value.WritableValue;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.databinding.util.JFaceProperties;
import org.eclipse.jface.databinding.viewers.ObservableSetContentProvider;
import org.eclipse.jface.databinding.viewers.ViewersObservables;
import org.eclipse.jface.viewers.IOpenListener;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;

import com.patrikdufresne.jface.databinding.preference.PreferenceStoreProperties;
import com.patrikdufresne.jface.databinding.viewers.PropertyViewerComparator;
import com.patrikdufresne.planner.Planner;
import com.patrikdufresne.planner.databinding.PlannerProperties;
import com.patrikdufresne.planner.databinding.PlannerViewerUpdater;
import com.patrikdufresne.planner.viewer.PlannerViewer;
import com.patrikdufresne.util.Localized;
import com.planimod.core.AbstractCalendarEvent;
import com.planimod.core.PlanimodManagers;
import com.planimod.core.ProductionEvent;
import com.planimod.core.Shift;
import com.planimod.core.Team;
import com.planimod.core.comparators.ShiftComparators;
import com.planimod.ui.databinding.Converters;
import com.planimod.ui.databinding.DateColorControlStyleSupport;
import com.planimod.ui.databinding.manager.ShiftComputedSet;
import com.planimod.ui.preference.PlanimodPreferences;
import com.planimod.ui.viewers.planner.ObservableMapPlannerLabelProviderWithColor;
import com.planimod.ui.viewers.planner.PlanimodPlannerLook;
import com.planimod.ui.views.AbstractViewPart;
import com.planimod.ui.views.ChangeDateAction;

/**
 * This view part display planif information in a planner view.
 * 
 * @author Patrik Dufresne
 * 
 */
public class ProductionViewPart extends AbstractViewPart {
	/**
	 * Dot value (.)
	 */
	private static final String DOT = "."; //$NON-NLS-1$
	/**
	 * The part id.
	 */
	public static final String ID = "comp.planimod.ui.views.production.ProductionViewPart"; //$NON-NLS-1$

	private DuplicateProductionEventAction duplicateProductionEventAction;
	protected EditProductionEventAction editProductionAction;

	/**
	 * Used for localization.
	 */
	private Localized localized = Localized.load(ProductionViewPart.class);

	private ChangeDateAction nextAction;

	private ChangeDateAction previousAction;
	private RemoveAllProductionEventAction removeProductionEventAction;
	private ChangeDateAction todayAction;
	private PlannerViewer viewer;

	/**
	 * Create a new view part.
	 */
	public ProductionViewPart() {
		super(ID);
		setTitle(this.localized.get("ProductionViewPart.title")); //$NON-NLS-1$
	}

	/**
	 * This implementation add tool bar action and bin the view.
	 */
	@Override
	public void activate(Composite parent) {

		// Create the viewer
		this.viewer = createPlannerViewer(parent);
		this.viewer.getControl().setLayoutData(
				new GridData(SWT.FILL, SWT.FILL, true, true));

		// Populate the tool bar
		fillToolBar();

		// Create binding
		bind();

	}

	/**
	 * Binds the planner date selection to a shared state.
	 */
	@Override
	protected void bindValues() {
		super.bindValues();

		/*
		 * Get the states.
		 */
		WritableValue date = new WritableValue(null, Date.class);
		getDbc().bindValue(
				date,
				PreferenceStoreProperties.value(PlanimodPreferences.DATE,
						String.class).observe(
						PlanimodPreferences.getPreferenceStore()));
		if (date.getValue() == null) {
			date.setValue(new Date());
		}

		/*
		 * Bind date with planner date selection.
		 */
		Planner planner = this.viewer.getPlanner();
		getDbc().bindValue(PlannerProperties.dateSelection().observe(planner),
				date);
		IObservableValue start = PlannerProperties.startDateValue().observe(
				planner);
		IObservableValue end = PlannerProperties.endDateValue()
				.observe(planner);

		/*
		 * Bind the viewer.
		 */
		IObservableSet shifts = new ShiftComputedSet(getSite().getService(
				PlanimodManagers.class), start, end);
		IObservableMap shiftLabels = new ShiftProductionEventObservableMap(
				getSite().getService(PlanimodManagers.class), shifts);
		IObservableMap shiftStart = BeanProperties.value(
				AbstractCalendarEvent.class, AbstractCalendarEvent.START_DATE,
				Date.class).observeDetail(shifts);
		IObservableMap shiftEnd = BeanProperties.value(
				AbstractCalendarEvent.class, AbstractCalendarEvent.END_DATE,
				Date.class).observeDetail(shifts);
		IObservableMap color = BeanProperties
				.value(Shift.class, Shift.TEAM + DOT + Team.COLOR)
				.value(BindingProperties.convertedValue(Converters
						.StringToRGB())).observeDetail(shifts);

		this.viewer.setContentProvider(new ObservableSetContentProvider(
				new PlannerViewerUpdater(this.viewer)));
		this.viewer
				.setLabelProvider(new ObservableMapPlannerLabelProviderWithColor(
						shiftLabels, shiftStart, shiftEnd, color));
		this.viewer.setComparator(new PropertyViewerComparator(ShiftComparators
				.byHourAndTeam()));
		this.viewer.setInput(shifts);

		IObservableValue selectedShift = ViewersObservables
				.observeSingleSelection(this.viewer);

		/*
		 * Bind the planner background color.
		 */
		DateColorControlStyleSupport.create(this.viewer.getPlanner(), date);

		/*
		 * Bind actions
		 */
		this.previousAction.setDate(date);
		this.previousAction.setUnit(ChangeDateAction.UNIT_WEEK);
		this.todayAction.setDate(date);
		this.nextAction.setDate(date);
		this.nextAction.setUnit(ChangeDateAction.UNIT_WEEK);

		// Duplicate action
		getDbc().bindValue(
				JFaceProperties.value(DuplicateProductionEventAction.class,
						DuplicateProductionEventAction.DATE,
						DuplicateProductionEventAction.DATE).observe(
						this.duplicateProductionEventAction), date);

		// Edit action
		getDbc().bindValue(
				JFaceProperties.value(EditProductionEventAction.class,
						ProductionEvent.SHIFT, EditProductionEventAction.SHIFT)
						.observe(this.editProductionAction), selectedShift);

		// Remove action
		getDbc().bindValue(
				JFaceProperties.value(RemoveAllProductionEventAction.class,
						"date", //$NON-NLS-1$
						RemoveAllProductionEventAction.DATE).observe(
						this.removeProductionEventAction), date);

	}

	/**
	 * This implementation create a planner viewer.
	 */
	protected PlannerViewer createPlannerViewer(Composite parent) {

		PlannerViewer viewer = new PlannerViewer(parent);

		// sets planner look.
		viewer.getPlanner().setLook(new PlanimodPlannerLook());

		/**
		 * Add a listener to edit the events.
		 */
		viewer.addOpenListener(new IOpenListener() {
			@Override
			public void open(OpenEvent event) {
				ProductionViewPart.this.editProductionAction.run();
			}
		});

		return viewer;
	}

	/**
	 * This implementation free allocated resources.
	 */
	@Override
	public void deactivate() {
		try {
			this.duplicateProductionEventAction = null;
			this.editProductionAction = null;
			this.nextAction = null;
			this.previousAction = null;
			this.removeProductionEventAction = null;
			this.todayAction = null;
			this.viewer = null;
		} finally {
			super.deactivate();
		}
	}

	@Override
	public void dispose() {
		this.localized = null;
		super.dispose();
	}

	void fillToolBar() {

		IToolBarManager toolbar = getSite().getToolBarManager();
		/*
		 * Date navigation
		 */
		this.previousAction = ChangeDateAction.previousAction();
		this.todayAction = ChangeDateAction.todayAction();
		this.nextAction = ChangeDateAction.nextAction();
		toolbar.add(this.previousAction);
		toolbar.add(this.todayAction);
		toolbar.add(this.nextAction);

		/*
		 * Separator
		 */
		toolbar.add(new Separator());

		/*
		 * Edit events
		 */
		ActionContributionItem aci;
		toolbar.add(aci = new ActionContributionItem(
				this.editProductionAction = new EditProductionEventAction(
						getSite().getService(PlanimodManagers.class), getSite())));
		aci.setMode(ActionContributionItem.MODE_FORCE_TEXT);

		/*
		 * Remove events
		 */
		toolbar.add(aci = new ActionContributionItem(
				this.removeProductionEventAction = new RemoveAllProductionEventAction(
						getSite().getService(PlanimodManagers.class),
						getSite(), getSite().getMainWindow())));
		aci.setMode(ActionContributionItem.MODE_FORCE_TEXT);

		/*
		 * Copy events
		 */
		toolbar.add(aci = new ActionContributionItem(
				this.duplicateProductionEventAction = new DuplicateProductionEventAction(
						getSite().getService(PlanimodManagers.class),
						getSite(), getSite().getMainWindow())));
		aci.setMode(ActionContributionItem.MODE_FORCE_TEXT);

	}

}
