/**
   * 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
        }
      }
  }
 public boolean semanticEventAfter(SemanticEvent se, String msg) {
   Object arg = se.getArg();
   String winclass = getAttr("winclass");
   if (MSG_NEW == msg && this == arg && winclass != null) {
     Map<String, Object> attrs = (Map) CHashMap.getInstance(getAttr("attrs"));
     Browser br = getBrowser();
     Layer layer =
         (getAttr("doc") == null ? br.getRoot() : br.getCurDocument())
             .getLayer(getAttr("layer", Layer.SCRATCH));
     // System.out.println("system layer behaviors\n\t");
     //		for (Iterator<> i=systemLayer.behaviorIterator(); i.hasNext(); )
     // System.out.println(((Behavior)i.next()).getName()+" ");
     Behavior.getInstance(winclass /*for now -- getName() not right*/, winclass, attrs, layer);
     // if (win.getTitle()==null) win.setTitle(getAttr("title"));    // share TITLE attribute with
     // target VFrame, if it doesn't have one
     // if (lastbbox_==null) lastbbox_=win.getBounds(); else {
     // win.setLocation(lastbbox_.x,lastbbox_.y); win.setSize(lastbbox_.width,lastbbox_.height); }
     // getBrowser().eventq(VFrame.SHOWEVENT, win); -- part of VFrame restore()
   }
   // if (VFrame.SHOWEVENT==msg && this==arg) System.out.println("SHOW on "+winclass);
   return super.semanticEventAfter(se, msg);
 }
 public void restore(ESISNode n, Map<String, Object> attr, Layer layer) {
   super.restore(n, attr, layer);
   triggerMsg_ = ("createWidget/" + (getAttr("menu", "Lens"))).intern();
 }
  /**
   * Centralized behavior instantiation <i>factory</i>: <b>instantiate all behaviors through this
   * method</b> -- never use <code>new <var>behavior</var>(...)</code>.
   *
   * <ul>
   *   <li>remapping of names so can dynamically replace references in old hubs
   *   <li>centralized, correct instantiation and error handling
   * </ul>
   *
   * {@link #restore(ESISNode, Map, Layer)} is called as part of instantiation, serving the place of
   * arguments to a constructor. Logical names are normalized to all lowercase.
   */
  public static Behavior getInstance(
      String logicalname,
      String behaviorclass,
      ESISNode children,
      Map<String, Object> attr,
      Layer layer) {
    assert logicalname != null
            && behaviorclass != null /*&& (layer!=null || xxx instanceof Layer)--topmost Layer*/
        : "logical=" + logicalname + ", class=" + behaviorclass;
    if (behaviorclass == null) return null; // if not testing (asserts on), keep on truckin'

    if (multivalent.Meta.MONITOR /*false*/ && layer != null && layer.getBrowser() != null) {
      Browser br = layer.getBrowser();
      Graphics g = br.getGraphics(); // -- works, but not well
      if (Behavior.rainbowi_ == Behavior.RAINBOW.length) Behavior.rainbowi_ = 0;
      if (g != null) { // !Multivalent.standalone_ / embedded in Swing
        g.setColor(Behavior.RAINBOW[Behavior.rainbowi_++]);
        g.fillRect(0, 0, 10 /*rainbowi_*/, 10); // g.drawLine(0,10, 10,0);
      }

      /*		g.setColor(Color.WHITE); g.fillRect(250,y_, 600,20);
      g.setColor(Color.BLACK); rfont_.drawString(g, logicalname+" / "+behaviorclass, 300, y_+15);
      y_ += 20; if (y_>20*10) y_ = 0;	// set to 600 to conver page, but can only take in 10 lines at a time
      	 */
    }
    // long start = System.currentTimeMillis();

    // String oname = logicalname;
    logicalname = logicalname.toLowerCase();
    // if (!(oname.equals(logicalname))) System.out.println("uppercase logical: "+oname);	// warn of
    // this inefficiency

    Multivalent v = Multivalent.getInstance();
    String bname = v.remapBehavior(behaviorclass);
    Logger log = getLogger();
    // getLogger().finest((/*"getInstance "+logicalname+"/"+behaviorclass+"=>"+bname);

    if (Behavior.deadbe__.get(bname) == null)
      try {
        ClassLoader cl = /*v.getJARsClassLoader();*/ v.getClass().getClassLoader();
        // assert cl == Behavior.class.getClassLoader();	// true now with new bootstrapping
        Object bc = Class.forName(bname, true, cl).newInstance();
        Behavior be = (Behavior) bc;
        // be.setName(logicalname);	// can't save uppercase
        be.name_ = logicalname;
        // be.name_ = (logicalname!=null? logicalname.toLowerCase(): null);
        be.classname_ = behaviorclass;

        // System.out.println(bname);
        // see save() -- this still ok
        // if (attr==null) {} else if (attr.get(ATTR_BEHAVIOR)!=null) { if (attr.size()==1)
        // attr=null; else attr.remove(ATTR_BEHAVIOR); }

        /*
        long time = System.currentTimeMillis() - start;
        if (false && g!=null/* && time > 0L* /) {
        	g.drawString(Long.toString(time), 250,15);
        	try { Thread.currentThread().sleep(2000L); } catch (Exception e) {}
        }
        		 */
        be.restore(
            children, attr,
            layer); // after added to layer, so can climb around and find things during restore
        // log.finest("created "+bname);

        // assert layer!=null || be instanceof Layer;	// => temporary use of behavior that don't
        // want to make logical part of document
        return be;

      } catch (ClassNotFoundException e) {
        log.warning("couldn't find behavior " + bname + " -- ignored");

      } catch (ClassCastException e) {
        log.severe(
            "class " + bname + " is not a behavior (does not subclass from Behavior) -- ignored");
      } catch (InstantiationException e) {
        log.severe("couldn't instantiate " + bname + " -- is it abstract?");
      } catch (IllegalAccessException e) {
        log.severe(bname + ": " + e + " -- perhaps class or constructor needs to be public");

      } catch (Exception e) {
        e.printStackTrace();
        log.severe("unanticipated error while restoring " + logicalname + "/" + bname + ": " + e);
      }

    // error fall through
    Behavior.deadbe__.put(bname, bname);
    return null;
  }