//------------------------------------------------------------------------------
// Copyright (c) 2005, 2006 IBM Corporation and others.
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// which accompanies this distribution, and is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// Contributors:
// IBM Corporation - initial implementation
//------------------------------------------------------------------------------
package org.eclipse.epf.authoring.ui.properties;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
import org.eclipse.epf.library.edit.IConfigurationApplicator;
import org.eclipse.epf.library.edit.Providers;
import org.eclipse.epf.library.edit.TngAdapterFactory;
import org.eclipse.epf.library.edit.command.IActionManager;
import org.eclipse.epf.library.edit.util.TngUtil;
import org.eclipse.epf.library.edit.util.VariabilityElementLabelProvider;
import org.eclipse.epf.uma.MethodConfiguration;
import org.eclipse.epf.uma.MethodElement;
import org.eclipse.epf.uma.TaskDescriptor;
import org.eclipse.epf.uma.UmaPackage;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Table;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.ListSelectionDialog;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;


/**
 * The task descriptor - step section
 * 
 * @author Shilpa Toraskar
 * @since 1.0
 * 
 */
public class TaskDescriptorStepSection extends AbstractSection {

	protected ILabelProvider labelProvider = new AdapterFactoryLabelProvider(
			TngAdapterFactory.INSTANCE
					.getNavigatorView_ComposedAdapterFactory());

	private TaskDescriptor element;

	private IActionManager actionMgr;

	private FormToolkit toolkit;

	private Button ctrl_add, ctrl_remove, ctrl_up, ctrl_down;

	private Table ctrl_selected;

	private TableViewer viewer;

	// private Text ctrl_brief_desc;
	private Image titleImage;

	/**
	 * @see org.eclipse.wst.common.ui.properties.ITabbedPropertySection#createControls(org.eclipse.swt.widgets.Composite,
	 *      org.eclipse.wst.common.ui.properties.TabbedPropertySheetPage)
	 */
	public void createControls(Composite parent,
			TabbedPropertySheetPage tabbedPropertySheetPage) {

		super.createControls(parent, tabbedPropertySheetPage);
		init();

		parent.setLayout(new GridLayout());
		parent.setLayoutData(new GridData(GridData.FILL_BOTH));

		// create steps section
		createStepSection(parent);

		addListeners();

	}

	private void init() {
		// get activity object
		element = (TaskDescriptor) getElement();

		// get toolkit
		toolkit = getWidgetFactory();

		// get action manager
		actionMgr = EPFPropertySheetPage.getActionManager();
	}

	/*
	 * @see org.eclipse.wst.common.ui.properties.view.ITabbedPropertySection#refresh()
	 */
	public void refresh() {
		try {
			if (getElement() instanceof TaskDescriptor) {
				element = (TaskDescriptor) getElement();
				viewer.refresh();

				// hide/refresh controls
				updateControls();
			}
		} catch (Exception ex) {
			logger.logError("Error refreshing TaskDescriptor step section" + element, ex); 
		}
	}

	public void dispose() {
		super.dispose();

		if (labelProvider != null) {
			labelProvider.dispose();
		}
	}

	public void updateControls() {
		ctrl_add.setEnabled(editable);
		IStructuredSelection selection = (IStructuredSelection) viewer
				.getSelection();
		if (selection.size() > 0 && editable) {
			ctrl_remove.setEnabled(editable);
			ctrl_up.setEnabled(editable);
			ctrl_down.setEnabled(editable);
		} else {
			ctrl_remove.setEnabled(false);
			ctrl_up.setEnabled(false);
			ctrl_down.setEnabled(false);

		}
	}

	private void createStepSection(Composite composite) {
		// create step section
		Section stepSection = FormUI
				.createSection(
						toolkit,
						composite,
						PropertiesResources.TaskDescriptor_stepInformationTitle, //$NON-NLS-1$
						PropertiesResources.TaskDescriptor_stepInformationDescription); //$NON-NLS-1$

		// create step composite
		Composite stepComposite = FormUI.createComposite(toolkit, stepSection,
				2, false);

		// create table composite
		Composite pane1 = FormUI.createComposite(toolkit, stepComposite,
				GridData.FILL_BOTH);
		FormUI.createLabel(toolkit, pane1, PropertiesResources.TaskDescriptor_Selected_Steps); //$NON-NLS-1$

		ctrl_selected = FormUI.createTable(toolkit, pane1);
		viewer = new TableViewer(ctrl_selected);

		IStructuredContentProvider contentProvider = new AdapterFactoryContentProvider(
				TngAdapterFactory.INSTANCE
						.getNavigatorView_ComposedAdapterFactory()) {
			public Object[] getElements(Object object) {
				return element.getSelectedSteps().toArray();
			}
		};

		viewer.setContentProvider(contentProvider);
		viewer.setLabelProvider(labelProvider);
		viewer.setInput(element);

		// create button composite
		Composite pane2 = FormUI.createComposite(toolkit, stepComposite,
				GridData.VERTICAL_ALIGN_CENTER
						| GridData.HORIZONTAL_ALIGN_CENTER);

		// create buttons
		ctrl_add = FormUI.createButton(toolkit, pane2, PropertiesResources.Process_Add); //$NON-NLS-1$
		ctrl_remove = FormUI.createButton(toolkit, pane2, PropertiesResources.Process_Remove); //$NON-NLS-1$
		ctrl_remove.setEnabled(false);
		ctrl_up = FormUI.createButton(toolkit, pane2, PropertiesResources.Process_Up); //$NON-NLS-1$
		ctrl_down = FormUI.createButton(toolkit, pane2, PropertiesResources.Process_Down); //$NON-NLS-1$

		// create brief description
		// int heightHint = 40;
		// int horizontalSpan = 2;
		// Label label = FormUI.createLabel(toolkit, stepComposite,
		// PropertiesResources.getString("Process.briefDescription"),
		// heightHint);
		// ctrl_brief_desc = FormUI.createText(toolkit, stepComposite,
		// heightHint, heightHint);
		// ctrl_brief_desc.setEditable(false);
		//		
		toolkit.paintBordersFor(stepComposite);
		toolkit.paintBordersFor(pane1);

	}

	private void addListeners() {
		// Add focus listener on primary tasks list
		ctrl_selected.addFocusListener(new FocusAdapter() {
			public void focusGained(FocusEvent e) {
				IStructuredSelection selection = (IStructuredSelection) viewer
						.getSelection();
				if ((selection.size() > 0) && editable) {
					ctrl_remove.setEnabled(editable);
					ctrl_up.setEnabled(editable);
					ctrl_down.setEnabled(editable);
				}
			}
		});

		viewer.addSelectionChangedListener(new ISelectionChangedListener() {

			public void selectionChanged(SelectionChangedEvent event) {
				IStructuredSelection selection = (IStructuredSelection) viewer
						.getSelection();
				if ((selection.size() > 0) && editable) {
					ctrl_remove.setEnabled(true);

					if (viewer.getTable().getSelectionIndex() > 0
							&& selection.size() == 1) {
						ctrl_up.setEnabled(true);
					} else
						ctrl_up.setEnabled(false);

					if (viewer.getTable().getSelectionIndex() < viewer
							.getTable().getItemCount() - 1
							&& selection.size() == 1) {
						ctrl_down.setEnabled(true);
					} else
						ctrl_down.setEnabled(false);

				}

				if (selection.size() == 1) {
					String desc = ((MethodElement) selection.getFirstElement())
							.getBriefDescription();
					if (desc == null) {
						desc = ""; //$NON-NLS-1$
					}
					// ctrl_brief_desc.setText(desc);
				} else if (selection.size() > 1) {
					// ctrl_brief_desc.setText(PropertiesResources.getString("Process.MultipleSelection")
					// + " - " + selection.size());
				}
			}
		});

		ctrl_add.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				IStructuredContentProvider stepContentProvider = new AdapterFactoryContentProvider(
						TngAdapterFactory.INSTANCE
								.getNavigatorView_ComposedAdapterFactory()) {
					public Object[] getElements(Object object) {

						// get all steps
						IConfigurationApplicator configApplicator = Providers
								.getConfigurationApplicator();
						MethodConfiguration config = TngUtil.getOwningProcess(
								element).getDefaultContext();
						List steps = (List) configApplicator.getReference(
								element.getTask(), UmaPackage.eINSTANCE
										.getTask_Steps(), config);

						// remove already existing steps
						steps.removeAll(element.getSelectedSteps());
						return steps.toArray();
					}
				};

				ILabelProvider stepLabelProvider = new VariabilityElementLabelProvider(
						TngAdapterFactory.INSTANCE
								.getNavigatorView_ComposedAdapterFactory()) {

					public boolean isExternal(Object obj) {

						boolean flag = !element.getTask().getPresentation()
								.getSections().contains(obj);
						return flag;
					}
				};

				ListSelectionDialog dlg = new ListSelectionDialog(PlatformUI
						.getWorkbench().getActiveWorkbenchWindow().getShell(),
						element.getTask(), stepContentProvider,
						stepLabelProvider, PropertiesResources.TaskDescriptor_StepDialogMessage); //$NON-NLS-1$
				titleImage = Display.getCurrent().getActiveShell().getImage();
				ListSelectionDialog.setDefaultImage(titleImage);
				dlg.setTitle(PropertiesResources.TaskDescriptor_StepDialogTitle); //$NON-NLS-1$
				dlg.setBlockOnOpen(true);
				dlg.open();

				addSteps(dlg.getResult());
				viewer.refresh();
			}
		});

		ctrl_remove.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				IStructuredSelection selection = (IStructuredSelection) viewer
						.getSelection();
				if (selection.size() > 0) {
					// update the model
					ArrayList rmItems = new ArrayList();
					rmItems.addAll(selection.toList());
					removeSteps(rmItems);
					viewer.refresh();

					// clear the selection
					viewer.setSelection(null, true);
					// ctrl_brief_desc.setText("");
				}
				// ctrl_remove.setEnabled(false);
			}
		});

		ctrl_up.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				ArrayList steps = new ArrayList();
				IStructuredSelection selection = (IStructuredSelection) viewer
						.getSelection();
				if (selection.size() > 0) {
					ArrayList items = new ArrayList();
					items.addAll(selection.toList());
					BasicEList stepList = (BasicEList) element
							.getSelectedSteps();

					for (Iterator it = items.iterator(); it.hasNext();) {
						Object object = it.next();
						int index = stepList.indexOf(object);
						if (index > 0)
							stepList.move(index - 1, object);

					}
					steps.addAll(stepList);
					// TODO - may be write a command. Hacking it for now to
					// activate dirty flag
					actionMgr.doAction(IActionManager.REMOVE_MANY, element,
							UmaPackage.eINSTANCE
									.getTaskDescriptor_SelectedSteps(),
							stepList, -1);
					actionMgr.doAction(IActionManager.ADD_MANY, element,
							UmaPackage.eINSTANCE
									.getTaskDescriptor_SelectedSteps(), steps,
							-1);

					viewer.refresh();
				}

				if (viewer.getTable().getSelectionIndex() > 0 && editable)
					ctrl_up.setEnabled(true);
				else
					ctrl_up.setEnabled(false);

				if (viewer.getTable().getSelectionIndex() < viewer.getTable()
						.getItemCount() - 1
						&& editable)
					ctrl_down.setEnabled(true);
				else
					ctrl_down.setEnabled(false);
			}

		});

		ctrl_down.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				ArrayList steps = new ArrayList();
				IStructuredSelection selection = (IStructuredSelection) viewer
						.getSelection();
				if (selection.size() > 0) {
					ArrayList items = new ArrayList();
					items.addAll(selection.toList());
					BasicEList stepList = (BasicEList) element
							.getSelectedSteps();

					for (Iterator it = items.iterator(); it.hasNext();) {
						Object object = it.next();
						int index = stepList.indexOf(object);

						if (index < stepList.size() - 1)
							stepList.move(index + items.size(), object);

					}
					steps.addAll(stepList);

					// TODO - write a cmmand. Hacking it for now to activate
					// dirty flag
					actionMgr.doAction(IActionManager.REMOVE_MANY, element,
							UmaPackage.eINSTANCE
									.getTaskDescriptor_SelectedSteps(),
							stepList, -1);
					actionMgr.doAction(IActionManager.ADD_MANY, element,
							UmaPackage.eINSTANCE
									.getTaskDescriptor_SelectedSteps(), steps,
							-1);

					viewer.refresh();
				}

				if (viewer.getTable().getSelectionIndex() > 0 && editable)
					ctrl_up.setEnabled(true);
				else
					ctrl_up.setEnabled(false);

				if (viewer.getTable().getSelectionIndex() < viewer.getTable()
						.getItemCount() - 1
						&& editable)
					ctrl_down.setEnabled(true);
				else
					ctrl_down.setEnabled(false);

			}

		});
	}

	private void addSteps(Object[] addItems) {
		// update the model
		if (addItems != null) {
			for (int i = 0; i < addItems.length; i++) {
				org.eclipse.epf.uma.Section item = (org.eclipse.epf.uma.Section) addItems[i];

				actionMgr.doAction(IActionManager.ADD, element,
						UmaPackage.eINSTANCE.getTaskDescriptor_SelectedSteps(),
						item, -1);
			}
		}
	}

	private void removeSteps(List rmItems) {
		// update the model
		if (!rmItems.isEmpty()) {
			for (Iterator it = rmItems.iterator(); it.hasNext();) {
				org.eclipse.epf.uma.Section item = (org.eclipse.epf.uma.Section) it.next();

				actionMgr.doAction(IActionManager.REMOVE, element,
						UmaPackage.eINSTANCE.getTaskDescriptor_SelectedSteps(),
						item, -1);
			}
		}
	}
}