// Walks the tree, checking to make sure that we haven't violated any
    // logical constraints.  This is a method for debugging.
    public boolean check() {
      String path = pathLabel();
      if (suffixLink != null) {
        String suffixPath = suffixLink.pathLabel();
        if (!path.substring(1, path.length()).equals(suffixPath)) {
          logger.log(
              Level.SEVERE,
              String.format("Suffix Link for node (%s) didn't match: %s", path, suffixPath));
          return false;
        }
      }

      for (char c : childEdges.keySet()) {
        TreeEdge e = childEdges.get(c);
        if (!e.check()) {
          return false;
        }
      }

      for (int k : terminalEdges.keySet()) {
        TreeEdge e = terminalEdges.get(k);
        if (!e.check()) {
          return false;
        }
      }

      return true;
    }
 public void finishFinalEdges() {
   for (TreeEdge edge : edgesWithE) {
     if (edge.isEndSymbolic()) {
       edge.setEnd(lastE);
     }
   }
   edgesWithE.clear();
 }
 public String pathLabel() {
   if (parentEdge != null) {
     StringBuilder sb = new StringBuilder(parentEdge.headNode.pathLabel());
     for (int i = 0; i < parentEdge.length(); i++) {
       sb.append(parentEdge.getChar(i));
     }
     return sb.toString();
   } else {
     return "";
   }
 }
    public void addEdge(TreeEdge e) {
      if (e.start() == e.string.length() - 1) {
        int key = e.string.getIndex();
        if (terminalEdges.containsKey(key)) {
          throw new IllegalArgumentException();
        }

        e.headNode = this;
        terminalEdges.put(key, e);
      } else {
        char key = e.getChar(0);
        if (childEdges.containsKey(key)) {
          throw new IllegalArgumentException();
        }
        e.headNode = this;
        childEdges.put(key, e);
      }
    }
 public void print(int indent, PrintStream ps) {
   if (isLeaf()) {
     printSuffixes(ps);
     ps.println();
   } else {
     int i = 0;
     for (char c : childEdges.keySet()) {
       TreeEdge edge = childEdges.get(c);
       edge.print(indent, i != 0, ps);
       i++;
     }
     for (int k : terminalEdges.keySet()) {
       TreeEdge edge = terminalEdges.get(k);
       edge.print(indent, i != 0, ps);
       i++;
     }
   }
 }
    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 boolean inEdgeMiddle() {
   return lastEdge != null && lastMatchLength() < lastEdge.length();
 }