class ParboiledAutoComplete {

  @VisibleForTesting
  static Optional<String> findPrecedingInput(
      PotentialMatch pm, String query, Anchor.Type headAnchorType, Anchor.Type tailAnchorType) {
    int anchorIndex = pm.getPath().indexOf(pm.getAnchor());
    checkArgument(anchorIndex != -1, "Anchor is not present in the path.");

    Optional<PathElement> nodeStartElement =
        findFirstMatchingPathElement(pm, anchorIndex, headAnchorType);

    if (!nodeStartElement.isPresent()) {
      return Optional.empty();
    }

    Optional<PathElement> nodeEndElement =
        findFirstMatchingPathElement(pm, anchorIndex, tailAnchorType);
    checkArgument(
        nodeEndElement.isPresent(),
        "Tail anchor type '%s' not found for input '%s'",
        tailAnchorType,
        query);

    return Optional.of(
        query.substring(
            nodeStartElement.get().getStartIndex(), nodeEndElement.get().getStartIndex()));
  }

    ParboiledAutoComplete(
      CommonParser parser,
      Grammar grammar,
      Map<String, Anchor.Type> completionTypes,
      String network,
      String snapshot,
      String query,
      int maxSuggestions,
      CompletionMetadata completionMetadata,
      NodeRolesData nodeRolesData,
      ReferenceLibrary referenceLibrary);
    ParboiledAutoComplete(
      Grammar grammar,
      Rule inputRule,
      Map<String, Anchor.Type> completionTypes,
      String network,
      String snapshot,
      String query,
      int maxSuggestions,
      CompletionMetadata completionMetadata,
      NodeRolesData nodeRolesData,
      ReferenceLibrary referenceLibrary);

}