/**
 * File:    InterruptibleCommandStack.java
 * Created: 18.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:
 *    Christian Saad, Programming distributed Systems Lab, University of Augsburg 
 *    	- initial API and implementation
 *******************************************************************************/

package org.eclipse.jwt.we.commands.editdomain.internal;

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

import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CommandStack;
import org.eclipse.jwt.meta.commands.interfaces.IInterruptibleCommand;
import org.eclipse.jwt.we.commands.gefEmfAdapter.EmfToGefCommandAdapter;

/**
 * This command stack allows the execution of interruptible commands, i.e.
 * commands that implement the IInterruptibleCommand interface. It works with
 * GEF commands as well as with wrapped EMF commands and compound commands of
 * both types. If a command implements the interface, then prior to its
 * execution its method checkIfCommandCanBeExecuted() is called. If this method
 * returns false, the command will not be executed which means it doesn't appear
 * on the command stack. This is a convenient method to realize extensive checks
 * in commands, that should only be executed once.
 * 
 * @version $Id: InterruptibleCommandStack.java,v 1.4 2009/11/26 12:41:38 chsaad
 *          Exp $
 * @author Christian Saad (csaad@gmx.net), Programming distributed Systems Lab,
 *         University of Augsburg, Germany, www.ds-lab.org
 */
public class InterruptibleCommandStack extends CommandStack
{

	/**
	 * Returns a list of all interruptible commands contained in a command
	 * (recursively), including the command itself.
	 * 
	 * @param command
	 * @return A set of all IInterruptibleCommands.
	 */
	private Set getAllInterruptibleCommandsRecursively(Object command)
	{
		// extract emf command from emftogefcommandadapter
		if (command instanceof EmfToGefCommandAdapter)
		{
			command = ((EmfToGefCommandAdapter) command).getEmfCommand();
		}

		Set commands = new HashSet();

		// add command if its an interruptible command
		if (command instanceof IInterruptibleCommand)
		{
			commands.add(command);
		}
		// follow gef compound commands recursively
		else if (command instanceof org.eclipse.gef.commands.CompoundCommand)
		{
			for (Iterator iteratorC = ((org.eclipse.gef.commands.CompoundCommand) command)
					.getCommands().iterator(); iteratorC.hasNext();)
			{
				commands.addAll(getAllInterruptibleCommandsRecursively(iteratorC.next()));
			}
		}
		// follow emf compound commands recursively
		else if (command instanceof org.eclipse.emf.common.command.CompoundCommand)
		{
			for (Iterator iteratorC = ((org.eclipse.emf.common.command.CompoundCommand) command)
					.getCommandList().iterator(); iteratorC.hasNext();)
			{
				commands.addAll(getAllInterruptibleCommandsRecursively(iteratorC.next()));
			}
		}

		return commands;
	}


	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.eclipse.gef.commands.CommandStack#execute(org.eclipse.gef.commands
	 * .Command)
	 */
	@Override
	public void execute(Command command)
	{
		Set interruptibleCommands = getAllInterruptibleCommandsRecursively(command);

		// if command is instance of IInterruptibleCommand, run pre-execution
		// check and
		// execute command only if this check returns true (otherwise it will
		// not be
		// executed and therefore not be put onto the command stack)
		for (Iterator iterator = interruptibleCommands.iterator(); iterator.hasNext();)
		{
			IInterruptibleCommand interruptibleCommand = (IInterruptibleCommand) iterator
					.next();

			// all interruptible commands must return true to to trigger
			// execution
			if (!interruptibleCommand.checkIfCommandCanBeExecuted())
			{
				return;
			}
		}

		super.execute(command);
	}

}
