/**
 * Copyright (c) 2002-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 v2.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v20.html
 * 
 * Contributors: 
 *   IBM - Initial API and implementation
 */
package org.eclipse.emf.codegen.ecore.genmodel.impl;

import org.eclipse.emf.codegen.ecore.genmodel.GenClass;
import org.eclipse.emf.codegen.ecore.genmodel.GenClassifier;
import org.eclipse.emf.codegen.ecore.genmodel.GenDataType;
import org.eclipse.emf.codegen.ecore.genmodel.GenEnum;
import org.eclipse.emf.codegen.ecore.genmodel.GenFeature;
import org.eclipse.emf.codegen.ecore.genmodel.GenJDKLevel;
import org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage;
import org.eclipse.emf.codegen.ecore.genmodel.GenPackage;
import org.eclipse.emf.codegen.ecore.genmodel.GenTypedElement;
import org.eclipse.emf.codegen.util.CodeGenUtil;
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.EClassifier;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EGenericType;
import org.eclipse.emf.ecore.EModelElement;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.ETypeParameter;
import org.eclipse.emf.ecore.ETypedElement;
import org.eclipse.emf.ecore.impl.ENotificationImpl;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.util.EcoreValidator;
import org.eclipse.emf.ecore.xml.type.XMLTypePackage;

/**
 * <!-- begin-user-doc -->
 * An implementation of the model object '<em><b>Gen Typed Element</b></em>'.
 * <!-- end-user-doc -->
 * <p>
 * The following features are implemented:
 * </p>
 * <ul>
 *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenTypedElementImpl#getDocumentation <em>Documentation</em>}</li>
 * </ul>
 *
 * @generated
 */
public abstract class GenTypedElementImpl extends GenBaseImpl implements GenTypedElement
{
  /**
   * The default value of the '{@link #getDocumentation() <em>Documentation</em>}' attribute.
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @see #getDocumentation()
   * @since 2.14
   * @generated
   * @ordered
   */
  protected static final String DOCUMENTATION_EDEFAULT = null;
  /**
   * The cached value of the '{@link #getDocumentation() <em>Documentation</em>}' attribute.
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @see #getDocumentation()
   * @since 2.14
   * @generated
   * @ordered
   */
  protected String documentation = DOCUMENTATION_EDEFAULT;

  /**
   * This is true if the Documentation attribute has been set.
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @since 2.14
   * @generated
   * @ordered
   */
  protected boolean documentationESet;

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

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

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @since 2.14
   * @generated
   */
  public String getDocumentationGen()
  {
    return documentation;
  }

  @Override
  public String getDocumentation()
  {
    return isSetDocumentation() ? getDocumentationGen() : super.getDocumentation();
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @since 2.14
   * @generated
   */
  public void setDocumentation(String newDocumentation)
  {
    String oldDocumentation = documentation;
    documentation = newDocumentation;
    boolean oldDocumentationESet = documentationESet;
    documentationESet = true;
    if (eNotificationRequired())
      eNotify(new ENotificationImpl(this, Notification.SET, GenModelPackage.GEN_TYPED_ELEMENT__DOCUMENTATION, oldDocumentation, documentation, !oldDocumentationESet));
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @since 2.14
   * @generated
   */
  public void unsetDocumentation()
  {
    String oldDocumentation = documentation;
    boolean oldDocumentationESet = documentationESet;
    documentation = DOCUMENTATION_EDEFAULT;
    documentationESet = false;
    if (eNotificationRequired())
      eNotify(new ENotificationImpl(this, Notification.UNSET, GenModelPackage.GEN_TYPED_ELEMENT__DOCUMENTATION, oldDocumentation, DOCUMENTATION_EDEFAULT, oldDocumentationESet));
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @since 2.14
   * @generated
   */
  public boolean isSetDocumentation()
  {
    return documentationESet;
  }

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

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

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  @Override
  public void eUnset(int featureID)
  {
    switch (featureID)
    {
      case GenModelPackage.GEN_TYPED_ELEMENT__DOCUMENTATION:
        unsetDocumentation();
        return;
    }
    super.eUnset(featureID);
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  @Override
  public boolean eIsSet(int featureID)
  {
    switch (featureID)
    {
      case GenModelPackage.GEN_TYPED_ELEMENT__DOCUMENTATION:
        return isSetDocumentation();
    }
    return super.eIsSet(featureID);
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  @Override
  public String toString()
  {
    if (eIsProxy()) return super.toString();

    StringBuilder result = new StringBuilder(super.toString());
    result.append(" (documentation: ");
    if (documentationESet) result.append(documentation); else result.append("<unset>");
    result.append(')');
    return result.toString();
  }

  public abstract ETypedElement getEcoreTypedElement();

  @Override
  public EModelElement getEcoreModelElement()
  {
    return getEcoreTypedElement();
  }

  public GenPackage getTypeGenPackage()
  {
    return findGenPackage(getEcoreTypedElement().getEType().getEPackage());
  }

  public String getTypeClassifierAccessorName()
  {
    return findGenClassifier(getEcoreTypedElement().getEType()).getClassifierAccessorName();
  }

  /**
   * @deprecated As of EMF 2.1, replaced by {@link #getTypeClassifierAccessorName}. 
   */
  @Deprecated
  public String getTypeClassifier()
  {
    return getTypeClassifierAccessorName();
  }

  protected GenClass getContext()
  {
    for (EObject context = eContainer(); context != null; context = context.eContainer())
    {
      if (context instanceof GenClass)
      {
        return (GenClass)context;
      }
    }
    return null;
  }

  public boolean hasGenericType()
  {
    if (getEffectiveComplianceLevel().getValue() >= GenJDKLevel.JDK50)
    {
      EGenericType eGenericType = getEcoreTypedElement().getEGenericType();
      return eGenericType != null && (eGenericType.getETypeParameter() != null || !eGenericType.getETypeArguments().isEmpty());
    }
    return false;
  }

  public String getRawType()
  {
    if (isFeatureMapType()) return getEffectiveFeatureMapWrapperInterface();
    if (isMapType()) return getEffectiveMapType();
    if (isListType()) return getEffectiveListType();
    if (isMapEntryType()) return getEffectiveMapType();
    if (isEObjectType()) return getEffectiveEObjectType();
    return getType(getContext(), getEcoreTypedElement().getEType(), false, true);
  }

  public String getRawBoundType()
  {
    if (isFeatureMapType()) return getEffectiveFeatureMapWrapperInterface();
    if (isMapType()) return getEffectiveMapType();
    if (isListType()) return getEffectiveListType();
    if (isMapEntryType()) return getEffectiveMapEntryType();
    if (isEObjectType()) return getEffectiveEObjectType();
    return getType(getContext(), getBoundType(getEcoreTypedElement().getEGenericType()), false, true);
  }

  @Deprecated
  public String getType()
  {
    return getType(getContext());
  }

  public String getType(GenClass context)
  {
    if (isFeatureMapType()) return getEffectiveFeatureMapWrapperInterface();
    if (isMapType()) return getEffectiveMapType(context, getEcoreTypedElement().getEGenericType(), getMapEntryTypeGenClass());
    if (isMapEntryType()) 
      if (isListType())
        if (getEffectiveComplianceLevel().getValue() < GenJDKLevel.JDK50) return getEffectiveListType();
        else return getEffectiveListType() + "<" + getEffectiveMapEntryType(context, getEcoreTypedElement().getEGenericType(), getMapEntryTypeGenClass()) + ">";
      else return getEffectiveMapEntryType(context, getEcoreTypedElement().getEGenericType(), getMapEntryTypeGenClass());
    if (isListType()) return getEffectiveListType(context, getEcoreTypedElement().getEGenericType());
    if (isEObjectType()) return getEffectiveEObjectType();
    if (isListDataType() && getEffectiveComplianceLevel().getValue() >= GenJDKLevel.JDK50)
    {
      return "java.util.List<" + getType(context, getListDataType().getEcoreDataType(), true) + ">";
    }
    return getType(context, getEcoreTypedElement().getEGenericType(), false);
  }

  public String getRawImportedType()
  {
    if (isFeatureMapType()) return getGenModel().getImportedName(getEffectiveFeatureMapWrapperInterface());
    if (isMapType()) return getGenModel().getImportedName(getEffectiveMapType());
    if (isListType()) return getGenModel().getImportedName(getEffectiveListType());
    if (isMapEntryType()) return getGenModel().getImportedName(getEffectiveMapEntryType());
    if (isEObjectType()) return getGenModel().getImportedName(getEffectiveEObjectType());
    return getImportedType(null, getEcoreTypedElement().getEType(), false);
  }

  public String getRawImportedBoundType()
  {
    if (isFeatureMapType()) return getGenModel().getImportedName(getEffectiveFeatureMapWrapperInterface());
    if (isMapType()) return getGenModel().getImportedName(getEffectiveMapType());
    if (isListType()) return getGenModel().getImportedName(getEffectiveListType());
    if (isMapEntryType()) return getGenModel().getImportedName(getEffectiveMapEntryType());
    if (isEObjectType()) return getGenModel().getImportedName(getEffectiveEObjectType());
    return getImportedType(null, getBoundType(getEcoreTypedElement().getEGenericType()), false, true);
  }

  @Deprecated
  public String getImportedType()
  {
    return getImportedType(getContext());
  }

  public String getImportedType(GenClass context)
  {
    if (isFeatureMapType()) return getGenModel().getImportedName(getEffectiveFeatureMapWrapperInterface());
    if (isMapType()) return getGenModel().getImportedName(getEffectiveMapType(context, getEcoreTypedElement().getEGenericType(), getMapEntryTypeGenClass()));
    if (isMapEntryType()) 
      if (isListType())
        if (getEffectiveComplianceLevel().getValue() < GenJDKLevel.JDK50) return getGenModel().getImportedName(getEffectiveListType());
        else return getGenModel().getImportedName(getEffectiveListType() + "<" + getEffectiveMapEntryType(context, getEcoreTypedElement().getEGenericType(), getMapEntryTypeGenClass()) + ">");
      else return getGenModel().getImportedName(getEffectiveMapEntryType(context, getEcoreTypedElement().getEGenericType(), getMapEntryTypeGenClass()));
    if (isListType()) return getGenModel().getImportedName(getEffectiveListType(context, getEcoreTypedElement().getEGenericType()));
    if (isEObjectType()) return getGenModel().getImportedName(getEffectiveEObjectType());
    if (isListDataType() && getEffectiveComplianceLevel().getValue() >= GenJDKLevel.JDK50)
    {
      return getGenModel().getImportedName("java.util.List") + "<" + getImportedType(context, getListDataType().getEcoreDataType(), true) + ">";
    }
    return getImportedType(context, getEcoreTypedElement().getEGenericType(), false);
  }

  @Deprecated
  public String getObjectType()
  {
    return getObjectType(getContext()); 
  }

  public String getObjectType(GenClass context)
  {
    if (isFeatureMapType()) return getGenModel().getImportedName(getEffectiveFeatureMapWrapperInterface());
    if (isMapType()) return getGenModel().getImportedName(getEffectiveMapType(context, getEcoreTypedElement().getEGenericType(), getMapEntryTypeGenClass()));
    if (isMapEntryType())
      if (isListType())
        if (getEffectiveComplianceLevel().getValue() < GenJDKLevel.JDK50) return getGenModel().getImportedName(getEffectiveListType());
        else return getGenModel().getImportedName(getEffectiveListType() + "<" + getEffectiveMapEntryType(context, getEcoreTypedElement().getEGenericType(), getMapEntryTypeGenClass()) + ">");
      else return getGenModel().getImportedName(getEffectiveMapEntryType(context, getEcoreTypedElement().getEGenericType(), getMapEntryTypeGenClass()));
    if (isListType()) return getGenModel().getImportedName(getEffectiveListType(context, getEcoreTypedElement().getEGenericType()));
    if (isEObjectType()) return getGenModel().getImportedName(getEffectiveEObjectType());
    if (isListDataType() && getEffectiveComplianceLevel().getValue() >= GenJDKLevel.JDK50)
    {
      return getGenModel().getImportedName("java.util.List") + "<" + getImportedType(context, getListDataType().getEcoreDataType(), true) + ">";
    }
    return getImportedType(context, getEcoreTypedElement().getEGenericType(), true);
  }

  public String getQualifiedObjectType(GenClass context)
  {
    if (isFeatureMapType()) return getEffectiveFeatureMapWrapperInterface();
    if (isMapType()) return getEffectiveMapType(context, getEcoreTypedElement().getEGenericType(), getMapEntryTypeGenClass());
    if (isMapEntryType())
      if (isListType())
        if (getEffectiveComplianceLevel().getValue() < GenJDKLevel.JDK50) return getEffectiveListType();
        else return getEffectiveListType() + "<" + /*x*/getEffectiveMapEntryType(context, getEcoreTypedElement().getEGenericType(), getMapEntryTypeGenClass()) + ">";
      else return getEffectiveMapEntryType(context, getEcoreTypedElement().getEGenericType(), getMapEntryTypeGenClass());
    if (isListType()) return getEffectiveListType(context, getEcoreTypedElement().getEGenericType());
    if (isEObjectType()) return getEffectiveEObjectType();
    if (isListDataType() && getEffectiveComplianceLevel().getValue() >= GenJDKLevel.JDK50)
    {
      return "java.util.List<" + getType(context, getListDataType().getEcoreDataType(), true) + ">";
    }
    return getType(context, getEcoreTypedElement().getEGenericType(), true);
  }

  @Deprecated
  public String getImportedInternalType()
  {
    return getImportedInternalType(getContext());
  }

  public String getImportedInternalType(GenClass context)
  {
    if (isFeatureMapType())
       return
         isBlank(getGenModel().getFeatureMapWrapperInternalInterface()) ?
             getImportedEffectiveFeatureMapWrapperClass() :
             getImportedEffectiveFeatureMapWrapperInternalInterface();
    if (isMapType()) return getGenModel().getImportedName("org.eclipse.emf.common.util.EMap") + getImportedMapTemplateArguments(context); 
    if (isMapEntryType())
      if (isListType())
        if (getEffectiveComplianceLevel().getValue() < GenJDKLevel.JDK50) return getGenModel().getImportedName("org.eclipse.emf.common.util.EList");
        else return getGenModel().getImportedName("org.eclipse.emf.common.util.EList") + "<" + getGenModel().getImportedName("java.util.Map$Entry") + getImportedMapTemplateArguments(context) + ">"; 
      else return getGenModel().getImportedName("java.util.Map$Entry") + getImportedMapTemplateArguments(context); 
    if (isListType()) return getGenModel().getImportedName("org.eclipse.emf.common.util.EList") + getListTemplateArguments(context);
    if (isListDataType() && getEffectiveComplianceLevel().getValue() >= GenJDKLevel.JDK50)
    {
      return getGenModel().getImportedName("java.util.List") + "<" + getImportedType(context, getListDataType().getEcoreDataType(), true) + ">";
    }
    return getImportedType(context, getEcoreTypedElement().getEGenericType(), false);
  }

  public boolean isFeatureMapType()
  {
    EClassifier type = getEcoreTypedElement().getEType();
    return type != null && isFeatureMapEntry(getEcoreTypedElement().getEType().getInstanceClassName());
  }

  protected static boolean isFeatureMapEntry(String name)
  {
    return "org.eclipse.emf.ecore.util.FeatureMap.Entry".equals(name) || "org.eclipse.emf.ecore.util.FeatureMap$Entry".equals(name);
  } 

  public boolean isWrappedFeatureMapType()
  {
    return 
      isFeatureMapType() &&  
        !isBlank(getGenModel().getFeatureMapWrapperInterface()) &&
        !isBlank(getGenModel().getFeatureMapWrapperClass());    
  }

  /**
   * @deprecated As of EMF 2.1, replaced by {@link #isWrappedFeatureMapType}. 
   */
  @Deprecated
  public boolean isFeatureMapWrapped()
  {
    return isWrappedFeatureMapType();
  }

  @Override
  public GenJDKLevel getEffectiveComplianceLevel()
  {
    return super.getEffectiveComplianceLevel();
  }

  @Override
  public boolean isEffectiveSuppressEMFTypes()
  {
    return super.isEffectiveSuppressEMFTypes();
  }

  @Override
  public String getImportedEffectiveFeatureMapWrapperInternalInterface()
  {
    return super.getImportedEffectiveFeatureMapWrapperInternalInterface();
  }

  @Override
  public String getImportedEffectiveFeatureMapWrapperClass()
  {
    return super.getImportedEffectiveFeatureMapWrapperClass();
  }

  public boolean isListType()
  {
    ETypedElement eTypedElement = getEcoreTypedElement();
    return 
      eTypedElement != null &&
        (eTypedElement.isMany() || 
          isFeatureMapType() ||
          eTypedElement.getUpperBound() == ETypedElement.UNSPECIFIED_MULTIPLICITY &&
            eTypedElement instanceof EStructuralFeature && 
            XMLTypePackage.eNS_URI.equals(getExtendedMetaData().getNamespace((EStructuralFeature)eTypedElement)));
  }

  public boolean isListDataType()
  {
    GenDataType genDataType = getTypeGenDataType();
    return genDataType != null && ((GenDataTypeImpl)genDataType).getEffectiveItemType() != null;
  }

  public GenDataType getListDataType()
  {
    GenDataType genDataType = getTypeGenDataType();
    return genDataType == null ? null : ((GenDataTypeImpl)genDataType).getEffectiveItemType();
  }

  public String getListTemplateArguments(GenClass context)
  {
    return getEffectiveComplianceLevel().getValue() <= GenJDKLevel.JDK14 ? "" : "<" + getListItemType(context) + ">";
  }

  @Deprecated
  public String getListItemType()
  {
    return getListItemType(getContext());
  }

  public String getListItemType(GenClass context)
  {
    if (isMapEntryType()) return getGenModel().getImportedName(getEffectiveMapEntryType(context, getEcoreTypedElement().getEGenericType(), getMapEntryTypeGenClass()));
    return getImportedType(context, getEcoreTypedElement().getEGenericType(), true);
  }

  public String getRawListItemType()
  {
    return getImportedType(getContext(), getEcoreTypedElement().getEType(), true, true);
  }

  public String getRawListItemType(GenClass context)
  {
    return getGenModel().useGenerics() ? getTypeArgument(context, getEcoreTypedElement().getEGenericType(), true, true) : getImportedType(context, getEcoreTypedElement().getEType(), true, true);
  }

  public String getArrayItemType(GenClass context)
  {
    if (getGenModel().useGenerics())
    {
      EGenericType eGenericType = getEcoreTypedElement().getEGenericType();
      eGenericType = EcoreUtil.getReifiedType(context.getEcoreClass(), eGenericType);
      ETypeParameter eTypeParameter = eGenericType.getETypeParameter();
      if (eTypeParameter != null)
      {
        EList<EGenericType> eBounds = eTypeParameter.getEBounds();
        if (eBounds.isEmpty())
        {
          return getImportedType(context, eGenericType.getERawType(), true, true);
        }
        else
        {
          return getTypeArgument(context, eBounds.get(0), true, false);
        }
      }
      else
      {
        return getTypeArgument(context, eGenericType, true, false);
      }
    }
    else
    {
      return getRawListItemType(null);
    }
  }

  @Deprecated
  public String getQualifiedListItemType()
  {
    return getQualifiedListItemType(getContext());
  }

  public String getQualifiedListItemType(GenClass context)
  {
    if (isMapEntryType()) return getEffectiveMapEntryType(context, getEcoreTypedElement().getEGenericType(), getMapEntryTypeGenClass()).replace('$', '.');
    return getType(context, getEcoreTypedElement().getEGenericType(), true).replace('$', '.');
  }

  public boolean isMapType()
  {
    return isListType() && getMapGenClass() != null;
  }

  public boolean isMapEntryType()
  {
    return getMapEntryTypeGenClass() != null;
  }

  public GenClass getMapEntryTypeGenClass()
  {
    EClassifier eType = getEcoreTypedElement().getEType();
    if (eType instanceof EClass && isJavaUtilMapEntry(eType.getInstanceClassName()))
    {
      GenClass genClass = findGenClass((EClass)eType);
      if (genClass.isMapEntry())
      {
        return genClass;
      }
    }
    return null;
  }

  public String getImportedMapEntryType()
  {
    GenClass genClass = getMapEntryTypeGenClass();
    return genClass == null ? null : genClass.getImportedClassName();
  }
  
  public String getImportedMapKeyType(GenClass context)
  {
    EGenericType eGenericType = getEcoreTypedElement().getEGenericType();
    if (eGenericType.getETypeArguments().size() == 2)
    {
      return getTypeArgument(context,eGenericType.getETypeArguments().get(0), true, false);
    }
    else
    {
      GenClass genClass = getMapEntryTypeGenClass();
      return genClass == null ? null : genClass.getMapEntryKeyFeature().getImportedType(context);
    }
  }

  public String getImportedMapValueType(GenClass context)
  {
    EGenericType eGenericType = getEcoreTypedElement().getEGenericType();
    if (eGenericType.getETypeArguments().size() == 2)
    {
      return getTypeArgument(context,eGenericType.getETypeArguments().get(1), true, false);
    }
    else
    {
      GenClass genClass = getMapEntryTypeGenClass();
      return genClass == null ? null : genClass.getMapEntryValueFeature().getImportedType(context);
    }
  }
  
  public String getImportedMapTemplateArguments(GenClass context)
  {
    return 
      getEffectiveComplianceLevel().getValue() <= GenJDKLevel.JDK14 ? 
        ""  : 
        "<" + getImportedMapKeyType(context) + ", " + getImportedMapValueType(context) + ">";
  }

  /**
   * @deprecated As of EMF 2.1, replaced by {@link #getMapEntryTypeGenClass}.
   */
  @Deprecated
  public GenClass getMapGenClass()
  {
    return getMapEntryTypeGenClass();
  }

  /**
   * @deprecated As of EMF 2.1, replaced by {@link #getImportedMapEntryType}.
   */
  @Deprecated
  public String getMapItemType()
  {
    return getImportedMapEntryType();
  }

  protected boolean isEObjectType()
  {
    if (getEffectiveComplianceLevel().getValue() >= GenJDKLevel.JDK50)
    {
      EGenericType eGenericType = getEcoreTypedElement().getEGenericType();
      if (eGenericType.getETypeParameter() != null)
      {
        return false;
      }
    }
    EClassifier type = getEcoreTypedElement().getEType();
    GenClassifier genClassifier = findGenClassifier(type);
    return genClassifier instanceof GenClass &&  ((GenClass)genClassifier).isEObject();
  }

  protected boolean hasEObjectBound(ETypeParameter eTypeParameter)
  {
    for (EGenericType eBound : eTypeParameter.getEBounds())
    {
      if (eBound.getETypeParameter() != null && hasEObjectExtensionBound(eBound.getETypeParameter()) ||
            eBound.getEClassifier() instanceof EClass  && findGenClass((EClass)eBound.getEClassifier()).isEObject())
      {
        return true;
      }
    }
    return false;
  }

  protected boolean isEObjectExtensionType()
  {
    if (getEffectiveComplianceLevel().getValue() >= GenJDKLevel.JDK50)
    {
      EGenericType eGenericType = getEcoreTypedElement().getEGenericType();
      if (eGenericType.getETypeParameter() != null)
      {
        return hasEObjectExtensionBound(eGenericType.getETypeParameter());
      }
    }
    EClassifier type = getEcoreTypedElement().getEType();
    return type instanceof EClass && findGenClass((EClass)type).isEObjectExtension();
  }

  protected boolean hasEObjectExtensionBound(ETypeParameter eTypeParameter)
  {
    for (EGenericType eBound : eTypeParameter.getEBounds())
    {
      if (eBound.getETypeParameter() != null ? 
            hasEObjectExtensionBound(eBound.getETypeParameter()) :
            eBound.getEClassifier() instanceof EClass && findGenClass((EClass)eBound.getEClassifier()).isEObjectExtension())
      {
        return true;
      }
    }
    return false;
  }
  
  public boolean isUncheckedCast()
  {
    return isUncheckedCast(getContext());
  }

  public boolean isUncheckedCast(GenClass context)
  {
    GenClassifier type = getTypeGenClassifier();
    if (type != null && type.isUncheckedCast())
    {
      return true;
    }
    if (isListType() || isListDataType() || isMapEntryType())
    {
      return true;
    }
    EGenericType actualEGenericType = getEcoreTypedElement().getEGenericType();
    if (actualEGenericType == null)
    {
      return false;
    }
    String substitutedType = getTypeArgument(context, actualEGenericType, false, false);
    EGenericType eGenericType = EcoreValidator.EGenericTypeBuilder.INSTANCE.buildEGenericType(substitutedType);
    if (eGenericType != null)
    {
      // Type parameter casts can't be checked.
      //
      if (eGenericType.getETypeParameter() != null)
      {
        return true;
      }
      else
      {
        EClassifier eClassifier = eGenericType.getEClassifier();
        if (eClassifier != null)
        {
          String instanceTypeName = eClassifier.getInstanceTypeName();
          if (instanceTypeName != null)
          {
            int index = instanceTypeName.indexOf('[');
            if (index != -1)
            {
              instanceTypeName = instanceTypeName.substring(0, index);
            }
            if (instanceTypeName.indexOf('.') == -1 && !CodeGenUtil.isJavaPrimitiveType(instanceTypeName))
            {
              return true;
            }
          }
          // If there are any arguments and they are not unbounded wildcards, casts can't be checked.
          //
          for (EGenericType eTypeArgument : eGenericType.getETypeArguments())
          {
            if (eTypeArgument.getETypeParameter() != null ||
                  eTypeArgument.getEClassifier() != null ||
                  eTypeArgument.getEUpperBound() != null ||
                  eTypeArgument.getELowerBound() != null)
            {
              return true;
            }
          }
        }
      }
    }
    return false;
  }

  public String getEObjectCast()
  {
    return !isEObjectExtensionType() || (isEObjectType() && isEffectiveSuppressEMFTypes()) ?
      "(" + getGenModel().getImportedName("org.eclipse.emf.ecore.EObject") + ")" : "";
  }

  public String getInternalTypeCast()
  {
    return isEObjectType() && isEffectiveSuppressEMFTypes() ? 
      "(" + getGenModel().getImportedName("org.eclipse.emf.ecore.EObject") + ")" : "";
  }

  @Deprecated
  public String getNonEObjectInternalTypeCast()
  {
    return getNonEObjectInternalTypeCast(getContext());
  }

  public String getNonEObjectInternalTypeCast(GenClass context)
  {
    return isEObjectType() ? "" : "(" + getImportedInternalType(context) + ")";
  }
  
  public String getRawTypeCast()
  {
    return getType(null).equals(getRawType()) ? "" : "(" + getImportedType(null) + ")";
  }

  public boolean isPrimitiveType()
  {
    return !isListType() && isPrimitiveType(getEcoreTypedElement().getEType());
  }

  public String getPrimitiveValueFunction()
  {
    Class<?> instanceClass = getInstanceClass(getEcoreTypedElement().getEType());
    if (instanceClass == java.lang.Boolean.TYPE)
      return "booleanValue";
    if (instanceClass == java.lang.Byte.TYPE)
      return "byteValue";
    if (instanceClass == java.lang.Character.TYPE)
      return "charValue";
    if (instanceClass == java.lang.Double.TYPE)
      return "doubleValue";
    if (instanceClass == java.lang.Float.TYPE)
      return "floatValue";
    if (instanceClass == java.lang.Integer.TYPE)
      return "intValue";
    if (instanceClass == java.lang.Long.TYPE)
      return "longValue";
    if (instanceClass == java.lang.Short.TYPE)
      return "shortValue";
    return null;
  }

  public boolean isBooleanType()
  {
    return isPrimitiveType() && getInstanceClass(getEcoreTypedElement().getEType()) == java.lang.Boolean.TYPE;
  }

  public boolean isStringType()
  {
    return !isListType() && getInstanceClass(getEcoreTypedElement().getEType()) == java.lang.String.class;
  }

  // Like isStringType(), but still returns true even if multiplicity-many.
  //
  public boolean isStringBasedType()
  {
    return getInstanceClass(getEcoreTypedElement().getEType()) == java.lang.String.class;
  }

  public boolean isEnumType()
  {
    return !isListType() && getEcoreTypedElement().getEType() instanceof EEnum;
  }

  public boolean isEnumBasedType()
  {
    return getEcoreTypedElement().getEType() instanceof EEnum;
  }

  public GenEnum getTypeGenEnum()
  {
    EClassifier eType = getEcoreTypedElement().getEType();
    return eType instanceof EEnum ? findGenEnum((EEnum)eType) : null;
  }

  public GenDataType getTypeGenDataType()
  {
    EClassifier eType = getEcoreTypedElement().getEType();
    return eType instanceof EDataType ? findGenDataType((EDataType)eType) : null;
  }

  public GenClass getTypeGenClass()
  {
    EClassifier eType = getEcoreTypedElement().getEType();
    return eType instanceof EClass ? findGenClass((EClass)eType) : null;
  }

  public GenClassifier getTypeGenClassifier()
  {
    EClassifier eType = getEcoreTypedElement().getEType();
    return eType == null ? null : findGenClassifier(eType);
  }

  /**
   * @deprecated As of EMF 2.1, replaced by {@link #getTypeGenEnum}.
   */
  @Deprecated
  public GenEnum getGenEnumType()
  {
    return getTypeGenEnum();
  }

  /**
   * @deprecated As of EMF 2.1, replaced by {@link #getTypeGenDataType}.
   */
  @Deprecated
  public GenDataType getGenDataTypeType()
  {
    return getTypeGenDataType();
  }

  /**
   * @deprecated As of EMF 2.1, replaced by {@link #getTypeGenClass}.
   */
  @Deprecated
  public GenClass getGenClassType()
  {
    return getTypeGenClass();
  }

  public String getLowerBound()
  {
    return String.valueOf(getEcoreTypedElement().getLowerBound());
  }

  public String getUpperBound()
  {
    return String.valueOf(getEcoreTypedElement().getUpperBound());
  }

  public boolean isUnique()
  {
    return getEcoreTypedElement().isUnique();
  }

  public String getUniqueFlag()
  {
    String result = !isUnique() ? "!" : "";
    return result + "IS_UNIQUE";
  }

  public String getOrderedFlag()
  {
    String result = !getEcoreTypedElement().isOrdered() ? "!" : "";
    return result + "IS_ORDERED";
  }

  protected void appendModelSetting(StringBuffer result, boolean qualified, String name, String value)
  {
    appendModelSetting(result, qualified ? getEcoreTypedElement().getName() : null, name, value);
  }

  protected String getMapModelInfo(boolean qualified, boolean includeFeatures)
  {
    GenClass mapGenClass = getMapEntryTypeGenClass();
    if (mapGenClass != null)
    {
      StringBuffer result = new StringBuffer();

      GenFeature keyFeature = mapGenClass.getMapEntryKeyFeature();
      GenFeature valueFeature = mapGenClass.getMapEntryValueFeature();
      String mapType = mapGenClass.getGenPackage().getInterfacePackageName() + '.' + mapGenClass.getEcoreClass().getName();
      boolean useGenerics = getEffectiveComplianceLevel().getValue() >= GenJDKLevel.JDK50;
      if (useGenerics)
      {
        mapType += 
           '<' + 
             getEcoreType(keyFeature.getEcoreFeature().getEGenericType()) + ", " + 
             getEcoreType(valueFeature.getEcoreFeature().getEGenericType()) + '>';
      }
      appendModelSetting(result, qualified, "mapType", mapType);

      if (includeFeatures && !useGenerics)
      {
        appendModelSetting(result, qualified, "keyType", getType(getContext(), keyFeature.getEcoreFeature().getEType(), false));
  
        appendModelSetting(result, qualified, "valueType", getType(getContext(), valueFeature.getEcoreFeature().getEType(), false));
      }

      return result.toString();
    }

    return null;
  }

  protected String getMultiplicityModelInfo(boolean qualified)
  {
    ETypedElement eTypedElement = getEcoreTypedElement();
    StringBuffer result = new StringBuffer();

    int lowerBound = eTypedElement.getLowerBound();
    if (lowerBound == 1)
    {
      appendModelSetting(result, qualified, "required", "true");
    }
    else if (lowerBound > 1)
    {
      appendModelSetting(result, qualified, "lower", Integer.toString(lowerBound));
    }
    
    int upperBound = eTypedElement.getUpperBound();
    if (upperBound > 1 || upperBound < -1)
    {
      appendModelSetting(result, qualified, "upper", Integer.toString(eTypedElement.getUpperBound()));
    }
    else if (upperBound == 1)
    {
      String typeName = getType(getContext(), eTypedElement.getEType(), false);
      if ("org.eclipse.emf.common.util.EList".equals(typeName) || "java.util.List".equals(typeName) || "org.eclipse.emf.ecore.util.FeatureMap$Entry".equals(typeName)) 
      {
        appendModelSetting(result, qualified, "many", "false");
      }
    }
    else if ((qualified || isFeatureMapType()) && upperBound == -1)
    {
      appendModelSetting(result, qualified, "many", "true");
    }

    return result.toString();
  }

} //GenTypedElementImpl
