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

import java.lang.reflect.InvocationTargetException;

import java.util.Collection;

import java.util.Iterator;
import java.util.List;
import org.eclipse.emf.common.notify.NotificationChain;

import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.InternalEObject;

import org.eclipse.emf.ecore.util.EObjectContainmentEList;
import org.eclipse.emf.ecore.util.InternalEList;

import org.eclipse.ocl.pivot.evaluation.Executor;
import org.eclipse.ocl.pivot.ids.IdResolver;
import org.eclipse.ocl.pivot.library.oclany.OclAnyOclAsTypeOperation;
import org.eclipse.ocl.pivot.library.oclany.OclAnyOclIsKindOfOperation;
import org.eclipse.ocl.pivot.messages.PivotMessages;
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.etsi.mts.tdl.DataElementUse;
import org.etsi.mts.tdl.DataType;
import org.etsi.mts.tdl.DataUse;
import org.etsi.mts.tdl.MemberReference;
import org.etsi.mts.tdl.NamedElement;
import org.etsi.mts.tdl.ParameterBinding;
import org.etsi.mts.tdl.tdlPackage;
import org.etsi.mts.tdl.tdlTables;

/**
 * <!-- begin-user-doc -->
 * An implementation of the model object '<em><b>Data Use</b></em>'.
 * <!-- end-user-doc -->
 * <p>
 * The following features are implemented:
 * </p>
 * <ul>
 *   <li>{@link org.etsi.mts.tdl.impl.DataUseImpl#getArgument <em>Argument</em>}</li>
 *   <li>{@link org.etsi.mts.tdl.impl.DataUseImpl#getReduction <em>Reduction</em>}</li>
 * </ul>
 *
 * @generated
 */
public abstract class DataUseImpl extends ElementImpl implements DataUse
{
	/**
	 * The cached value of the '{@link #getArgument() <em>Argument</em>}' containment reference list.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getArgument()
	 * @generated
	 * @ordered
	 */
	protected EList<ParameterBinding> argument;

	/**
	 * The cached value of the '{@link #getReduction() <em>Reduction</em>}' containment reference list.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getReduction()
	 * @generated
	 * @ordered
	 */
	protected EList<MemberReference> reduction;

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

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

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public EList<ParameterBinding> getArgument()
	{
		if (argument == null) {
			argument = new EObjectContainmentEList<ParameterBinding>(ParameterBinding.class, this, tdlPackage.DATA_USE__ARGUMENT);
		}
		return argument;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public EList<MemberReference> getReduction()
	{
		if (reduction == null) {
			reduction = new EObjectContainmentEList<MemberReference>(MemberReference.class, this, tdlPackage.DATA_USE__REDUCTION);
		}
		return reduction;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public DataType resolveDataType()
	{
		/**
		 * null
		 */
		return null;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public boolean isEffectivelyStatic()
	{
		/**
		 *
		 * (
		 *   self.oclIsKindOf(StaticDataUse) or
		 *   self.oclIsKindOf(DataElementUse) and
		 *   (
		 *     self.oclAsType(DataElementUse)
		 *     .dataElement.oclIsUndefined() or
		 *     self.oclAsType(DataElementUse)
		 *     .dataElement.oclIsKindOf(DataInstance) or
		 *     self.oclAsType(DataElementUse)
		 *     .dataElement.oclIsKindOf(DataType)
		 *   )
		 * ) and
		 * self.argument->forAll(a | a.dataUse.isEffectivelyStatic())
		 */
		final /*@NonInvalid*/ Executor executor = PivotUtil.getExecutor(this);
		final /*@NonInvalid*/ IdResolver idResolver = executor.getIdResolver();
		/*@Caught*/ Object CAUGHT_or_1;
		try {
			final /*@NonInvalid*/ org.eclipse.ocl.pivot.Class TYP_tdl_c_c_StaticDataUse_0 = idResolver.getClass(tdlTables.CLSSid_StaticDataUse, null);
			final /*@NonInvalid*/ boolean oclIsKindOf = OclAnyOclIsKindOfOperation.INSTANCE.evaluate(executor, this, TYP_tdl_c_c_StaticDataUse_0).booleanValue();
			final /*@Thrown*/ Boolean or_1;
			if (oclIsKindOf) {
				or_1 = ValueUtil.TRUE_VALUE;
			}
			else {
				/*@Caught*/ Object CAUGHT_and;
				try {
					final /*@NonInvalid*/ org.eclipse.ocl.pivot.Class TYP_tdl_c_c_DataElementUse_0 = idResolver.getClass(tdlTables.CLSSid_DataElementUse, null);
					final /*@NonInvalid*/ boolean oclIsKindOf_0 = OclAnyOclIsKindOfOperation.INSTANCE.evaluate(executor, this, TYP_tdl_c_c_DataElementUse_0).booleanValue();
					final /*@Thrown*/ Boolean and;
					if (!oclIsKindOf_0) {
						and = ValueUtil.FALSE_VALUE;
					}
					else {
						/*@Caught*/ Object CAUGHT_or_0;
						try {
							/*@Caught*/ Object CAUGHT_or;
							try {
								/*@Caught*/ Object CAUGHT_dataElement;
								try {
									final /*@Thrown*/ DataElementUse oclAsType = (DataElementUse)OclAnyOclAsTypeOperation.INSTANCE.evaluate(executor, this, TYP_tdl_c_c_DataElementUse_0);
									final /*@Thrown*/ NamedElement dataElement = oclAsType.getDataElement();
									CAUGHT_dataElement = dataElement;
								}
								catch (Exception e) {
									CAUGHT_dataElement = ValueUtil.createInvalidValue(e);
								}
								final /*@NonInvalid*/ boolean oclIsUndefined = (CAUGHT_dataElement == null) || (CAUGHT_dataElement instanceof InvalidValueException);
								final /*@Thrown*/ Boolean or;
								if (oclIsUndefined) {
									or = ValueUtil.TRUE_VALUE;
								}
								else {
									/*@Caught*/ Object CAUGHT_oclIsKindOf_1;
									try {
										final /*@NonInvalid*/ org.eclipse.ocl.pivot.Class TYP_tdl_c_c_DataInstance_0 = idResolver.getClass(tdlTables.CLSSid_DataInstance, null);
										final /*@Thrown*/ DataElementUse oclAsType_0 = (DataElementUse)OclAnyOclAsTypeOperation.INSTANCE.evaluate(executor, this, TYP_tdl_c_c_DataElementUse_0);
										final /*@Thrown*/ NamedElement dataElement_0 = oclAsType_0.getDataElement();
										final /*@Thrown*/ boolean oclIsKindOf_1 = OclAnyOclIsKindOfOperation.INSTANCE.evaluate(executor, dataElement_0, TYP_tdl_c_c_DataInstance_0).booleanValue();
										CAUGHT_oclIsKindOf_1 = oclIsKindOf_1;
									}
									catch (Exception e) {
										CAUGHT_oclIsKindOf_1 = ValueUtil.createInvalidValue(e);
									}
									if (CAUGHT_oclIsKindOf_1 == ValueUtil.TRUE_VALUE) {
										or = ValueUtil.TRUE_VALUE;
									}
									else {
										if (CAUGHT_oclIsKindOf_1 instanceof InvalidValueException) {
											throw (InvalidValueException)CAUGHT_oclIsKindOf_1;
										}
										or = ValueUtil.FALSE_VALUE;
									}
								}
								CAUGHT_or = or;
							}
							catch (Exception e) {
								CAUGHT_or = ValueUtil.createInvalidValue(e);
							}
							final /*@Thrown*/ Boolean or_0;
							if (CAUGHT_or == ValueUtil.TRUE_VALUE) {
								or_0 = ValueUtil.TRUE_VALUE;
							}
							else {
								/*@Caught*/ Object CAUGHT_oclIsKindOf_2;
								try {
									final /*@NonInvalid*/ org.eclipse.ocl.pivot.Class TYP_tdl_c_c_DataType_0 = idResolver.getClass(tdlTables.CLSSid_DataType, null);
									final /*@Thrown*/ DataElementUse oclAsType_1 = (DataElementUse)OclAnyOclAsTypeOperation.INSTANCE.evaluate(executor, this, TYP_tdl_c_c_DataElementUse_0);
									final /*@Thrown*/ NamedElement dataElement_1 = oclAsType_1.getDataElement();
									final /*@Thrown*/ boolean oclIsKindOf_2 = OclAnyOclIsKindOfOperation.INSTANCE.evaluate(executor, dataElement_1, TYP_tdl_c_c_DataType_0).booleanValue();
									CAUGHT_oclIsKindOf_2 = oclIsKindOf_2;
								}
								catch (Exception e) {
									CAUGHT_oclIsKindOf_2 = ValueUtil.createInvalidValue(e);
								}
								if (CAUGHT_oclIsKindOf_2 == ValueUtil.TRUE_VALUE) {
									or_0 = ValueUtil.TRUE_VALUE;
								}
								else {
									if (CAUGHT_or instanceof InvalidValueException) {
										throw (InvalidValueException)CAUGHT_or;
									}
									if (CAUGHT_oclIsKindOf_2 instanceof InvalidValueException) {
										throw (InvalidValueException)CAUGHT_oclIsKindOf_2;
									}
									if (CAUGHT_or == null) {
										or_0 = null;
									}
									else {
										or_0 = ValueUtil.FALSE_VALUE;
									}
								}
							}
							CAUGHT_or_0 = or_0;
						}
						catch (Exception e) {
							CAUGHT_or_0 = ValueUtil.createInvalidValue(e);
						}
						if (CAUGHT_or_0 == ValueUtil.FALSE_VALUE) {
							and = ValueUtil.FALSE_VALUE;
						}
						else {
							if (CAUGHT_or_0 instanceof InvalidValueException) {
								throw (InvalidValueException)CAUGHT_or_0;
							}
							if (CAUGHT_or_0 == null) {
								and = null;
							}
							else {
								and = ValueUtil.TRUE_VALUE;
							}
						}
					}
					CAUGHT_and = and;
				}
				catch (Exception e) {
					CAUGHT_and = ValueUtil.createInvalidValue(e);
				}
				if (CAUGHT_and == ValueUtil.TRUE_VALUE) {
					or_1 = ValueUtil.TRUE_VALUE;
				}
				else {
					if (CAUGHT_and instanceof InvalidValueException) {
						throw (InvalidValueException)CAUGHT_and;
					}
					if (CAUGHT_and == null) {
						or_1 = null;
					}
					else {
						or_1 = ValueUtil.FALSE_VALUE;
					}
				}
			}
			CAUGHT_or_1 = or_1;
		}
		catch (Exception e) {
			CAUGHT_or_1 = ValueUtil.createInvalidValue(e);
		}
		final /*@Thrown*/ Boolean and_0;
		if (CAUGHT_or_1 == ValueUtil.FALSE_VALUE) {
			and_0 = ValueUtil.FALSE_VALUE;
		}
		else {
			final /*@NonInvalid*/ List<ParameterBinding> argument = this.getArgument();
			final /*@NonInvalid*/ OrderedSetValue BOXED_argument = idResolver.createOrderedSetOfAll(tdlTables.ORD_CLSSid_ParameterBinding, argument);
			/*@Thrown*/ Object accumulator = ValueUtil.TRUE_VALUE;
			Iterator<Object> ITERATOR_a = BOXED_argument.iterator();
			/*@NonInvalid*/ Boolean forAll;
			while (true) {
				if (!ITERATOR_a.hasNext()) {
					if (accumulator == ValueUtil.TRUE_VALUE) {
						forAll = ValueUtil.TRUE_VALUE;
					}
					else {
						throw (InvalidValueException)accumulator;
					}
					break;
				}
				/*@NonInvalid*/ ParameterBinding a = (ParameterBinding)ITERATOR_a.next();
				/**
				 * a.dataUse.isEffectivelyStatic()
				 */
				final /*@NonInvalid*/ DataUse dataUse = a.getDataUse();
				final /*@NonInvalid*/ boolean isEffectivelyStatic = dataUse.isEffectivelyStatic();
				//
				if (!isEffectivelyStatic) {					// Normal unsuccessful body evaluation result
					forAll = ValueUtil.FALSE_VALUE;
					break;														// Stop immediately
				}
				else if (isEffectivelyStatic) {				// Normal successful body evaluation result
					;															// Carry on
				}
				else {															// Impossible badly typed result
					accumulator = new InvalidValueException(PivotMessages.NonBooleanBody, "forAll");
				}
			}
			if (forAll == ValueUtil.FALSE_VALUE) {
				and_0 = ValueUtil.FALSE_VALUE;
			}
			else {
				if (CAUGHT_or_1 instanceof InvalidValueException) {
					throw (InvalidValueException)CAUGHT_or_1;
				}
				if ((CAUGHT_or_1 == null) || (forAll == null)) {
					and_0 = null;
				}
				else {
					and_0 = ValueUtil.TRUE_VALUE;
				}
			}
		}
		if (and_0 == null) {
			throw new InvalidValueException("Null body for \'tdl::DataUse::isEffectivelyStatic() : Boolean[1]\'");
		}
		return and_0;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public NotificationChain eInverseRemove(InternalEObject otherEnd, int featureID, NotificationChain msgs)
	{
		switch (featureID) {
			case tdlPackage.DATA_USE__ARGUMENT:
				return ((InternalEList<?>)getArgument()).basicRemove(otherEnd, msgs);
			case tdlPackage.DATA_USE__REDUCTION:
				return ((InternalEList<?>)getReduction()).basicRemove(otherEnd, msgs);
		}
		return super.eInverseRemove(otherEnd, featureID, msgs);
	}

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

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void eSet(int featureID, Object newValue)
	{
		switch (featureID) {
			case tdlPackage.DATA_USE__ARGUMENT:
				getArgument().clear();
				getArgument().addAll((Collection<? extends ParameterBinding>)newValue);
				return;
			case tdlPackage.DATA_USE__REDUCTION:
				getReduction().clear();
				getReduction().addAll((Collection<? extends MemberReference>)newValue);
				return;
		}
		super.eSet(featureID, newValue);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public void eUnset(int featureID)
	{
		switch (featureID) {
			case tdlPackage.DATA_USE__ARGUMENT:
				getArgument().clear();
				return;
			case tdlPackage.DATA_USE__REDUCTION:
				getReduction().clear();
				return;
		}
		super.eUnset(featureID);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public boolean eIsSet(int featureID)
	{
		switch (featureID) {
			case tdlPackage.DATA_USE__ARGUMENT:
				return argument != null && !argument.isEmpty();
			case tdlPackage.DATA_USE__REDUCTION:
				return reduction != null && !reduction.isEmpty();
		}
		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.DATA_USE___RESOLVE_DATA_TYPE:
				return resolveDataType();
			case tdlPackage.DATA_USE___IS_EFFECTIVELY_STATIC:
				return isEffectivelyStatic();
		}
		return super.eInvoke(operationID, arguments);
	}

} //DataUseImpl
