@Override
  @SuppressWarnings("unchecked")
  public void visit(BranchNode branchNode, NodeStorageManager storage) {
    assert branchNode.mutable;

    Node<? extends Node<?>> bestChild = findWritableBestBranch(branchNode, item, storage);

    if (bestChild != null) {
      bestChild.accept(this, storage);
      return;
    }

    // Exceptional case - empty node. So do this last
    if (branchNode.getNumChildren() == 0) {
      // We are making a change so clone the node
      BranchNode updateBranch = storage.getWriteableBranch(branchNode.getRef());
      LeafNode newLeaf = storage.createLeafNode(updateBranch.getRef());
      updateBranch.add(new Branch((RefImpl) newLeaf.getRef()));
      newLeaf.accept(this, storage);
      return;
    }
    // FIXME: This happens if an enum splitter has been configured too small
    // we shouldn't need to pre-allocate the branches in that case
    throw new Error("InsertFailedException(item);");
  }
  /**
   * Begin a new search - use the helper Index.NewSearch()
   *
   * @param spec
   * @param nominee
   */
  public OrderedSearch(
      SearchSpecImpl spec,
      IScoreConfiguration config,
      boolean nominee,
      NodeStorageManager storage) {
    super();
    this.spec = spec;
    this.storage = storage;
    this.nominee = nominee;

    resultsQ =
        new ResultsQ(spec.getMaxNonMatches(), spec.getScoreThreshold(), spec.getTargetNumResults());

    workQ = new WorkQ(this, resultsQ, config);
    workQ.add(
        new NextNode(new NodeScore(), getNextSeq(), storage.getRootNode())); // FIXME: NodeScore

    if (log.isInfoEnabled()) {
      log.info(
          "New Search: threshold = "
              + spec.getScoreThreshold()
              + ", targetNumResults = "
              + spec.getTargetNumResults()
              + ", searchType = "
              + spec.getScorerConfig());
    }

    //		log.info( "Index dump: ");
    //		storage.getRootNode().dumpNode(System.out, 0, storage);
  }
  private Node<? extends Node<?>> findWritableBestBranch(
      BranchNode branchNode, IAttributeContainer item, NodeStorageManager storage) {

    Node<? extends Node<?>> bestChild = null;
    int bestCount = Integer.MAX_VALUE;
    for (int i = 0; i < branchNode.numChildren; i++) {
      if (branchNode.children[i].consistent(item)) {
        Node<? extends Node<?>> child = branchNode.children[i].getWriteableChild(storage);

        // normal case is that we split, so first matching child is appropriate
        if (branchNode.children[i].getSplitId() != -1) { // i.e. hasSplit()
          return child;
        }

        if (child instanceof LeafNode) {
          LeafNode leaf = (LeafNode) child;
          // If children are LeafNode, and more than one qualifies, insert into the smallest one.
          // This is because we can split a node without splitting on an attribute, if the
          // attributes are
          // too close to split and no manager wants to split.
          int count = leaf.items.size();
          if (count < bestCount) {
            bestCount = count;
            bestChild = child;
          }
        } else {
          int bestIndex = rand.nextInt(branchNode.numChildren); // rand between 0 to numChildren-1
          return branchNode.children[bestIndex].getWriteableChild(storage);

          // was     			if (bestChild == null) bestChild = child;	// prefer leaf node to branch node
          // if both qualify
          //        			break;
        }
      }
    }
    return (bestChild == null) ? null : storage.getWriteableNode(bestChild.getRef());
  }