private MappedClassInfo getMappedClassInfoForNonAliasedToken(
      CompletionParser cp, boolean matchNameExact) {
    MappedClassInfo ret = null;

    for (MappedClassInfo mappedClassInfo : _mappedClassInfos) {
      if (mappedClassInfo.matches(cp, true, true)) {
        // An exact match always ends search
        return mappedClassInfo;
      } else if (false == matchNameExact && mappedClassInfo.matches(cp, false, true)) {
        // We have a non exact match here.
        // Nonetheless we continue the loop to see if an exact match exists
        ret = mappedClassInfo;
      }

      if (cp.getStringToParse().startsWith(mappedClassInfo.getClassName())
          || cp.getStringToParse().startsWith(mappedClassInfo.getSimpleClassName())) {
        ArrayList<PropertyInfo> matchingAttributes =
            mappedClassInfo.getQualifiedMatchingAttributes(cp);
        for (PropertyInfo matchingAttribute : matchingAttributes) {
          if (matchingAttribute
              .getHibernatePropertyInfo()
              .getPropertyName()
              .equals(cp.getLastToken())) {
            return matchingAttribute.getMappedClassInfo();
          }
        }
      }
    }

    return ret;
  }
  public MappedClassInfo getMappedClassInfoFor(String token) {
    // Example for this code:
    // Completion should
    // from Kv k inner join fetch k.positionen as posses where posses.artNr = 'sdfsdf'

    CompletionParser cp = new CompletionParser(token);

    if (2 > cp.size()) {
      return getMappedClassInfoForNonAliasedToken(cp, true);
    }

    String aliasCandidate = cp.getToken(0);

    // We need this buffer because this method may be called asynchronously to the event dispatch
    // thread
    // What could happen is, that _currentAliasInfos ist changed.

    ArrayList<AliasInfo> buf = _currentAliasInfos;

    for (AliasInfo currentAliasInfo : buf) {
      if (currentAliasInfo.getCompareString().equals(aliasCandidate)) {
        ArrayList<PropertyInfo> matchingAttributes =
            currentAliasInfo.getQualifiedMatchingAttributes(cp);
        for (PropertyInfo matchingAttribute : matchingAttributes) {
          if (matchingAttribute
              .getHibernatePropertyInfo()
              .getPropertyName()
              .equals(cp.getLastToken())) {
            return matchingAttribute.getMappedClassInfo();
          }
        }
      }
    }

    return getMappedClassInfoForNonAliasedToken(cp, false);
  }
  public CompletionCandidates getInfosStartingWith(CompletionParser parser) {

    // Tricky alias and chaining completion examples
    //
    // au to auftr in
    // from Kv auftr where au
    //
    // au to auftr in
    // from Kv.positionen.kv auftr where au
    //
    // positionen. to fields of Kv aggregate positionen in
    // from Kv auftr where auftr.positionen.
    //
    // positionen. to fields of Kv aggregate positionen in
    // from Kv where positionen.

    ArrayList<CompletionInfo> ciClasses = new ArrayList<CompletionInfo>();
    ArrayList<CompletionInfo> ciAttrs = new ArrayList<CompletionInfo>();

    for (AliasInfo aliasInfo : _currentAliasInfos) {
      if (aliasInfo.matches(parser)) {
        ciClasses.add(aliasInfo);
      }
      ciAttrs.addAll(aliasInfo.getQualifiedMatchingAttributes(parser));
    }

    for (MappedClassInfo mappedClassInfo : _mappedClassInfos) {
      if (mappedClassInfo.matches(parser, false, false)) {
        ciClasses.add(mappedClassInfo);
      }

      ciAttrs.addAll(mappedClassInfo.getQualifiedMatchingAttributes(parser));
    }

    ArrayList<CompletionInfo> ret = new ArrayList<CompletionInfo>();
    MappedClassInfo lastFoundBuf = _lastFoundMappedClassInfo;
    if (null != lastFoundBuf) {
      if (1 == parser.size()) {
        ret.addAll(lastFoundBuf.getMatchingAttributes(parser));
      } else {

        for (PropertyInfo propertyInfo : lastFoundBuf.getAttributes()) {
          if (propertyInfo
              .getHibernatePropertyInfo()
              .getPropertyName()
              .equals(parser.getToken(0))) {
            MappedClassInfo mappedClassInfo = propertyInfo.getMappedClassInfo();
            CompletionParser simpleAttrFakeParser =
                new CompletionParser(
                    mappedClassInfo.getClassName() + "." + parser.getAllButFirst());
            ArrayList<PropertyInfo> matchingAttributes =
                mappedClassInfo.getQualifiedMatchingAttributes(simpleAttrFakeParser);
            ret.addAll(matchingAttributes);
          }
        }
      }
    }

    int replacementStart;
    String stringToReplace;
    if (0 < ciClasses.size()) {
      // We assume that classes and attributes won't be in the same completion list.
      // Classes will be completed fully qualified when the user works with fully qualified class
      // names ...
      ret.addAll(ciClasses);
      replacementStart = parser.getReplacementStart();
      stringToReplace = parser.getStringToReplace();
    } else {
      // ... while attributes used in qualified expressions will not be completed qualified.
      // That means for pack.Foo. the completion popup will be placed behind the last dot.
      ret.addAll(ciAttrs);
      replacementStart = parser.getTextTillCarret().length() - parser.getLastToken().length();
      stringToReplace = parser.getLastToken();
    }

    for (SimpleHQLCompletionInfo simpleInfo : _simpleInfos) {
      if (simpleInfo.matches(parser)) {
        ret.add(simpleInfo);
      }
    }

    return new CompletionCandidates(
        ret.toArray(new CompletionInfo[ret.size()]), replacementStart, stringToReplace);
  }