public void print(int indent, boolean printIndent, PrintStream ps) {
   char nodeChar = headNode.suffixLink != null ? '*' : '-';
   for (int i = 0; printIndent && i < indent; i++) {
     ps.print(" ");
   }
   // String coords = String.format("(%d,%d)", start, end);
   String coords = "";
   ps.print(String.format("%c%s%s", nodeChar, coords, getSubstring()));
   tailNode.print(indent + length() + coords.length() + 1, ps);
 }
    public void matchFrom(TreeNode startNode, boolean skipcount) {
      assert string != null || array != null;
      assert lastEdge == null;

      matchingFrom = start;
      matchedTo = start;

      // a base case.
      if (end - start <= 0) {
        return;
      }

      char nextChar = getChar(matchingFrom);

      assert startNode != null;

      System.err.println("startNode is " + startNode + " and nextChar is " + nextChar);

      if (startNode.childEdges.containsKey(nextChar)) {
        lastEdge = startNode.childEdges.get(nextChar);
      } else if (skipcount) {
        System.err.println("Failure Node: ");
        startNode.print(0, System.err);
        System.err.println();
        System.err.flush();
        throw new IllegalArgumentException();
      }

      boolean keepMatching = lastEdge != null;

      while (keepMatching) {
        int remaining = end - matchingFrom;
        int matching =
            skipcount
                ? Math.min(lastEdge.length(), remaining)
                : (string != null
                    ? lastEdge.countMatches(string, matchingFrom, end)
                    : lastEdge.countMatches(array, matchingFrom, end));
        matchedTo = matchingFrom + matching;

        if (matching < lastEdge.length()) {
          // we either matched all the way into the middle of the
          // current edge, or we found a mismatch in the current edge.
          // either way, update the matchedTo variable and we're done.
          keepMatching = false;
        } else {
          if (matching < remaining) {
            nextChar = getChar(matchedTo);

            if (lastEdge.tailNode.childEdges.containsKey(nextChar)) {
              lastEdge = lastEdge.tailNode.childEdges.get(nextChar);
              matchingFrom += matching;

            } else if (skipcount) {
              System.err.println("ERROR TREE: ");
              print(System.err);
              System.err.println();
              System.err.flush();

              String err =
                  String.format(
                      "[%s] node:'%s' (next: %c)", toString(), startNode.pathLabel(), nextChar);
              throw new IllegalArgumentException(err);
            } else {
              keepMatching = false;
            }
          } else {
            keepMatching = false;
          }
        }
      }
    }
 public void print(PrintStream ps) {
   root.print(0, ps);
 }