//------------------------------------------------------------------------------
// 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.diagram.model.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

import org.eclipse.draw2d.geometry.Point;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.notify.NotificationChain;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.util.InternalEList;
import org.eclipse.emf.edit.provider.ITreeItemContentProvider;
import org.eclipse.epf.diagram.model.ActivityDetailDiagram;
import org.eclipse.epf.diagram.model.Link;
import org.eclipse.epf.diagram.model.ModelFactory;
import org.eclipse.epf.diagram.model.ModelPackage;
import org.eclipse.epf.diagram.model.Node;
import org.eclipse.epf.diagram.model.NodeContainer;
import org.eclipse.epf.diagram.model.RoleTaskComposite;
import org.eclipse.epf.diagram.model.WorkProductComposite;
import org.eclipse.epf.diagram.model.util.GraphicalDataHelper;
import org.eclipse.epf.diagram.model.util.IActivityDetailDiagramChangeListener;
import org.eclipse.epf.diagram.model.util.IAdapterFactoryFilter;
import org.eclipse.epf.library.edit.TngAdapterFactory;
import org.eclipse.epf.library.edit.process.BreakdownElementWrapperItemProvider;
import org.eclipse.epf.library.edit.util.ConfigurableComposedAdapterFactory;
import org.eclipse.epf.library.edit.util.ProcessUtil;
import org.eclipse.epf.library.edit.util.TngUtil;
import org.eclipse.epf.uma.Activity;
import org.eclipse.epf.uma.BreakdownElement;
import org.eclipse.epf.uma.Descriptor;
import org.eclipse.epf.uma.MethodElement;
import org.eclipse.epf.uma.RoleDescriptor;
import org.eclipse.epf.uma.TaskDescriptor;
import org.eclipse.epf.uma.WorkProductDescriptor;
import org.eclipse.epf.uma.util.AssociationHelper;

/**
 * <!-- begin-user-doc --> An implementation of the model object '<em><b>Activity Detail Diagram</b></em>'.
 * <!-- end-user-doc -->
 * <p>
 * </p>
 * 
 * @generated
 */
public class ActivityDetailDiagramImpl extends DiagramImpl implements
		ActivityDetailDiagram {
	private class ActivityDetailDiagramChangeListener extends ActivityAdapter
			implements IActivityDetailDiagramChangeListener {
		// /* (non-Javadoc)
		// * @see
		// org.eclipse.epf.diagram.model.impl.DiagramImpl.ActivityAdapter#notifyChanged(org.eclipse.emf.common.notify.Notification)
		// */
		// public void notifyChanged(Notification msg) {
		// if(!notificationEnabled) return;
		// notificationEnabled = false;
		// try {
		// Object obj;
		// switch(msg.getFeatureID(Activity.class)) {
		// case UmaPackage.ACTIVITY__BREAKDOWN_ELEMENTS:
		// repopulateDiagram();
		// break;
		// }
		// }
		// finally {
		// notificationEnabled = true;
		// }
		//
		// }

	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 */
	protected ActivityDetailDiagramImpl() {
		super();

		diagramChangeListener = new ActivityDetailDiagramChangeListener();
	}

	/**
	 * 
	 */
	public void repopulateDiagram() {
		// clear diagram
		//

		int size = getNodes().size();

		// disable notification for all nodes in this diagram to avoid unwanted
		// concurrent modification of their connection list
		//
		for (int i = 0; i < size; i++) {
			NodeImpl node = ((NodeImpl) getNodes().get(i));
			node.notificationEnabled = false;
		}
		for (Iterator iteration = getNodes().iterator(); iteration.hasNext();) {
			Node node = (Node) iteration.next();

			// clear all links
			//
			for (Iterator iter = node.getOutgoingConnections().iterator(); iter
					.hasNext();) {
				Link link = (Link) iter.next();
				link.setTarget(null);
			}

			for (Iterator iter = node.getIncomingConnections().iterator(); iter
					.hasNext();) {
				Link link = (Link) iter.next();
				link.setSource(null);
			}
			node.getOutgoingConnections().clear();
			node.getIncomingConnections().clear();
		}

		getNodes().clear();

		populateDiagram();
	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * 
	 * @generated
	 */
	protected EClass eStaticClass() {
		return ModelPackage.eINSTANCE.getActivityDetailDiagram();
	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * 
	 * @generated
	 */
	public NotificationChain eInverseAdd(InternalEObject otherEnd,
			int featureID, Class baseClass, NotificationChain msgs) {
		if (featureID >= 0) {
			switch (eDerivedStructuralFeatureID(featureID, baseClass)) {
			case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__INCOMING_CONNECTIONS:
				return ((InternalEList) getIncomingConnections()).basicAdd(
						otherEnd, msgs);
			case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__OUTGOING_CONNECTIONS:
				return ((InternalEList) getOutgoingConnections()).basicAdd(
						otherEnd, msgs);
			default:
				return eDynamicInverseAdd(otherEnd, featureID, baseClass, msgs);
			}
		}
		if (eContainer != null)
			msgs = eBasicRemoveFromContainer(msgs);
		return eBasicSetContainer(otherEnd, featureID, msgs);
	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * 
	 * @generated
	 */
	public NotificationChain eInverseRemove(InternalEObject otherEnd,
			int featureID, Class baseClass, NotificationChain msgs) {
		if (featureID >= 0) {
			switch (eDerivedStructuralFeatureID(featureID, baseClass)) {
			case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__INCOMING_CONNECTIONS:
				return ((InternalEList) getIncomingConnections()).basicRemove(
						otherEnd, msgs);
			case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__OUTGOING_CONNECTIONS:
				return ((InternalEList) getOutgoingConnections()).basicRemove(
						otherEnd, msgs);
			case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__NODES:
				return ((InternalEList) getNodes()).basicRemove(otherEnd, msgs);
			default:
				return eDynamicInverseRemove(otherEnd, featureID, baseClass,
						msgs);
			}
		}
		return eBasicSetContainer(null, featureID, msgs);
	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * 
	 * @generated
	 */
	public Object eGet(EStructuralFeature eFeature, boolean resolve) {
		switch (eDerivedStructuralFeatureID(eFeature)) {
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__OBJECT:
			return getObject();
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__LOCATION:
			return getLocation();
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__WIDTH:
			return new Integer(getWidth());
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__HEIGHT:
			return new Integer(getHeight());
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__INCOMING_CONNECTIONS:
			return getIncomingConnections();
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__OUTGOING_CONNECTIONS:
			return getOutgoingConnections();
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__READ_ONLY:
			return isReadOnly() ? Boolean.TRUE : Boolean.FALSE;
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__NODES:
			return getNodes();
		}
		return eDynamicGet(eFeature, resolve);
	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * 
	 * @generated
	 */
	public void eSet(EStructuralFeature eFeature, Object newValue) {
		switch (eDerivedStructuralFeatureID(eFeature)) {
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__OBJECT:
			setObject((Object) newValue);
			return;
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__LOCATION:
			setLocation((Point) newValue);
			return;
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__WIDTH:
			setWidth(((Integer) newValue).intValue());
			return;
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__HEIGHT:
			setHeight(((Integer) newValue).intValue());
			return;
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__INCOMING_CONNECTIONS:
			getIncomingConnections().clear();
			getIncomingConnections().addAll((Collection) newValue);
			return;
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__OUTGOING_CONNECTIONS:
			getOutgoingConnections().clear();
			getOutgoingConnections().addAll((Collection) newValue);
			return;
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__READ_ONLY:
			setReadOnly(((Boolean) newValue).booleanValue());
			return;
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__NODES:
			getNodes().clear();
			getNodes().addAll((Collection) newValue);
			return;
		}
		eDynamicSet(eFeature, newValue);
	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * 
	 * @generated
	 */
	public void eUnset(EStructuralFeature eFeature) {
		switch (eDerivedStructuralFeatureID(eFeature)) {
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__OBJECT:
			setObject(OBJECT_EDEFAULT);
			return;
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__LOCATION:
			setLocation(LOCATION_EDEFAULT);
			return;
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__WIDTH:
			setWidth(WIDTH_EDEFAULT);
			return;
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__HEIGHT:
			setHeight(HEIGHT_EDEFAULT);
			return;
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__INCOMING_CONNECTIONS:
			getIncomingConnections().clear();
			return;
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__OUTGOING_CONNECTIONS:
			getOutgoingConnections().clear();
			return;
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__READ_ONLY:
			setReadOnly(READ_ONLY_EDEFAULT);
			return;
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__NODES:
			getNodes().clear();
			return;
		}
		eDynamicUnset(eFeature);
	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * 
	 * @generated
	 */
	public boolean eIsSet(EStructuralFeature eFeature) {
		switch (eDerivedStructuralFeatureID(eFeature)) {
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__OBJECT:
			return OBJECT_EDEFAULT == null ? object != null : !OBJECT_EDEFAULT
					.equals(object);
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__LOCATION:
			return LOCATION_EDEFAULT == null ? location != null
					: !LOCATION_EDEFAULT.equals(location);
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__WIDTH:
			return width != WIDTH_EDEFAULT;
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__HEIGHT:
			return height != HEIGHT_EDEFAULT;
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__INCOMING_CONNECTIONS:
			return incomingConnections != null
					&& !incomingConnections.isEmpty();
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__OUTGOING_CONNECTIONS:
			return outgoingConnections != null
					&& !outgoingConnections.isEmpty();
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__READ_ONLY:
			return readOnly != READ_ONLY_EDEFAULT;
		case ModelPackage.ACTIVITY_DETAIL_DIAGRAM__NODES:
			return nodes != null && !nodes.isEmpty();
		}
		return eDynamicIsSet(eFeature);
	}

	/**
	 * Gets all breakdown elements or their wrappers for the activity of this
	 * diagram
	 * 
	 * @return
	 */
	Collection getAllBreakdownElements() {
		ArrayList breakdownElements = new ArrayList();
		AdapterFactory[] adapterFactories;
		if(filter instanceof IAdapterFactoryFilter) {
			IAdapterFactoryFilter adapterFactoryFilter = (IAdapterFactoryFilter) filter;
			adapterFactories = new AdapterFactory[] {
					adapterFactoryFilter.getWBSAdapterFactory(),
					adapterFactoryFilter.getTBSAdapterFactory(),
					adapterFactoryFilter.getWPBSAdapterFactory() 
			};
		}
		else {
			adapterFactories = DEFAULT_ADAPTER_FACTORIES;
		}
		if (wrapper != null) {
			List wrappers = ProcessUtil.getWrappers(wrapper, adapterFactories);
			for (Iterator iter = wrappers.iterator(); iter.hasNext();) {
				BreakdownElementWrapperItemProvider w = (BreakdownElementWrapperItemProvider) iter
						.next();
				extractChildren(w, w, breakdownElements);
			}
		} else {
				for (int i = 0; i < adapterFactories.length; i++) {
					AdapterFactory adapterFactory = adapterFactories[i];
					ITreeItemContentProvider adapter = (ITreeItemContentProvider) adapterFactory
							.adapt(getObject(), ITreeItemContentProvider.class);
				extractChildren(adapter, getObject(), breakdownElements);
			}
		}
		return breakdownElements;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.epf.diagram.model.impl.DiagramImpl#populateNodes()
	 */
	protected void populateNodes() {
		Activity act = (Activity) getObject();
		if (act == null)
			return;
		// to populate the typednode.
		super.populateNodes();

		if(filter == null){
			filter = ((ConfigurableComposedAdapterFactory)DEFAULT_ADAPTER_FACTORIES[0]).getFilter();	
		}
		
		Node newNode = null;
		ArrayList nodes = new ArrayList();
		Collection breakdownElements = getAllBreakdownElements();
		Collection roleDescriptors = new HashSet();
		for (Iterator iterator = breakdownElements.iterator(); iterator
				.hasNext();) {
			Object object = iterator.next();
			Object element = TngUtil.unwrap(object);
			if (element instanceof TaskDescriptor) {
				TaskDescriptor descriptor = (TaskDescriptor) element;
				RoleDescriptor roleDescriptor = descriptor
				.getPerformedPrimarilyBy();
				if (roleDescriptor != null && filter.accept(roleDescriptor)
						//TODO: need to check if the role descriptor is inherited and locally suppressed
						// if locally suppressed, check the wrapper of the role descriptor
						//
						&& !roleDescriptor.getSuppressed().booleanValue() 
						&& !roleDescriptors.contains(roleDescriptor)) {
					roleDescriptors.add(roleDescriptor);
					newNode = createRoleTaskComposite(roleDescriptor);
					if(newNode != null) {
						if(ProcessUtil.isInherited(object)) {
							// task descriptor is inherited, its primary performer is not local
							// set role node of the RoleTaskComposite to read-only						
							//
							Node roleNode = (Node) ((NodeContainer)newNode).getNodes().get(0);
							roleNode.setReadOnly(true);
						}
						nodes.add(newNode);
					}
				}
				if(roleDescriptors.contains(roleDescriptor)){
					createTaskInputOutputNodes(descriptor, nodes);
				}
			}
		}

		if (!nodes.isEmpty()) {
			getNodes().addAll(nodes);
		}
	}

//	private boolean isAssociatedInConfig(Collection breakdownElements,
//			TaskDescriptor taskDescriptor) {
//		Object roledescp = taskDescriptor.getPerformedPrimarilyBy();
//		if (roledescp == null)
//			return false;
//		for (Iterator iter = breakdownElements.iterator(); iter.hasNext();) {
//			Object e = iter.next();
//			Object element = TngUtil.unwrap(e);
//			if (element != null) {
//				if (element.equals(roledescp))
//					return true;
//			}
//		}
//		return false;
//	}

	/**
	 * @param taskDescriptor
	 * @return
	 */
	Node createNode(TaskDescriptor taskDescriptor) {
		Node node = ModelFactory.eINSTANCE.createTaskNode();
		node.setUMAContainer(getGraphNode());
		node.setDiagram(this);
		node.setObject(taskDescriptor);
		return node;
	}

	/**
	 * @param descriptor
	 * @return
	 */
	Node createNode(WorkProductDescriptor descriptor) {
		Node node = ModelFactory.eINSTANCE.createWorkProductDescriptorNode();
		node.setUMAContainer(getGraphNode());
		node.setDiagram(this);
		node.setObject(descriptor);
		return node;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.epf.diagram.model.impl.DiagramImpl#populateLinks()
	 */
	protected void populateLinks() {
		populateLinks(getNodes(), true);
	}

	/**
	 * @param newNodes
	 * @param disableNotification
	 */
	private void populateLinks(Collection newNodes, boolean disableNotification) {
		// fill outgoing/incoming connection lists of all nodes
		//
		int size = getNodes().size();
		boolean[] notifies = new boolean[size];
		try {
			if (disableNotification)
				// disable notification for all nodes in this diagram to avoid
				// unwanted concurrent modification of their connection list
				//
				for (int i = 0; i < size; i++) {
					Node node = ((Node) getNodes().get(i));
					notifies[i] = node.eDeliver();
					node.eSetDeliver(false);
				}

			for (Iterator iter = newNodes.iterator(); iter.hasNext();) {
				Node child = (Node) iter.next();
				if (child instanceof WorkProductComposite) {
					// WorkProductComposite workproductComposite =
					// (WorkProductComposite) child.getObject();
					WorkProductComposite workproductComposite = (WorkProductComposite) child;
					if (workproductComposite.getType() == WorkProductComposite.INPUTS) {
						Object object = workproductComposite.getObject();
						if (object instanceof TaskDescriptor) {
							Node node = GraphicalDataHelper.findNode(this,
									object);
							Link link = ModelFactory.eINSTANCE.createLink();
							link.setSource(child);
							link.setTarget(node);
							GraphicalDataHelper.addGraphicalData(link);
						}
					}
					if (workproductComposite.getType() == WorkProductComposite.OUTPUTS) {
						Object object = workproductComposite.getObject();
						if (object instanceof TaskDescriptor) {
							Node node = GraphicalDataHelper.findNode(this,
									object);
							Link link = ModelFactory.eINSTANCE.createLink();
							link.setSource(node);
							link.setTarget(child);
							GraphicalDataHelper.addGraphicalData(link);
						}
					}
				}
			}
 		} finally {
			if (disableNotification)
				// restore notification flag
				//
				for (int i = 0; i < size; i++) {
					((EObject) getNodes().get(i)).eSetDeliver(notifies[i]);
				}
		}

	}

	public RoleTaskComposite createRoleTaskComposite(
			RoleDescriptor roleDescriptor) {
		RoleTaskComposite roleTaskComposite = ModelFactory.eINSTANCE
				.createRoleTaskComposite();
		roleTaskComposite.setUMAContainer(getGraphNode());
		roleTaskComposite.setDiagram(this);
		roleTaskComposite.setObject(roleDescriptor);
		return roleTaskComposite;
	}

	public WorkProductComposite createWorkProductComposite(
			TaskDescriptor taskDescriptor, int type) {
		WorkProductComposite workproductComposite = ModelFactory.eINSTANCE
				.createWorkProductComposite();
		workproductComposite.setUMAContainer(getGraphNode());
		workproductComposite.setDiagram(this);
		workproductComposite.setType(type);
		workproductComposite.setObject(taskDescriptor);
		return workproductComposite;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.epf.diagram.model.impl.DiagramImpl#getType()
	 */
	protected int getType() {
		return GraphicalDataHelper.ACTIVITY_DETAIL_DIAGRAM;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.epf.diagram.model.impl.DiagramImpl#getDiagramChangeListenerType()
	 */
	protected Class getDiagramChangeListenerType() {
		return IActivityDetailDiagramChangeListener.class;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.epf.diagram.model.impl.DiagramImpl#getBreakdownElementType()
	 */
	protected Class getBreakdownElementType() {
		return Descriptor.class;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.epf.diagram.model.impl.DiagramImpl#toNode(org.eclipse.epf.uma.MethodElement)
	 */
	protected Node toNode(MethodElement e) {
		if (e instanceof RoleDescriptor) {
			List list = AssociationHelper.getPrimaryTaskDescriptors((RoleDescriptor) e);
			for (Iterator iterator = list.iterator(); iterator.hasNext();) {
				Object obj = iterator.next();
				if (obj instanceof TaskDescriptor) {
					createTaskInputOutputNodes((TaskDescriptor) obj, getNodes());
				}
			}
			return createRoleTaskComposite((RoleDescriptor) e);
		} else if (e instanceof TaskDescriptor) {
			createTaskInputOutputNodes((TaskDescriptor) e, getNodes());
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.epf.diagram.model.impl.DiagramImpl#addNode(java.lang.Object)
	 */
	protected Node addNode(Object obj) {
		if (filter == null) {
			filter = ((ConfigurableComposedAdapterFactory) DEFAULT_ADAPTER_FACTORIES[0])
					.getFilter();
		}
		if (obj instanceof TaskDescriptor
				&& !filter.accept(((TaskDescriptor) obj)
						.getPerformedPrimarilyBy()))
			return null;
		Node node = null;
		if (obj instanceof TaskDescriptor) {
			RoleDescriptor roleDescriptor = ((TaskDescriptor) obj)
					.getPerformedPrimarilyBy();
			node = findNode(this, roleDescriptor);
			if (node == null) {
				node = createRoleTaskComposite(roleDescriptor);
				getNodes().add(node);
			} else {
				node = super.addNode(getNodes(), obj);
			}
		} else {
			node = super.addNode(getNodes(), obj);
		}
		if (node != null) {
			populateLinks(Collections.singletonList(node), false);
		}
		return node;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.epf.diagram.model.impl.DiagramImpl#addNodes(java.util.Collection)
	 */
	protected Collection addNodes(Collection collection) {
		Collection nodes = super.addNodes(collection);
		if (!nodes.isEmpty()) {
			populateLinks(nodes, false);
		}
		return nodes;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.epf.diagram.model.impl.DiagramImpl#removeFromUmaModel(org.eclipse.epf.diagram.model.Node)
	 */
	protected void removeFromUmaModel(Node removedNode) {
		// if the removed node is a TaskNode that had been moved to a
		// RoleTaskComposite
		// then its TaskDescriptor will not be removed from model
		//
		if (GraphicalDataHelper.findNode(this, removedNode.getObject()) != null) {
			return;
		}
		if (removedNode instanceof RoleTaskComposite
				|| removedNode instanceof WorkProductComposite)
			return;

		super.removeFromUmaModel(removedNode);
	}

	protected void addToUmaModel(int position, Node addedNode) {
		super.addToUmaModel(position, addedNode);

		if (addedNode.getObject() instanceof BreakdownElement) {
			Activity act = (Activity) getObject();
			// translate Node index to Activity index
			int i = toActivityIndex(position);
			System.out
					.println("ActivityDetailDiagram.addToUmaModel(): WorkBreakdownElement index: " + i); //$NON-NLS-1$
			if (i == -1) {
				act.getBreakdownElements().add(addedNode.getObject());
			} else {
				act.getBreakdownElements().add(i, addedNode.getObject());
			}
		}

	}

	private int toActivityIndex(int index) {
		if (index == -1)
			return index;
		int size = getNodes().size();
		int i = index + 1;
		if (i == size)
			return -1;
		Node node = (Node) getNodes().get(i);
		if (node == null)
			return -1;

		for (; !(node.getObject() instanceof BreakdownElement) && i < size; i++) {
			node = (Node) getNodes().get(i);
		}
		if (i == size)
			return -1;
		Activity act = (Activity) getObject();
		return act.getBreakdownElements().indexOf(node.getObject());

	}

	public Node findNode(ActivityDetailDiagram diagram, Object object) {
		for (Iterator iter = diagram.getNodes().iterator(); iter.hasNext();) {
			Node element = (Node) iter.next();
			if (object == element.getObject()) {
				return element;
			}
		}
		return null;
	}
	
	private static final AdapterFactory[] DEFAULT_ADAPTER_FACTORIES = {			
		TngAdapterFactory.INSTANCE.getWBS_ComposedAdapterFactory(),
		TngAdapterFactory.INSTANCE.getOBS_ComposedAdapterFactory(),
		TngAdapterFactory.INSTANCE.getPBS_ComposedAdapterFactory() 
	}; 
	
	public void createTaskInputOutputNodes(TaskDescriptor descriptor, Collection nodes) {
		Node newNode = null;
		if (!descriptor.getMandatoryInput().isEmpty()) {
			newNode = createWorkProductComposite(descriptor,
					WorkProductComposite.INPUTS);
			nodes.add(newNode);
		}
		if (!descriptor.getOutput().isEmpty()) {
			newNode = createWorkProductComposite(descriptor,
					WorkProductComposite.OUTPUTS);
			nodes.add(newNode);
		}
	}
	/* (non-Javadoc)
	 * @see org.eclipse.epf.diagram.model.impl.DiagramImpl#setNew(boolean)
	 */
	public void setNew(boolean n) {
		super.setNew(n);
		if(n == true){
			GraphicalDataHelper.createProperty(this.graphNode, 
					GraphicalDataHelper.PROP_AUTO_LAYOUT, 
					GraphicalDataHelper.PROP_AUTO_LAYOUT_VALUE_TRUE);
		}
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.epf.diagram.model.impl.DiagramImpl#moveNode(java.lang.Object)
	 */
	public void moveNode(Object oldValue) {
		// TODO Auto-generated method stub
	}
} // ActivityDetailDiagramImpl
