/**
 * File:    EMFHelper.java
 * Created: 19.01.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.helper;

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

import org.eclipse.emf.ecore.EObject;
import org.eclipse.jwt.meta.PluginProperties;
import org.eclipse.jwt.meta.model.core.NamedElement;
import org.eclipse.jwt.meta.model.core.ReferenceableElement;
import org.eclipse.jwt.meta.model.processes.Activity;
import org.eclipse.jwt.meta.model.processes.ActivityEdge;
import org.eclipse.jwt.meta.model.processes.ActivityLinkNode;
import org.eclipse.jwt.meta.model.processes.ActivityNode;


/**
 * This class contains a set of static functions for handling model objects that are used
 * as references for other objects (ReferenceableElement for Reference, Activity for
 * ActivityLinkNode).
 * 
 * @version $Id: CommandHelper.java,v 1.3 2009-11-26 15:16:51 chsaad Exp $
 * @author Christian Saad (csaad@gmx.net), Programming distributed Systems Lab, University
 *         of Augsburg, Germany, www.ds-lab.org
 */
public class CommandHelper
{

	/**
	 * Returns the root element of the model.
	 * 
	 * @return The root element.
	 */
	public static EObject getRoot(EObject object)
	{
		EObject parent = object;

		while (parent.eContainer() != null)
		{
			parent = parent.eContainer();
		}

		return parent;
	}


	/**
	 * Returns a string that contains a list of all names of the given set of
	 * NamedElements.
	 * 
	 * @param elements
	 *            A list of NamedElements
	 * @return String that contains all names of the Elements.
	 */
	public static String collectNames(Set elements)
	{
		String nameString = ""; //$NON-NLS-1$

		// collect names
		for (Iterator iterator = elements.iterator(); iterator.hasNext();)
		{
			EObject element = (EObject) iterator.next();

			// only for named elements
			if (element instanceof NamedElement)
			{
				// get name
				String name = ((NamedElement) element).getName();
				if (name == null || name.equals("")) //$NON-NLS-1$
				{
					name = PluginProperties.model_Unnamed_name; //$NON-NLS-1$
				}

				// add to string
				nameString += "'" + PluginProperties.model_type(element) + ": " + name //$NON-NLS-1$ //$NON-NLS-2$
						+ "'  "; //$NON-NLS-1$
			}
		}

		// remove unnecessary ", " from the end of the string
		if (nameString != null && nameString.length() > 3)
		{
			nameString = nameString.substring(0, nameString.length() - 2);
		}

		return nameString;
	}


	/**
	 * Checks a given list of Activites depending on whether they are still referenced
	 * somewhere in the model. A list of the subset of relevant elements is returned that
	 * are still referenced, or with returnReferences, the references (ActivityLinkNodes,
	 * References) themselves.
	 * 
	 * @param relevantElements
	 *            The elements which should be tested
	 * @param returnReferences
	 *            Returns the references instead of the referenced elements.
	 * @return Collection of ReferenceableElements and Activities which are still
	 *         referenced somewhere.
	 */
	public static Set collectReferencedElements(Set relevantElements, EObject root,
			boolean returnReferences)
	{
		Set result = new HashSet();

		// iterate over all contents to search for activitylinknodes
		for (Iterator iter = root.eAllContents(); iter.hasNext();)
		{
			EObject eobject = (EObject) iter.next();

			// check if referenced activitylinknode->activity should be deleted
			if (eobject instanceof ActivityLinkNode)
			{
				Activity activity = ((ActivityLinkNode) eobject).getLinksto();
				if (relevantElements.contains(activity))
				{
					if (returnReferences)
					{
						result.add(eobject);
					}
					else
					{
						result.add(activity);
					}
				}
			}
		}

		// returns the list of activities/refelems that are still referenced
		return result;
	}


	/**
	 * Collects all Activities and ReferenceableElements for the given EObject
	 * (recursively if necessary).
	 * 
	 * @param rootObject
	 *            The root for the recursive search
	 * @return All ReferenceableElements and Activities contained in the root object.
	 */
	public static Set collectRelevantElements(EObject rootObject)
	{
		Set result = new HashSet();

		if (rootObject instanceof Activity)
		{
			result.add(rootObject);
		}
		// referenceable element: add to list
		else if (rootObject instanceof ReferenceableElement)
		{
			result.add(rootObject);
		}

		for (Iterator iter = rootObject.eAllContents(); iter.hasNext();)
		{
			EObject eobject = (EObject) iter.next();

			if (eobject instanceof Activity)
			{
				result.add(eobject);
			}
			// referenceable element: add to list
			else if (eobject instanceof ReferenceableElement)
			{
				result.add(eobject);
			}
		}

		return result;
	}


	/**
	 * This method iterates over the input collection of objects and returns all
	 * ActivityEdges in the model that exist between the contained elements, even if the
	 * edges themselves are not in the collection.
	 * 
	 * @param affectedObjects
	 * @return The set of edges which exist between the objects.
	 */
	public static Set getAffectedEdges(Collection affectedObjects)
	{
		Set affectedEdges = new HashSet();

		for (Iterator iterator = affectedObjects.iterator(); iterator.hasNext();)
		{
			EObject object = (EObject) iterator.next();

			// Check ActivityNode.In & ActivityNode.Out
			if (object instanceof ActivityNode)
			{
				ActivityNode activityNode = (ActivityNode) object;

				for (Iterator iterator2 = activityNode.getIn().iterator(); iterator2
						.hasNext();)
				{
					ActivityEdge actEdge = (ActivityEdge) iterator2.next();

					if (affectedObjects.contains(actEdge.getSource()))
					{
						affectedEdges.add(actEdge);
					}
				}

				for (Iterator iterator2 = activityNode.getOut().iterator(); iterator2
						.hasNext();)
				{
					ActivityEdge actEdge = (ActivityEdge) iterator2.next();

					if (affectedObjects.contains(actEdge.getTarget()))
					{
						affectedEdges.add(actEdge);
					}
				}
			}

		}

		return affectedEdges;
	}

}