//------------------------------------------------------------------------------
// 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.library.edit.process.command;

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

import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.command.CompoundCommand;
import org.eclipse.emf.common.command.IdentityCommand;
import org.eclipse.emf.common.command.UnexecutableCommand;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.edit.command.DragAndDropCommand;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.epf.library.edit.command.IResourceAwareCommand;
import org.eclipse.epf.library.edit.command.ResourceAwareCompoundCommand;
import org.eclipse.epf.library.edit.ui.ExposedAdapterFactoryContentProvider;
import org.eclipse.epf.library.edit.util.ExposedAdapterFactory;
import org.eclipse.epf.library.edit.util.ProcessUtil;
import org.eclipse.epf.library.edit.util.TngUtil;
import org.eclipse.epf.uma.Activity;
import org.eclipse.epf.uma.BreakdownElement;
import org.eclipse.epf.uma.CapabilityPattern;
import org.eclipse.epf.uma.DeliveryProcess;
import org.eclipse.epf.uma.Process;
import org.eclipse.epf.uma.ProcessComponent;
import org.eclipse.jface.viewers.Viewer;


/**
 * Abstract drag and drop command for process authoring
 * 
 * @author Phong Nguyen Le
 * @author Shilpa Toraskar
 * @since 1.0
 */
public abstract class BSDragAndDropCommand extends DragAndDropCommand implements
		IResourceAwareCommand {

	/**
	 * @param domain
	 * @param owner
	 * @param location
	 * @param operations
	 * @param operation
	 * @param collection
	 */
	public BSDragAndDropCommand(EditingDomain domain, Object owner,
			float location, int operations, int operation, Collection collection) {
		super(domain, owner, location, operations, operation, collection);
	}

	protected boolean prepareDropCopyOn() {
		return prepareDropLinkOn();
	}

	protected boolean prepareDropLinkOn() {
		dragCommand = IdentityCommand.INSTANCE;
		dropCommand = UnexecutableCommand.INSTANCE;

		ArrayList list = new ArrayList();
		ArrayList actList = new ArrayList();
		for (Iterator iter = collection.iterator(); iter.hasNext();) {
			Object obj = iter.next();
			obj = TngUtil.unwrap(obj);
			if (TngUtil.isLocked((EObject) owner))
				return false;
			if (accept(obj)) {
				list.add(obj);
			}
			// else if(obj instanceof Process) {
			// // disallow drop a process as an activity
			// }
			else if (obj instanceof Activity) {
				Process srcProc = TngUtil
						.getOwningProcess((BreakdownElement) obj);
				Process targetProc = TngUtil
						.getOwningProcess((BreakdownElement) owner);

				if (!(srcProc instanceof DeliveryProcess && targetProc instanceof CapabilityPattern)) {
					actList.add(obj);
				}
				
				if ((ProcessUtil.hasCyclicDependency((Activity) obj, targetProc))){
					return false;
				}
			}
		}

		boolean result;
		if (list.isEmpty() && actList.isEmpty()) {
			result = false;
		} else {
			CompoundCommand cmd = new ResourceAwareCompoundCommand();
			if (!list.isEmpty()) {
				cmd.append(createDropCommand(owner, list));
			}
			if (!actList.isEmpty()) {
				if (owner instanceof Activity)
					cmd.append(new ActivityDropCommand((Activity) owner, actList,
						getTargetViewer(), ((AdapterFactoryEditingDomain)domain).getAdapterFactory()));
			}
			dropCommand = cmd;
			result = dropCommand.canExecute();
		}
		return result;
	}

	private Viewer getTargetViewer() {
		if (domain instanceof AdapterFactoryEditingDomain) {
			Process proc = TngUtil.getOwningProcess((BreakdownElement) owner);
			AdapterFactory adapterFactory = ((AdapterFactoryEditingDomain) domain)
					.getAdapterFactory();
			if (adapterFactory instanceof ExposedAdapterFactory) {
				for (Iterator iter = Collections.unmodifiableList(
						((ExposedAdapterFactory) adapterFactory)
								.getChangeListeners()).iterator(); iter
						.hasNext();) {
					Object listener = iter.next();
					if (listener instanceof ExposedAdapterFactoryContentProvider) {
						Viewer viewer = ((ExposedAdapterFactoryContentProvider) listener)
								.getViewer();
						if (viewer.getInput() instanceof ProcessComponent
								&& ((ProcessComponent) viewer.getInput())
										.getProcess() == proc)
							return viewer;
					}
				}
			}
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.ibm.library.edit.command.IResourceAwareCommand#getModifiedResources()
	 */
	public Collection getModifiedResources() {
		if (dropCommand instanceof IResourceAwareCommand) {
			return ((IResourceAwareCommand) dropCommand).getModifiedResources();
		}
		return Collections.EMPTY_LIST;
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.emf.edit.command.DragAndDropCommand#getAffectedObjects()
	 */
	public Collection getAffectedObjects() {
		return dropCommand.getAffectedObjects();		
	}

	protected abstract boolean accept(Object obj);

	protected abstract Command createDropCommand(Object owner, List dropSrc);

}
