/**
 * File:    CreateReferenceEdgeCommand.java
 * Created: 09.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.meta.commands.processes;

import java.util.Collections;

import org.eclipse.emf.common.command.AbstractCommand;
import org.eclipse.emf.common.command.CompoundCommand;
import org.eclipse.emf.edit.command.AddCommand;
import org.eclipse.emf.edit.command.SetCommand;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.jwt.meta.model.processes.ActivityEdge;
import org.eclipse.jwt.meta.model.processes.ActivityNode;
import org.eclipse.jwt.meta.model.processes.ProcessesPackage;
import org.eclipse.jwt.meta.model.processes.impl.ProcessesFactoryImpl;

/**
 * This command creates an ActivityEdge between two ActivityNodes.
 * 
 * @version $Id: CreateActivityEdgeCommand.java,v 1.2 2009/11/26 15:16:21 chsaad
 *          Exp $
 * @author Christian Saad (csaad@gmx.net), Programming distributed Systems Lab,
 *         University of Augsburg, Germany, www.ds-lab.org
 */
public class CreateActivityEdgeCommand extends AbstractCommand
{

	/**
	 * The EMF EditingDomain.
	 */
	private EditingDomain editingDomain;

	/**
	 * The source of the connection.
	 */
	private ActivityNode conSource;

	/**
	 * The target of the connection.
	 */
	private ActivityNode conTarget;

	/**
	 * EMF command to create the activity edge.
	 */
	private CompoundCommand createActivityEdgeCommand;

	/**
	 * Stores the maximum number of outgoing edges.
	 */
	private int maximumOutEdges = Integer.MAX_VALUE;

	/**
	 * Stores the maximum number of ingoing edges.
	 */
	private int maximumInEdges = Integer.MAX_VALUE;


	/**
	 * The constructor.
	 * 
	 * @param editingDomain
	 * @param maximumInEdges
	 * @param maximumOutEdges
	 */
	public CreateActivityEdgeCommand(EditingDomain editingDomain)
	{
		super();

		this.editingDomain = editingDomain;
	}


	/**
	 * Sets the maximumInEdges.
	 * 
	 * @param maximumInEdges
	 *            The maximumInEdges to set.
	 */
	public void setMaximumInEdges(int maximumInEdges)
	{
		this.maximumInEdges = maximumInEdges;
	}


	/**
	 * Sets the maximumOutEdges.
	 * 
	 * @param maximumOutEdges
	 *            The maximumOutEdges to set.
	 */
	public void setMaximumOutEdges(int maximumOutEdges)
	{
		this.maximumOutEdges = maximumOutEdges;
	}


	/**
	 * Sets the connection source.
	 * 
	 * @param source
	 */
	public void setSource(ActivityNode source)
	{
		conSource = source;
	}


	/**
	 * Sets the connection target.
	 * 
	 * @param source
	 */
	public void setTarget(ActivityNode target)
	{
		conTarget = target;
	}


	/**
	 * Checks if the max in/out limitations are ok.
	 * 
	 * @return If the max connection is valid.
	 */
	public boolean checkMaxInOutConnections()
	{
		// check number of ingoing edges
		if (conTarget != null && conTarget.getIn().size() >= maximumInEdges)
		{
			return false;
		}

		// check number of outgoing edges
		if (conSource != null && conSource.getOut().size() >= maximumOutEdges)
		{
			return false;
		}

		return true;
	}


	/**
	 * Checks if the connection is valid.
	 * 
	 * @return If the connection is valid.
	 */
	public boolean checkConnection()
	{
		// if action or reference is missing -> abort
		if (conSource == null || conTarget == null)
		{
			return false;
		}

		// if source node is the same as target -> abort
		if (conSource == conTarget)
		{
			return false;
		}

		// check the connection limitations
		return checkMaxInOutConnections();
	}


	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.eclipse.jwt.meta.model.commands.processes.ReconnectEdgeCommand#canExecute
	 * ()
	 */
	@Override
	public boolean canExecute()
	{
		if (editingDomain == null)
		{
			return false;
		}

		// check if the connection is valid
		return checkConnection();
	}


	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.eclipse.jwt.meta.model.commands.processes.ReconnectEdgeCommand#execute
	 * ()
	 */
	public void execute()
	{
		// create the activity edge
		ActivityEdge actEdge = ProcessesFactoryImpl.eINSTANCE.createActivityEdge();

		// create a command that sets the properties of the edge and adds it to
		// the scope
		createActivityEdgeCommand = new CompoundCommand();
		createActivityEdgeCommand.append(SetCommand.create(editingDomain, actEdge,
				ProcessesPackage.Literals.ACTIVITY_EDGE__SOURCE, conSource));
		createActivityEdgeCommand.append(SetCommand.create(editingDomain, actEdge,
				ProcessesPackage.Literals.ACTIVITY_EDGE__TARGET, conTarget));
		createActivityEdgeCommand.append(AddCommand.create(editingDomain, conSource
				.eContainer(), ProcessesPackage.Literals.SCOPE__EDGES, Collections
				.singleton(actEdge)));

		// execute the command
		if (createActivityEdgeCommand.canExecute())
		{
			createActivityEdgeCommand.execute();
		}
	}


	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.emf.common.command.AbstractCommand#undo()
	 */
	@Override
	public void undo()
	{
		// undo the creation of the activity edge
		createActivityEdgeCommand.undo();
	}


	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.emf.common.command.Command#redo()
	 */
	public void redo()
	{
		// redo the activity edge
		createActivityEdgeCommand.redo();
	}


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

		if (createActivityEdgeCommand != null)
		{
			createActivityEdgeCommand.dispose();
		}
	}

}