//------------------------------------------------------------------------------
// 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.actions;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.edit.provider.DelegatingWrapperItemProvider;
import org.eclipse.emf.edit.provider.IWrapperItemProvider;
import org.eclipse.emf.edit.provider.ItemProviderAdapter;
import org.eclipse.epf.authoring.ui.AuthoringUIPlugin;
import org.eclipse.epf.authoring.ui.AuthoringUIResources;
import org.eclipse.epf.authoring.ui.editors.IEditorKeeper;
import org.eclipse.epf.authoring.ui.views.LibraryView;
import org.eclipse.epf.common.serviceability.MsgBox;
import org.eclipse.epf.library.LibraryService;
import org.eclipse.epf.library.edit.FeatureValueWrapperItemProvider;
import org.eclipse.epf.library.edit.ui.UserInteractionHelper;
import org.eclipse.epf.library.edit.util.TngUtil;
import org.eclipse.epf.persistence.MultiFileResourceSetImpl;
import org.eclipse.epf.uma.CustomCategory;
import org.eclipse.epf.uma.MethodConfiguration;
import org.eclipse.epf.uma.MethodElement;
import org.eclipse.epf.uma.UmaPackage;
import org.eclipse.epf.uma.VariabilityElement;
import org.eclipse.epf.uma.util.AssociationHelper;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;

/**
 * Deletes an element in the Library view.
 * 
 * @author Phong Nguyen Le
 * @author Kelvin Low
 * @since 1.0
 */
public class LibraryViewDeleteAction extends MethodElementDeleteAction {

	/**
	 * @see MethodElementDeleteAction#didDelete(Collection)
	 */
	protected void didDelete(Collection deletedElements) {
		// Close all open editors associated with the deleted elements.
		for (Iterator iter = deletedElements.iterator(); iter.hasNext();) {
			Object element = TngUtil.unwrap(iter.next());
			if (element instanceof MethodElement
					&& ((MethodElement) element).eContainer() == null) {
				IEditorKeeper.REFERENCE.getEditorKeeper()
						.closeEditorsOnDeletion((MethodElement) element);
			}
		}
	}

	public boolean updateSelection(IStructuredSelection selection) {
		ArrayList filteredSelection = new ArrayList();

		for (Iterator iter = selection.iterator(); iter.hasNext();) {
			Object e = iter.next();
			Object element = TngUtil.unwrap(e);
			if (element instanceof ItemProviderAdapter
					|| (element instanceof MethodElement && TngUtil
							.isPredefined((MethodElement) element))) {
				continue;
			}
			if (element instanceof CustomCategory) {
				filterCustomCategorySelection(e, filteredSelection);
			} else {				
				if(e instanceof IWrapperItemProvider) {
					IWrapperItemProvider wrapper = (IWrapperItemProvider) e;
					if(wrapper.getValue() instanceof IWrapperItemProvider &&
							!(TngUtil.unwrap(wrapper.getOwner()) instanceof CustomCategory)) {
						// disallow deleting element when its reference in
						// CustomCategory tree
						// that is not directly under a CustomCategory is
						// selected
						//
						continue;
					}
					else if (wrapper.getFeature() == UmaPackage.Literals.DISCIPLINE_GROUPING__DISCIPLINES
							|| wrapper.getFeature() == UmaPackage.Literals.ROLE_SET_GROUPING__ROLE_SETS) {
						filteredSelection.add(element);
						continue;
					}
				}				
				filteredSelection.add(e);
			}
		}

		if (filteredSelection.isEmpty())
			return false;

		return super
				.updateSelection(new StructuredSelection(filteredSelection));
	}

	protected void performDelete() {
		HashSet configsToDelete = new HashSet();
		HashSet modifiedResources = new HashSet();
		if (selection != null && selection.size() > 0) {
			for (Iterator iter = selection.iterator(); iter.hasNext();) {
				Object object = TngUtil.unwrap(iter.next());
				if (object instanceof MethodConfiguration) {
					configsToDelete.add(object);
				}
				if (object instanceof EObject) {
					EObject container = ((EObject) object).eContainer();
					if (container != null && container.eResource() != null) {
						modifiedResources.add(container.eResource());
					}
				}
			}
		}

		// Avoid deleting the default configuration of a process.
		if (!configsToDelete.isEmpty()) {
			HashSet configGUIDsToDelete = new HashSet();
			for (Iterator iter = configsToDelete.iterator(); iter.hasNext();) {
				MethodConfiguration config = (MethodConfiguration) iter.next();
				configGUIDsToDelete.add(config.getGuid());
			}
			MultiFileResourceSetImpl resourceSet = (MultiFileResourceSetImpl) LibraryService
					.getInstance().getCurrentMethodLibrary().eResource()
					.getResourceSet();
			resourceSet
					.loadOppositeFeatures(
							Collections
									.singletonList(AssociationHelper.MethodConfiguration_DependentProcesses),
							configGUIDsToDelete);

			for (Iterator iter = configsToDelete.iterator(); iter.hasNext();) {
				MethodConfiguration config = (MethodConfiguration) iter.next();

				List references = AssociationHelper
						.getDependentProcesses(config);
				if (references != null && references.size() > 0) {
					String processName = ((org.eclipse.epf.uma.Process) references
							.get(0)).getName();
					AuthoringUIPlugin
							.getDefault()
							.getMsgDialog()
							.displayWarning(
									AuthoringUIResources.deleteDialog_title, //$NON-NLS-1$
									AuthoringUIResources.deleteConfigError_msg, //$NON-NLS-1$
									AuthoringUIResources
											.bind(
													AuthoringUIResources.deleteConfigError_reason,
													processName)); //$NON-NLS-1$
					return;
				}

			}

		}

		IStatus status = UserInteractionHelper.checkModify(modifiedResources,
				MsgBox.getDefaultShell());
		if (!status.isOK()) {
			AuthoringUIPlugin.getDefault().getMsgDialog().display(
					AuthoringUIResources.deleteDialog_title, //$NON-NLS-1$
					status);
			return;
		}

		if (confirmDelete()) {
			// Collect the information of Refreshable Objects
			// ( Reference Objects should be refreshed in navigation tree) -
			// RATLC00385835
			ArrayList refreshList = new ArrayList();
			for (Iterator iter = selection.iterator(); iter.hasNext();) {
				Object deletingObject = TngUtil.unwrap(iter.next());
				if (deletingObject instanceof MethodElement) {
					// check for variability
					if (deletingObject instanceof VariabilityElement) {
						for (Iterator iterator = TngUtil
								.getGeneralizers((VariabilityElement) deletingObject); iterator
								.hasNext();) {
							Object aReference = iterator.next();
							refreshList.add(aReference);
						}
					}
				}
			}

			// execute actual delete command.
			command.execute();

			// Refresh the refreshlist objects in navigation tree.
			if (refreshList.size() > 0) {
				TreeViewer viewer = ((TreeViewer) (LibraryView.getView()
						.getViewer()));
				for (Iterator iter = refreshList.iterator(); iter.hasNext();) {
					viewer.refresh(iter.next());
				}
			}
		}
	}

	/**
	 * @see org.eclipse.jface.action.Action#firePropertyChange(String, Object,
	 *      Object)
	 */
	public void notifyPropertyChange(String propertyName, Object oldValue,
			Object newValue) {
		super.firePropertyChange(propertyName, oldValue, newValue);
	}

	/*
	 * Handle the special case of customcategory Copy/Delete action If parent of
	 * customcategory selected, ignore the customcategory, otherwise compound
	 * command creates a command for parent and a command for child,
	 * CompoundCommand will execute both commands, command for parent will
	 * remove parent itself and removes child too, next it try to execute
	 * command for child, command will fail because child got remove in command
	 * for parent. 
	 * TODO: handle properly in RemoveCommand for this case instead here.
	 */

	public void filterCustomCategorySelection(Object e, List filteredSelection) {
		if (e instanceof FeatureValueWrapperItemProvider) {
			filteredSelection.add(e);
		} else {
			Object owner = ((DelegatingWrapperItemProvider) e).getOwner();
			while (owner instanceof DelegatingWrapperItemProvider) {
				if (owner instanceof FeatureValueWrapperItemProvider) {
					if (!filteredSelection.contains(owner)) {
						filteredSelection.add(e);
					}
					break;
				} else {
					if (filteredSelection.contains(owner))
						break;
					owner = ((DelegatingWrapperItemProvider) owner).getOwner();
					if (!(owner instanceof FeatureValueWrapperItemProvider)) {
						if (!filteredSelection.contains(owner)) {
							filteredSelection.add(e);
							break;
						}
					}
				}
			}
		}
	}

}