private IndexedElement findBestMatchHelper(
      PythonParserResult info,
      String name,
      Set<IndexedElement> elements,
      BaseDocument doc,
      int astOffset,
      int lexOffset,
      AstPath path,
      PythonTree callNode,
      PythonIndex index) {

    Set<IndexedElement> candidates = new HashSet<IndexedElement>();

    if (elements.size() == 0) {
      return null;
    } else if (elements.size() == 1) {
      return elements.iterator().next();
    }

    // 1. Prefer matches in the current file
    String searchUrl = info.getSnapshot().getSource().getFileObject().toURL().toExternalForm();
    candidates = new HashSet<IndexedElement>();

    for (IndexedElement element : elements) {
      String url = element.getFilenameUrl();

      if (url.equals(searchUrl)) {
        candidates.add(element);
      }
    }

    if (candidates.size() == 1) {
      return candidates.iterator().next();
    } else if (!candidates.isEmpty()) {
      elements = candidates;
    }

    // 2. See which of the class references are defined in files directly
    //   included by this file.
    Set<String> included = new HashSet<String>();
    candidates = new HashSet<IndexedElement>();

    SymbolTable table = PythonAstUtils.getParseResult(info).getSymbolTable();
    List<Import> imports = table.getImports();
    for (Import imp : imports) {
      List<alias> names = imp.getInternalNames();
      if (names != null) {
        for (alias at : names) {
          included.add(at.getInternalName());
        }
      }
    }
    List<ImportFrom> importsFrom = table.getImportsFrom();
    for (ImportFrom imp : importsFrom) {
      included.add(imp.getInternalModule());
    }

    if (included.size() > 0) {
      for (IndexedElement element : elements) {
        String mod = element.getModule();

        if (included.contains(mod)) {
          candidates.add(element);
        }
      }

      if (candidates.size() == 1) {
        return candidates.iterator().next();
      } else if (!candidates.isEmpty()) {
        elements = candidates;
      }
    }

    // 4. Prefer builtins
    candidates = new HashSet<IndexedElement>();

    for (IndexedElement element : elements) {
      String url = element.getFilenameUrl();

      if (url != null && url.indexOf("pythonstubs") != -1) { // NOI18N
        candidates.add(element);
      }
    }

    if (candidates.size() == 1) {
      return candidates.iterator().next();
    } else if (!candidates.isEmpty()) {
      elements = candidates;
    }

    // 5. Prefer documented classes
    candidates = new HashSet<IndexedElement>();
    for (IndexedElement element : elements) {
      if (element.isDocumented()) {
        candidates.add(element);
      }
    }

    if (candidates.size() == 1) {
      return candidates.iterator().next();
    } else if (!candidates.isEmpty()) {
      elements = candidates;
    }

    // TODO - use some heuristics here!
    return elements.iterator().next();
  }