/**
 * File:    WECutToClipboardCommand.java
 * Created: 14.06.2008
 *
 *
/*******************************************************************************
 * Copyright (c) 2005-2011
 * University of Augsburg, Germany <www.ds-lab.org>
 *
 * 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:
 *    Markus Bauer, Programming distributed Systems Lab, University of Augsburg 
 *    	- initial API and implementation
 *    Christian Saad, Programming distributed Systems Lab, University of Augsburg 
 *    	- rewrote from scratch
 *******************************************************************************/

package org.eclipse.jwt.we.commands.clipboard;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.edit.command.RemoveCommand;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.jwt.meta.commands.clipboard.JWTCutToClipboardCommand;
import org.eclipse.jwt.meta.model.processes.ActivityEdge;
import org.eclipse.jwt.we.editors.WEEditor;
import org.eclipse.jwt.we.misc.util.EMFHelper;
import org.eclipse.jwt.we.misc.views.LayoutDataManager;
import org.eclipse.jwt.we.model.view.ReferenceEdge;

/**
 * This is a custom CutToClipboard command, that: 1. does not place the original
 * elements into the clipboard but copies 2. also copies the edges that exist
 * between these elemets into the clipboard 3. aborts, if still referenced
 * elements are affected (RefElems, Activities)
 * 
 * @version $Id: CustomCutToClipboardCommand.java,v 1.2.2.1 2009/01/20 15:25:38
 *          chsaad Exp $
 * @author Christian Saad (csaad@gmx.net), Programming distributed Systems Lab,
 *         University of Augsburg, Germany, www.ds-lab.org
 */
public class WECutToClipboardCommand extends JWTCutToClipboardCommand
{

	/**
	 * The workflow editor.
	 */
	private WEEditor weeditor;


	/**
	 * The constructor.
	 * 
	 * @param domain
	 * @param command
	 */
	public WECutToClipboardCommand(WEEditor weeditor, EditingDomain domain,
			Command command)
	{
		super(domain, command);

		this.weeditor = weeditor;
	}


	/**
	 * This method searches the command for all (recursively) contained remove
	 * commands and adds all objects which should be deleted to a collection.
	 * Then, all edges are added to this collection which exist between objects
	 * in the collection.
	 * 
	 * @return A list of objects to be removed, including the edges between the
	 *         objects.
	 */
	private Set getAffectedObjectsForClipboard()
	{
		// search recursively for remove commands contained in the given command
		Set removeCommands = getAllRemoveCommandsRecursively(command);

		// all objects to be deleted except ReferenceEdges and ActivityEdges
		Set affectedObjects = new HashSet();
		for (Iterator iterator = removeCommands.iterator(); iterator.hasNext();)
		{
			RemoveCommand removeCommand = (RemoveCommand) iterator.next();

			for (Iterator iterator2 = removeCommand.getCollection().iterator(); iterator2
					.hasNext();)
			{
				EObject object = (EObject) iterator2.next();

				if (!(object instanceof ActivityEdge)
						&& !(object instanceof ReferenceEdge))
				{
					affectedObjects.add(object);
				}
			}
		}

		affectedObjects.addAll(EMFHelper.getAllContainedReferences(weeditor,
				affectedObjects));
		affectedObjects.addAll(EMFHelper.getAllContainedReferenceEdges(weeditor,
				affectedObjects));

		// add all edges which exist between the affected objects
		affectedObjects.addAll(EMFHelper.getAffectedEdges(affectedObjects));

		// get all layoutdata of the relevant objects
		affectedObjects.addAll(LayoutDataManager.getAllContainedLayoutDatas(weeditor,
				affectedObjects));

		Set containerPresent = new HashSet();
		for (Iterator iterator = affectedObjects.iterator(); iterator.hasNext();)
		{
			Object object = iterator.next();
			if (!(object instanceof EObject))
			{
				continue;
			}

			// check if the container of the object is in the list
			EObject container = ((EObject) object).eContainer();
			while (container != null)
			{
				if (affectedObjects.contains(container))
				{
					containerPresent.add(object);
					break;
				}
				container = container.eContainer();
			}
		}

		affectedObjects.removeAll(containerPresent);

		return affectedObjects;
	}


	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.emf.edit.command.CutToClipboardCommand#execute()
	 */
	@Override
	public void execute()
	{
		// get all objects to be removed, including all edges which exist
		// between them
		Set affectedObjects = getAffectedObjectsForClipboard();

		// save old clipboard and place a copy of the affected objects in the
		// clipboard
		// (also unset refElement features of actions, if the corresponding
		// ReferenceEdge/Reference is not present in the clipboard)
		if (domain != null)
		{
			oldClipboard = domain.getClipboard();

			Collection copy = EcoreUtil.copyAll(affectedObjects);
			EMFHelper.unsetUnconnectedRefElements(weeditor, copy);
			domain.setClipboard(copy);
		}

		// execute remove command (from CommandWrapper: super.super.execute)
		if (command != null)
		{
			command.execute();
		}
	}


	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.emf.edit.command.CutToClipboardCommand#redo()
	 */
	@Override
	public void redo()
	{
		// get all objects to be removed, including all edges which exist
		// between them
		Set affectedObjects = getAffectedObjectsForClipboard();

		// save old clipboard and place a copy of the affected objects in the
		// clipboard (also unset refElement features of actions, if the
		// corresponding ReferenceEdge/Reference is not present in the
		// clipboard)
		if (domain != null)
		{
			oldClipboard = domain.getClipboard();

			Collection copy = EcoreUtil.copyAll(affectedObjects);
			EMFHelper.unsetUnconnectedRefElements(weeditor, copy);
			domain.setClipboard(copy);
		}

		// execute remove command (from CommandWrapper: super.super.execute)
		if (command != null)
		{
			command.redo();
		}
	}


	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.emf.common.command.CommandWrapper#undo()
	 */
	@Override
	public void undo()
	{
		super.undo();
	}

}