public StageTree(TreeObject base, int capacity) {
   this.shadow = base;
   this.capacity = capacity;
   reset();
 }
  /**
   * Commit the changes made on this stage to the repo, returning the reference for the TreeObject
   * we will save for this.
   *
   * @param rp
   * @param commitRef
   * @return @
   */
  public String commitStage(
      VersionedRepo rp,
      String commitRef,
      CommitCollector collector,
      Map<DocumentObject, String> savedDocRefs) {
    // We create a new tree
    TreeObject newTreeObject = new TreeObject();
    // We need to work out a new document bag structure, by removing and
    // resaving any document bags that have had
    // items removed... We then add back any documents back into the bags
    // that have room

    Set<DocumentBagObject> needToSave = new HashSet<DocumentBagObject>();
    Map<String, DocumentBagObject> maybeReuse = new HashMap<String, DocumentBagObject>();
    Set<String> refsToSave = new HashSet<String>();

    workOutCommitChanges(rp, needToSave, maybeReuse, refsToSave);
    applyNewSaves(newTreeObject, refsToSave);

    // For the ones in needToSave, we can use them to hopefully fill a gap

    Map<String, DocumentObject> combinedSet = rebalanceTree();

    for (Map.Entry<String, DocumentObject> entries : combinedSet.entrySet()) {

      // If the document is already in the savedDocRefs, we don't need to
      // save it, we should simply get the reference
      // from that
      String reference = null;
      if (savedDocRefs.containsKey(entries.getValue())) {
        reference = savedDocRefs.get(entries.getValue());
      } else {
        entries.getValue().setCommitRef(commitRef);
        reference = rp.getObjectDatabase().writeDocument(entries.getValue());
        savedDocRefs.put(entries.getValue(), reference);
      }

      collector.addDocReference(reference);
      collector.addDocName(entries.getKey());

      // Find a spot to put this reference in
      boolean done = false;

      for (DocumentBagObject d : needToSave) {
        if (d.getDocRefs().size() < capacity) {
          d.getDocRefs().put(entries.getKey(), reference);
          done = true;
          break;
        }
      }
      if (!done && maybeReuse.size() != 0) {
        Map.Entry<String, DocumentBagObject> d = maybeReuse.entrySet().iterator().next();
        d.getValue().getDocRefs().put(entries.getKey(), reference);
        needToSave.add(d.getValue());
        maybeReuse.remove(d.getKey());
        done = true;
      }
      if (!done) {
        DocumentBagObject dNew = new DocumentBagObject();
        dNew.getDocRefs().put(entries.getKey(), reference);
        needToSave.add(dNew);
      }
    }

    // Add back those we didn't use
    for (String k : maybeReuse.keySet()) {
      if (!removedDocuments.contains(k)) {
        DocumentBagReference dr = new DocumentBagReference();
        dr.setBagRef(k);
        dr.setSize(maybeReuse.get(k).getDocRefs().size());
        newTreeObject.getDocuments().add(dr);
      }
    }

    // Now we need to save the need to save

    for (DocumentBagObject d : needToSave) {
      String reference = rp.getObjectDatabase().writeDocumentBag(d);
      DocumentBagReference dr = new DocumentBagReference();
      dr.setBagRef(reference);
      dr.setSize(d.getDocRefs().size());
      newTreeObject.getDocuments().add(dr);
    }

    newTreeObject.getTrees().putAll(shadow.getTrees());
    // Add the new ones, do the trees first
    for (Map.Entry<String, StageTree> entries : stagedTrees.entrySet()) {
      collector.enterFolder(entries.getKey());
      String reference = entries.getValue().commitStage(rp, commitRef, collector, savedDocRefs);
      collector.addTreeReference(reference);
      collector.leaveFolder();
      collector.addFolderName(entries.getKey());
      newTreeObject.getTrees().put(entries.getKey(), reference);
    }
    shadow = newTreeObject;
    reset();
    return rp.getObjectDatabase().writeTree(newTreeObject);
  }