/**
 */
package org.etsi.mts.tdl.impl;

import java.lang.reflect.InvocationTargetException;

import java.util.List;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.InternalEObject;

import org.eclipse.emf.ecore.impl.ENotificationImpl;

import org.eclipse.ocl.pivot.StandardLibrary;
import org.eclipse.ocl.pivot.evaluation.Executor;
import org.eclipse.ocl.pivot.ids.IdResolver;
import org.eclipse.ocl.pivot.ids.IdResolver.IdResolverExtension;
import org.eclipse.ocl.pivot.ids.TypeId;
import org.eclipse.ocl.pivot.internal.library.executor.ExecutorSingleIterationManager;
import org.eclipse.ocl.pivot.library.AbstractBinaryOperation;
import org.eclipse.ocl.pivot.library.LibraryIteration.LibraryIterationExtension;
import org.eclipse.ocl.pivot.library.collection.CollectionIncludesOperation;
import org.eclipse.ocl.pivot.library.oclany.OclAnyOclAsSetOperation;
import org.eclipse.ocl.pivot.library.oclany.OclAnyOclAsTypeOperation;
import org.eclipse.ocl.pivot.library.oclany.OclAnyOclIsKindOfOperation;
import org.eclipse.ocl.pivot.oclstdlib.OCLstdlibTables;
import org.eclipse.ocl.pivot.utilities.PivotUtil;
import org.eclipse.ocl.pivot.utilities.ValueUtil;
import org.eclipse.ocl.pivot.values.InvalidValueException;
import org.eclipse.ocl.pivot.values.OrderedSetValue;
import org.eclipse.ocl.pivot.values.SetValue;
import org.etsi.mts.tdl.AnnotationType;
import org.etsi.mts.tdl.ComponentType;
import org.etsi.mts.tdl.Extension;
import org.etsi.mts.tdl.GateType;
import org.etsi.mts.tdl.PackageableElement;
import org.etsi.mts.tdl.SimpleDataType;
import org.etsi.mts.tdl.StructuredDataType;
import org.etsi.mts.tdl.tdlPackage;
import org.etsi.mts.tdl.tdlTables;

/**
 * <!-- begin-user-doc -->
 * An implementation of the model object '<em><b>Extension</b></em>'.
 * <!-- end-user-doc -->
 * <p>
 * The following features are implemented:
 * </p>
 * <ul>
 *   <li>{@link org.etsi.mts.tdl.impl.ExtensionImpl#getExtending <em>Extending</em>}</li>
 * </ul>
 *
 * @generated
 */
public class ExtensionImpl extends ElementImpl implements Extension
{
	/**
	 * The cached value of the '{@link #getExtending() <em>Extending</em>}' reference.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getExtending()
	 * @generated
	 * @ordered
	 */
	protected PackageableElement extending;

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	protected ExtensionImpl()
	{
		super();
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	protected EClass eStaticClass()
	{
		return tdlPackage.Literals.EXTENSION;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public PackageableElement getExtending()
	{
		if (extending != null && extending.eIsProxy()) {
			InternalEObject oldExtending = (InternalEObject)extending;
			extending = (PackageableElement)eResolveProxy(oldExtending);
			if (extending != oldExtending) {
				if (eNotificationRequired())
					eNotify(new ENotificationImpl(this, Notification.RESOLVE, tdlPackage.EXTENSION__EXTENDING, oldExtending, extending));
			}
		}
		return extending;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public PackageableElement basicGetExtending()
	{
		return extending;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public void setExtending(PackageableElement newExtending)
	{
		PackageableElement oldExtending = extending;
		extending = newExtending;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET, tdlPackage.EXTENSION__EXTENDING, oldExtending, extending));
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@SuppressWarnings("unchecked")
	@Override
	public EList<Extension> transitiveExtending()
	{
		/**
		 *
		 * if self.extending.oclIsKindOf(AnnotationType)
		 * then
		 *   OrderedSet{self.extending.oclAsType(AnnotationType).extension
		 *   }
		 * else
		 *   if self.extending.oclIsKindOf(ComponentType)
		 *   then
		 *     OrderedSet{self.extending.oclAsType(ComponentType).extension
		 *     }
		 *   else
		 *     if self.extending.oclIsKindOf(GateType)
		 *     then
		 *       OrderedSet{self.extending.oclAsType(GateType).extension
		 *       }
		 *     else
		 *       if self.extending.oclIsKindOf(StructuredDataType)
		 *       then
		 *         self.extending.oclAsType(StructuredDataType).extension
		 *       else
		 *         if self.extending.oclIsKindOf(SimpleDataType)
		 *         then
		 *           OrderedSet{
		 *             self.extending.oclAsType(SimpleDataType).extension
		 *           }
		 *         else OrderedSet{}
		 *         endif
		 *       endif
		 *     endif
		 *   endif
		 * endif
		 */
		final /*@NonInvalid*/ Executor executor = PivotUtil.getExecutor(this);
		final /*@NonInvalid*/ IdResolver idResolver = executor.getIdResolver();
		final /*@NonInvalid*/ org.eclipse.ocl.pivot.Class TYP_tdl_c_c_AnnotationType_0 = idResolver.getClass(tdlTables.CLSSid_AnnotationType, null);
		final /*@NonInvalid*/ PackageableElement extending = this.getExtending();
		final /*@NonInvalid*/ boolean oclIsKindOf = OclAnyOclIsKindOfOperation.INSTANCE.evaluate(executor, extending, TYP_tdl_c_c_AnnotationType_0).booleanValue();
		/*@Thrown*/ OrderedSetValue local_4;
		if (oclIsKindOf) {
			final /*@Thrown*/ AnnotationType oclAsType = (AnnotationType)OclAnyOclAsTypeOperation.INSTANCE.evaluate(executor, extending, TYP_tdl_c_c_AnnotationType_0);
			final /*@Thrown*/ Extension extension = oclAsType.getExtension();
			final /*@Thrown*/ OrderedSetValue OrderedSet = ValueUtil.createOrderedSetOfEach(tdlTables.ORD_CLSSid_Extension, extension);
			local_4 = OrderedSet;
		}
		else {
			final /*@NonInvalid*/ org.eclipse.ocl.pivot.Class TYP_tdl_c_c_ComponentType_0 = idResolver.getClass(tdlTables.CLSSid_ComponentType, null);
			final /*@NonInvalid*/ boolean oclIsKindOf_0 = OclAnyOclIsKindOfOperation.INSTANCE.evaluate(executor, extending, TYP_tdl_c_c_ComponentType_0).booleanValue();
			/*@Thrown*/ OrderedSetValue local_3;
			if (oclIsKindOf_0) {
				final /*@Thrown*/ ComponentType oclAsType_0 = (ComponentType)OclAnyOclAsTypeOperation.INSTANCE.evaluate(executor, extending, TYP_tdl_c_c_ComponentType_0);
				final /*@Thrown*/ Extension extension_0 = oclAsType_0.getExtension();
				final /*@Thrown*/ OrderedSetValue OrderedSet_0 = ValueUtil.createOrderedSetOfEach(tdlTables.ORD_CLSSid_Extension, extension_0);
				local_3 = OrderedSet_0;
			}
			else {
				final /*@NonInvalid*/ org.eclipse.ocl.pivot.Class TYP_tdl_c_c_GateType_0 = idResolver.getClass(tdlTables.CLSSid_GateType, null);
				final /*@NonInvalid*/ boolean oclIsKindOf_1 = OclAnyOclIsKindOfOperation.INSTANCE.evaluate(executor, extending, TYP_tdl_c_c_GateType_0).booleanValue();
				/*@Thrown*/ OrderedSetValue local_2;
				if (oclIsKindOf_1) {
					final /*@Thrown*/ GateType oclAsType_1 = (GateType)OclAnyOclAsTypeOperation.INSTANCE.evaluate(executor, extending, TYP_tdl_c_c_GateType_0);
					final /*@Thrown*/ Extension extension_1 = oclAsType_1.getExtension();
					final /*@Thrown*/ OrderedSetValue OrderedSet_1 = ValueUtil.createOrderedSetOfEach(tdlTables.ORD_CLSSid_Extension, extension_1);
					local_2 = OrderedSet_1;
				}
				else {
					final /*@NonInvalid*/ org.eclipse.ocl.pivot.Class TYP_tdl_c_c_StructuredDataType_0 = idResolver.getClass(tdlTables.CLSSid_StructuredDataType, null);
					final /*@NonInvalid*/ boolean oclIsKindOf_2 = OclAnyOclIsKindOfOperation.INSTANCE.evaluate(executor, extending, TYP_tdl_c_c_StructuredDataType_0).booleanValue();
					/*@Thrown*/ OrderedSetValue local_1;
					if (oclIsKindOf_2) {
						final /*@Thrown*/ StructuredDataType oclAsType_2 = (StructuredDataType)OclAnyOclAsTypeOperation.INSTANCE.evaluate(executor, extending, TYP_tdl_c_c_StructuredDataType_0);
						final /*@Thrown*/ List<Extension> extension_2 = oclAsType_2.getExtension();
						final /*@Thrown*/ OrderedSetValue BOXED_extension_2 = idResolver.createOrderedSetOfAll(tdlTables.ORD_CLSSid_Extension, extension_2);
						local_1 = BOXED_extension_2;
					}
					else {
						final /*@NonInvalid*/ org.eclipse.ocl.pivot.Class TYP_tdl_c_c_SimpleDataType_0 = idResolver.getClass(tdlTables.CLSSid_SimpleDataType, null);
						final /*@NonInvalid*/ boolean oclIsKindOf_3 = OclAnyOclIsKindOfOperation.INSTANCE.evaluate(executor, extending, TYP_tdl_c_c_SimpleDataType_0).booleanValue();
						/*@Thrown*/ OrderedSetValue local_0;
						if (oclIsKindOf_3) {
							final /*@Thrown*/ SimpleDataType oclAsType_3 = (SimpleDataType)OclAnyOclAsTypeOperation.INSTANCE.evaluate(executor, extending, TYP_tdl_c_c_SimpleDataType_0);
							final /*@Thrown*/ Extension extension_3 = oclAsType_3.getExtension();
							final /*@Thrown*/ OrderedSetValue OrderedSet_2 = ValueUtil.createOrderedSetOfEach(tdlTables.ORD_CLSSid_Extension, extension_3);
							local_0 = OrderedSet_2;
						}
						else {
							local_0 = tdlTables.OrderedSet;
						}
						local_1 = local_0;
					}
					local_2 = local_1;
				}
				local_3 = local_2;
			}
			local_4 = local_3;
		}
		final /*@Thrown*/ List<Extension> ECORE_local_4 = ((IdResolverExtension)idResolver).ecoreValueOfAll(Extension.class, local_4);
		return (EList<Extension>)ECORE_local_4;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public Boolean isExtending(final PackageableElement e)
	{
		/**
		 *
		 * if self.extending = e
		 * then true
		 * else
		 *   if self->closure(transitiveExtending())->includes(e)
		 *   then true
		 *   else false
		 *   endif
		 * endif
		 */
		final /*@NonInvalid*/ Executor executor = PivotUtil.getExecutor(this);
		final /*@NonInvalid*/ IdResolver idResolver = executor.getIdResolver();
		final /*@NonInvalid*/ StandardLibrary standardLibrary = idResolver.getStandardLibrary();
		final /*@NonInvalid*/ PackageableElement extending = this.getExtending();
		final /*@NonInvalid*/ boolean eq = extending.equals(e);
		/*@NonInvalid*/ boolean local_2;
		if (eq) {
			local_2 = true;
		}
		else {
			final /*@NonInvalid*/ SetValue oclAsSet = OclAnyOclAsSetOperation.INSTANCE.evaluate(executor, tdlTables.SET_CLSSid_Extension, this);
			final org.eclipse.ocl.pivot.Class TYPE_closure_0 = executor.getStaticTypeOfValue(null, oclAsSet);
			final LibraryIterationExtension IMPL_closure_0 = (LibraryIterationExtension)TYPE_closure_0.lookupImplementation(standardLibrary, OCLstdlibTables.Operations._Set__closure);
			final /*@NonNull*/ Object ACC_closure_0 = IMPL_closure_0.createAccumulatorValue(executor, tdlTables.SET_CLSSid_Extension, tdlTables.ORD_CLSSid_Extension);
			/**
			 * Implementation of the iterator body.
			 */
			final AbstractBinaryOperation BODY_closure_0 = new AbstractBinaryOperation() {
				/**
				 * transitiveExtending()
				 */
				@Override
				public /*@Nullable*/ Object evaluate(final Executor executor, final TypeId typeId, final /*@Nullable*/ Object oclAsSet, final /*@NonInvalid*/ Object _1) {
					final /*@NonInvalid*/ Extension local_0 = (Extension)_1;
					if (local_0 == null) {
						throw new InvalidValueException("Null source for \'tdl::Extension::transitiveExtending() : OrderedSet(tdl::Extension[*|?])\'");
					}
					final /*@Thrown*/ List<Extension> transitiveExtending = local_0.transitiveExtending();
					final /*@Thrown*/ OrderedSetValue BOXED_transitiveExtending = idResolver.createOrderedSetOfAll(tdlTables.ORD_CLSSid_Extension, transitiveExtending);
					return BOXED_transitiveExtending;
				}
			};
			final ExecutorSingleIterationManager MGR_closure_0 = new ExecutorSingleIterationManager(executor, tdlTables.SET_CLSSid_Extension, BODY_closure_0, oclAsSet, ACC_closure_0);
			final /*@Thrown*/ SetValue closure = (SetValue)IMPL_closure_0.evaluateIteration(MGR_closure_0);
			final /*@Thrown*/ boolean includes = CollectionIncludesOperation.INSTANCE.evaluate(closure, e).booleanValue();
			/*@NonInvalid*/ boolean local_1;
			if (includes) {
				local_1 = true;
			}
			else {
				local_1 = false;
			}
			local_2 = local_1;
		}
		return local_2;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public Object eGet(int featureID, boolean resolve, boolean coreType)
	{
		switch (featureID) {
			case tdlPackage.EXTENSION__EXTENDING:
				if (resolve) return getExtending();
				return basicGetExtending();
		}
		return super.eGet(featureID, resolve, coreType);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public void eSet(int featureID, Object newValue)
	{
		switch (featureID) {
			case tdlPackage.EXTENSION__EXTENDING:
				setExtending((PackageableElement)newValue);
				return;
		}
		super.eSet(featureID, newValue);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public void eUnset(int featureID)
	{
		switch (featureID) {
			case tdlPackage.EXTENSION__EXTENDING:
				setExtending((PackageableElement)null);
				return;
		}
		super.eUnset(featureID);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public boolean eIsSet(int featureID)
	{
		switch (featureID) {
			case tdlPackage.EXTENSION__EXTENDING:
				return extending != null;
		}
		return super.eIsSet(featureID);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public Object eInvoke(int operationID, EList<?> arguments) throws InvocationTargetException
	{
		switch (operationID) {
			case tdlPackage.EXTENSION___TRANSITIVE_EXTENDING:
				return transitiveExtending();
			case tdlPackage.EXTENSION___IS_EXTENDING__PACKAGEABLEELEMENT:
				return isExtending((PackageableElement)arguments.get(0));
		}
		return super.eInvoke(operationID, arguments);
	}

} //ExtensionImpl
