/**
  * Walks up the containment hierarchy to find an EObject that is able to hold (contain) the given
  * object.
  */
 protected EObject findHookParent(
     EObject container,
     EClass startClass,
     org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ContainedFeature currentLink,
     EObject object) {
   EClass containerClass = currentLink.getContainerClass();
   while (container != null) {
     if (containerClass.isInstance(object)) {
       if (startClass.equals(container.eClass())) {
         return container;
       }
     }
     container = container.eContainer();
   }
   return null;
 }
  protected EObject findCorrectContainer(
      org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ExpectedTerminal expectedTerminal) {
    EObject container = expectedTerminal.getContainer();
    EClass ruleMetaclass = expectedTerminal.getTerminal().getRuleMetaclass();
    if (ruleMetaclass.isInstance(container)) {
      // container is correct for expected terminal
      return container;
    }
    // the container is wrong
    EObject parent = null;
    EObject previousParent = null;
    EObject correctContainer = null;
    EObject hookableParent = null;
    org.emftext.language.xpath3.resource.xpath3.grammar.Xpath3ContainmentTrace containmentTrace =
        expectedTerminal.getContainmentTrace();
    EClass startClass = containmentTrace.getStartClass();
    org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ContainedFeature currentLink = null;
    org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ContainedFeature previousLink = null;
    org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ContainedFeature[] containedFeatures =
        containmentTrace.getPath();
    for (int i = 0; i < containedFeatures.length; i++) {
      currentLink = containedFeatures[i];
      if (i > 0) {
        previousLink = containedFeatures[i - 1];
      }
      EClass containerClass = currentLink.getContainerClass();
      hookableParent = findHookParent(container, startClass, currentLink, parent);
      if (hookableParent != null) {
        // we found the correct parent
        break;
      } else {
        previousParent = parent;
        parent = containerClass.getEPackage().getEFactoryInstance().create(containerClass);
        if (parent != null) {
          if (previousParent == null) {
            // replace container for expectedTerminal with correctContainer
            correctContainer = parent;
          } else {
            // This assignment is only performed to get rid of a warning about a potential
            // null pointer access. Variable 'previousLink' cannot be null here, because it is
            // initialized for all loop iterations where 'i' is greather than 0 and for the
            // case where 'i' equals zero, this path is never executed, because
            // 'previousParent' is null in this case.
            org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ContainedFeature link =
                previousLink;
            org.emftext.language.xpath3.resource.xpath3.util.Xpath3EObjectUtil.setFeature(
                parent, link.getFeature(), previousParent, false);
          }
        }
      }
    }

    if (correctContainer == null) {
      correctContainer = container;
    }

    if (currentLink == null) {
      return correctContainer;
    }

    hookableParent = findHookParent(container, startClass, currentLink, parent);

    final EObject finalHookableParent = hookableParent;
    final EStructuralFeature finalFeature = currentLink.getFeature();
    final EObject finalParent = parent;
    if (parent != null && hookableParent != null) {
      expectedTerminal.setAttachmentCode(
          new Runnable() {

            public void run() {
              org.emftext.language.xpath3.resource.xpath3.util.Xpath3EObjectUtil.setFeature(
                  finalHookableParent, finalFeature, finalParent, false);
            }
          });
    }
    return correctContainer;
  }