//------------------------------------------------------------------------------
// 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.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.edit.command.CopyCommand;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.epf.library.edit.LibraryEditPlugin;
import org.eclipse.epf.library.edit.LibraryEditResources;
import org.eclipse.epf.uma.Activity;
import org.eclipse.epf.uma.ProcessComponent;
import org.eclipse.epf.uma.ProcessPackage;
import org.eclipse.epf.uma.UmaFactory;
import org.eclipse.epf.uma.edit.domain.TraceableAdapterFactoryEditingDomain;


/**
 * @author Phong Nguyen Le - Sep 16, 2005
 * @since 1.0
 */
public class ActivityAddCommand extends ProcessElementAddCommand {
	private List procPackages;

	/**
	 * @param command
	 */
	public ActivityAddCommand(Command command) {
		super(command);
	}

	private Map getCopyToOriginalMap() {
		EditingDomain ed = addCommand.getDomain();
		if (ed instanceof TraceableAdapterFactoryEditingDomain) {
			return ((TraceableAdapterFactoryEditingDomain) ed)
					.getCopyToOriginalMap();
		}
		return null;
	}

	private void copyProcessPackages() {
		if (procPackages == null) {
			Map copyToOriginalMap = getCopyToOriginalMap();
			if (copyToOriginalMap != null) {
				boolean showWarning = false;
				procPackages = new ArrayList();

				// check first element of addCommand.getCollection()
				// if it's a key in the CopyToOriginalMap, we are pasting and
				// may need to warn the user
				// if it's not a key in the CopyToOriginalMap, then we are
				// probably adding a new element
				if (addCommand.getCollection() != null
						&& addCommand.getCollection().size() > 0
						&& copyToOriginalMap.containsKey(addCommand
								.getCollection().toArray()[0])) {
					for (Iterator iter = addCommand.getCollection().iterator(); iter
							.hasNext();) {
						Object element = iter.next();
						if (element instanceof Activity) {
							Activity orig = (Activity) copyToOriginalMap
									.get(element);
							if (orig != null) {
								if (orig.eContainer() != null) {
									procPackages.add(orig.eContainer());
								}
							} else {
								showWarning = true;
							}
						}
					}
				}

				if (showWarning) {
					// warning
					LibraryEditPlugin
							.getDefault()
							.getMsgDialog()
							.displayWarning(
									getLabel(),
									LibraryEditResources.ActivityAddCommand_originalNotFoundWarning_msg); //$NON-NLS-1$
				}

				if (!procPackages.isEmpty()) {
					// copy the ProcessPackage of the original Activity to add
					// it to the ProcessPackage
					// of the target Activity.
					//
					// AdapterFactoryEditingDomain editingDomain = new
					// AdapterFactoryEditingDomain(TngAdapterFactory.INSTANCE.getProcessComposedAdapterFactory()
					// , new BasicCommandStack());
					Command command = CopyCommand.create(
							addCommand.getDomain(), procPackages);
					try {
						command.execute();

						// Refresh the AddCommand.collection with new copies.
						//
						Collection activities = addCommand.getCollection();
						activities.clear();

						for (Iterator iter = command.getResult().iterator(); iter
								.hasNext();) {
							ProcessPackage copy = (ProcessPackage) iter.next();
							if (copy instanceof ProcessComponent) {
								Activity actCopy = ((ProcessComponent) copy)
										.getProcess();
								// copy data from ProcessComponent to a new
								// ProcessPackage
								ProcessPackage pkgCopy = UmaFactory.eINSTANCE
										.createProcessPackage();
								pkgCopy.setName(actCopy.getName());
								pkgCopy.getProcessElements().add(actCopy);
								pkgCopy.getProcessElements().addAll(
										copy.getProcessElements());
								pkgCopy.getDiagrams()
										.addAll(copy.getDiagrams());
								pkgCopy.getChildPackages().addAll(
										copy.getChildPackages());

								activities.add(actCopy);
							} else {
								find_activity: for (Iterator iterator = copy
										.getProcessElements().iterator(); iterator
										.hasNext();) {
									Object element = iterator.next();
									if (element instanceof Activity) {
										activities.add((Activity) element);
										break find_activity;
									}
								}
							}
						}
					} finally {
						if (command != null) {
							command.dispose();
						}
					}
				}
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.ibm.library.edit.command.MethodElementAddCommand#execute()
	 */
	public void execute() {
		prepareAddList();
		copyProcessPackages();
		super.execute();
	}

	/**
	 * Checks if e is a child, direct or of act
	 * 
	 * @param act
	 * @param e
	 * @return
	 */
	private static boolean isChildOf(Object parent, Object e) {
		if (parent instanceof Activity) {
			Activity act = (Activity) parent;
			for (Iterator iter = act.getBreakdownElements().iterator(); iter
					.hasNext();) {
				Object child = iter.next();
				if (e == child) {
					return true;
				}
				if (isChildOf(child, e)) {
					return true;
				}
			}
		}
		// else if(parent instanceof WorkProductDescriptor) {
		// WorkProduct wp = ((WorkProductDescriptor)parent).getWorkProduct();
		// if(wp instanceof Artifact) {
		// if(e instanceof WorkProductDescriptor) {
		// if(UmaUtil.isContainedBy(((WorkProductDescriptor)e).getWorkProduct(),
		// wp)) {
		// return true;
		// }
		// }
		// }
		// }
		return false;
	}

	private static boolean isChildOf(Collection elements, Object e) {
		for (Iterator iter = elements.iterator(); iter.hasNext();) {
			if (isChildOf(iter.next(), e)) {
				return true;
			}
		}
		return false;
	}

	private void prepareAddList() {
		// cleanup element list before adding it to the activity to avoid adding
		// elements multiple times
		//
		Map copyToOriginalMap = getCopyToOriginalMap();
		if (copyToOriginalMap != null) {
			ArrayList originals = new ArrayList();
			Map originalToCopyMap = new HashMap();
			for (Iterator iter = addCommand.getCollection().iterator(); iter
					.hasNext();) {
				Object element = iter.next();
				Object original = copyToOriginalMap.get(element);
				if (original != null) {
					originals.add(original);
					originalToCopyMap.put(original, element);
				}
			}

			ArrayList removeList = new ArrayList();
			// ArrayList addList = new ArrayList();
			for (Iterator iter = originals.iterator(); iter.hasNext();) {
				Object element = iter.next();
				if (isChildOf(originals, element)) {
					removeList.add(originalToCopyMap.get(element));
				}
			}
			addCommand.getCollection().removeAll(removeList);
		}
	}

}
