//------------------------------------------------------------------------------
// 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.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.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.ModelFactory;
import org.eclipse.epf.diagram.model.ModelPackage;
import org.eclipse.epf.diagram.model.Node;
import org.eclipse.epf.diagram.model.WorkProductDependencyDiagram;
import org.eclipse.epf.diagram.model.WorkProductNode;
import org.eclipse.epf.diagram.model.util.GraphicalDataHelper;
import org.eclipse.epf.diagram.model.util.IAdapterFactoryFilter;
import org.eclipse.epf.diagram.model.util.IWPDDiagramChangeListener;
import org.eclipse.epf.library.edit.TngAdapterFactory;
import org.eclipse.epf.library.edit.process.BreakdownElementWrapperItemProvider;
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.Artifact;
import org.eclipse.epf.uma.BreakdownElement;
import org.eclipse.epf.uma.Deliverable;
import org.eclipse.epf.uma.MethodElement;
import org.eclipse.epf.uma.Outcome;
import org.eclipse.epf.uma.WorkProductDescriptor;

/**
 * <!-- begin-user-doc --> An implementation of the model object '<em><b>Work Product Dependency Diagram</b></em>'.
 * <!-- end-user-doc -->
 * <p>
 * </p>
 * 
 * @generated
 */
public class WorkProductDependencyDiagramImpl extends DiagramImpl implements
		WorkProductDependencyDiagram {
	private class WPDDiagramChangeListener extends ActivityAdapter implements
			IWPDDiagramChangeListener {

	};

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

		diagramChangeListener = new WPDDiagramChangeListener();
	}

	protected Class getDiagramChangeListenerType() {
		return IWPDDiagramChangeListener.class;
	}

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

	/**
	 * <!-- 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.WORK_PRODUCT_DEPENDENCY_DIAGRAM__INCOMING_CONNECTIONS:
				return ((InternalEList) getIncomingConnections()).basicAdd(
						otherEnd, msgs);
			case ModelPackage.WORK_PRODUCT_DEPENDENCY_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.WORK_PRODUCT_DEPENDENCY_DIAGRAM__INCOMING_CONNECTIONS:
				return ((InternalEList) getIncomingConnections()).basicRemove(
						otherEnd, msgs);
			case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__OUTGOING_CONNECTIONS:
				return ((InternalEList) getOutgoingConnections()).basicRemove(
						otherEnd, msgs);
			case ModelPackage.WORK_PRODUCT_DEPENDENCY_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.WORK_PRODUCT_DEPENDENCY_DIAGRAM__OBJECT:
			return getObject();
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__LOCATION:
			return getLocation();
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__WIDTH:
			return new Integer(getWidth());
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__HEIGHT:
			return new Integer(getHeight());
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__INCOMING_CONNECTIONS:
			return getIncomingConnections();
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__OUTGOING_CONNECTIONS:
			return getOutgoingConnections();
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__READ_ONLY:
			return isReadOnly() ? Boolean.TRUE : Boolean.FALSE;
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_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.WORK_PRODUCT_DEPENDENCY_DIAGRAM__OBJECT:
			setObject((Object) newValue);
			return;
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__LOCATION:
			setLocation((Point) newValue);
			return;
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__WIDTH:
			setWidth(((Integer) newValue).intValue());
			return;
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__HEIGHT:
			setHeight(((Integer) newValue).intValue());
			return;
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__INCOMING_CONNECTIONS:
			getIncomingConnections().clear();
			getIncomingConnections().addAll((Collection) newValue);
			return;
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__OUTGOING_CONNECTIONS:
			getOutgoingConnections().clear();
			getOutgoingConnections().addAll((Collection) newValue);
			return;
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__READ_ONLY:
			setReadOnly(((Boolean) newValue).booleanValue());
			return;
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_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.WORK_PRODUCT_DEPENDENCY_DIAGRAM__OBJECT:
			setObject(OBJECT_EDEFAULT);
			return;
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__LOCATION:
			setLocation(LOCATION_EDEFAULT);
			return;
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__WIDTH:
			setWidth(WIDTH_EDEFAULT);
			return;
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__HEIGHT:
			setHeight(HEIGHT_EDEFAULT);
			return;
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__INCOMING_CONNECTIONS:
			getIncomingConnections().clear();
			return;
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__OUTGOING_CONNECTIONS:
			getOutgoingConnections().clear();
			return;
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__READ_ONLY:
			setReadOnly(READ_ONLY_EDEFAULT);
			return;
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__NODES:
			getNodes().clear();
			return;
		}
		eDynamicUnset(eFeature);
	}

	/**
	 * <!-- begin-user-doc --> <!-- end-user-doc -->
	 * 
	 * @generated
	 */
	public boolean eIsSet(EStructuralFeature eFeature) {
		switch (eDerivedStructuralFeatureID(eFeature)) {
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__OBJECT:
			return OBJECT_EDEFAULT == null ? object != null : !OBJECT_EDEFAULT
					.equals(object);
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__LOCATION:
			return LOCATION_EDEFAULT == null ? location != null
					: !LOCATION_EDEFAULT.equals(location);
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__WIDTH:
			return width != WIDTH_EDEFAULT;
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__HEIGHT:
			return height != HEIGHT_EDEFAULT;
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__INCOMING_CONNECTIONS:
			return incomingConnections != null
					&& !incomingConnections.isEmpty();
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__OUTGOING_CONNECTIONS:
			return outgoingConnections != null
					&& !outgoingConnections.isEmpty();
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__READ_ONLY:
			return readOnly != READ_ONLY_EDEFAULT;
		case ModelPackage.WORK_PRODUCT_DEPENDENCY_DIAGRAM__NODES:
			return nodes != null && !nodes.isEmpty();
		}
		return eDynamicIsSet(eFeature);
	}
	
	private static final AdapterFactory[] DEFAULT_ADAPTER_FACTORIES = {			
		TngAdapterFactory.INSTANCE.getPBS_ComposedAdapterFactory() 
	}; 

	//
	// Start custom code
	//
	private Collection getChildren() {
		ITreeItemContentProvider adapter = null;
		AdapterFactory adapterFactory = null;
		if (wrapper != null) {
			//https://bugs.eclipse.org/bugs/show_bug.cgi?id=147552
			List wrappers = ProcessUtil.getWrappers(wrapper, DEFAULT_ADAPTER_FACTORIES);
			if(wrappers != null && wrappers.size() > 0){
				adapter = (ITreeItemContentProvider)wrappers.get(0);
			}
		} else {
			if (filter == null) {
				adapter = (ITreeItemContentProvider) TngAdapterFactory.INSTANCE
						.getPBS_ComposedAdapterFactory().adapt(getObject(),
								ITreeItemContentProvider.class);
			} else if (filter instanceof IAdapterFactoryFilter) {
				adapterFactory = ((IAdapterFactoryFilter) filter)
						.getWPBSAdapterFactory();
				adapter = (ITreeItemContentProvider) adapterFactory.adapt(
						getObject(), ITreeItemContentProvider.class);
			}
		}
		if (adapter != null) {
			// return adapter.getChildren(getObject());
			// commented above line, For diagrams - rollup should be false, for
			// handling rollup state below code.
			List children = new ArrayList();
			extractChildren(adapter, getObject(), children);
			return children;
		} else {
			return Collections.EMPTY_LIST;
		}
	}

	protected void populateNodes() {
		// Activity act = (Activity) getObject();

		// get all WorkProductDescriptors under the activity
		//
		super.populateNodes();
		// ITreeItemContentProvider adapter = (ITreeItemContentProvider)
		// TngAdapterFactory.INSTANCE.getPBS_ComposedAdapterFactory().adapt(act,
		// ITreeItemContentProvider.class);

		// ArrayList wpDescriptors = new ArrayList();
		for (Iterator iter = getChildren().iterator(); iter.hasNext();) {
			Object e = iter.next();
			Object element = TngUtil.unwrap(e);
			if (element instanceof WorkProductDescriptor) {
				WorkProductNode node = (WorkProductNode) toNode((MethodElement) element);
				if (e instanceof BreakdownElementWrapperItemProvider) {
					BreakdownElementWrapperItemProvider wrapper = (BreakdownElementWrapperItemProvider) e;
					if (wrapper.isReadOnly()) {
						((NamedNodeImpl) node).itemProvider = wrapper;
						node.setReadOnly(true);
					}
				}
				if (((WorkProductDescriptor) element).getWorkProduct() instanceof Artifact) {
					node.setType(1);
				}
				if (((WorkProductDescriptor) element).getWorkProduct() instanceof Deliverable) {
					node.setType(2);
				}
				if (((WorkProductDescriptor) element).getWorkProduct() instanceof Outcome) {
					node.setType(3);
				}
				getNodes().add(node);
			}
		}
	}
	protected Node toNode(MethodElement e) {
		// TODO Auto-generated method stub
		if(e instanceof WorkProductDescriptor){
			return super.toNode(e);
		}
		return null;
	}

	protected Node newNode() {
		return ModelFactory.eINSTANCE.createWorkProductNode();
	}

	protected int getType() {
		return GraphicalDataHelper.WORK_PRODUCT_DEPENDENCY_DIAGRAM;
	}

	protected Class getBreakdownElementType() {
		return WorkProductDescriptor.class;
	}

	protected void addToUmaModel(int position, Node addedNode) {
		if (addedNode.getObject() instanceof BreakdownElement) {
			((Activity) getObject()).getBreakdownElements().add(
					addedNode.getObject());
		}
		super.addToUmaModel(position, addedNode);
	}
	
} // WorkProductDependencyDiagramImpl