/**
   * Recursively process ESIS children, restore children as behaviors. Not called by default from
   * restore() because behaviors may selectively process children.
   */
  public void restoreChildren(
      ESISNode n, Layer layer) { // NB: overridden by Layer, so propagate changes.
    // System.out.println("restoring "+n.getGI());
    // with inner classes pass function to tree traversal method?
    assert layer != null;

    // traverse bottom up, so complex nodes higher up have components built first
    if (n != null)
      for (int i = 0;
          i < n.size() /* count can change while enumerating--still?  that would be bad */;
          i++) {
        Object child = n.childAt(i);
        // if (child instanceof ESISNode) System.out.println("child = "+((ESISNode)child).getGI());
        if (child instanceof ESISNode) {
          ESISNode m = (ESISNode) child;
          String bname = m.getAttr(Behavior.ATTR_BEHAVIOR);
          if (bname != null) {
            Behavior be = getInstance(m.getGI() /*bname*/, bname, m, m.attrs, layer);
            be.removeAttr(Behavior.ATTR_BEHAVIOR); // kept in classname_
          } // else assume subclass has some use for it.  DO NOT take GI as behavior name (with
          // remapping)!

          // most behaviors with internal structure call restoreChildren first and then (rest of)
          // self
        }
      }
  }
  /**
   * Build up save data as ESIS tree, then write that out. Makes node with GI = behavior name, same
   * attributes, and possibly some children. Attributes are cloned, so if you want to stuff
   * attributes from state, do that before <code>super.save()</code>. Always have {@link
   * #ATTR_BEHAVIOR} from save (short) classname.
   */
  public ESISNode save() {
    // if (getAttr(ATTR_BEHAVIOR)==null) putAttr(ATTR_BEHAVIOR, classname_);	//NOT getName(), NOT
    // getClass().getName());	// temporary.  X remove BEHAVIOR attribute in favor of name => want
    // names for things other than behvaior so no way to distinguish be from non-be
    Map<String, Object> attrs = getAttributes();
    if (attrs != null) {
      Map<String, Object> newattrs = new HashMap<String, Object>(attrs.size());
      newattrs.putAll(attrs);
      attrs = newattrs;
    } // make copy (ok if inefficient here)
    ESISNode e = new ESISNode(getName(), attrs);

    // take ATTR_BEHAVIOR if exists, else use value cached in field
    e.putAttr(
        Behavior.ATTR_BEHAVIOR,
        getAttr(
            Behavior.ATTR_BEHAVIOR,
            classname_)); // maintain classname_ in attribute, since few behaviors and above is
    // disgusting

    return e;
  }