public class ContainerClassWithJava3D implements Purgeable

private Vector purgeables;


 public void addPurgeable(Purgeable purgeable)
  {
    if (purgeables == null)
    {
      purgeables = new Vector();
    }
    purgeables.add(purgeable);
  }

  /**
  * called when the frame is disposed
  * stops rendering, viewing, removes the canvas detaches the branchGroup directly under
  * SimpleUniverse and calls purge on all the branchGroup's children
  * After which it calls purge() on any object which maintains references to elements of the scene
  * and which has regsitered an interest by a call to this.addPurgeable(any_object)
  * finally it gives a polite cough to the garbage collector
  */
  public void dispose()
  {
    if (canvas != null)
    {
      canvas.stopRenderer();
      view.stopView();
      view.removeCanvas3D(canvas);
      super.dispose();
      rootBranchGroup.detach();
      Enumeration nodes  = rootBranchGroup.getAllChildren();
      purge(nodes);
      for (Enumeration e = purgeables.elements() ; e.hasMoreElements() ;) 
      {
        Object o = e.nextElement();
        ((Purgeable)o).purge();
        o = null;
      } 
      System.gc();
    }
  }
 
/**
* from Purgeable interface: nulls any refernces to scen elements
*/  
public void purge()
  {
    proxy                      = null;
    rootBranchGroup            = null;
    view                       = null;
    canvas                     = null;
  }
  


  /**
  * arguments are typically enumeration of children (Node) as obtained from <br><i>group.getAllChildren();</i>
  * method detaches each element before recursively calling purge on each child
  * After which, depending on the class of the node the following are set to null or removed:<pre>
    appearance         and/or 
    texture            and/or 
    Material           and/or 
    CollisionBounds    and/or 
    geometry           and/or 
    Scope              and/or 
    InfluencingBounds  and/or 
    InfluencingBoundingLeaf
    </pre>
  */  
  private void purge(Enumeration victims)
  {
    while (victims.hasMoreElements()) 
    {
      Node victim = (Node)victims.nextElement();
      
      if (victim instanceof BranchGroup)
      {
       ((BranchGroup)victim).detach();
      }
      
      if (victim instanceof Group)
      {
        System.out.println("about to call destroy on all children["+
                           ((Group)victim).numChildren()+"] of " + victim);
        Enumeration e = ((Group)victim).getAllChildren();
        purge(e);
        while (((Group)victim).numChildren() > 0)
        {
          System.out.println("Group removeChild");
          ((Group)victim).removeChild(((Group)victim).numChildren()-1);
        }
        System.out.println("have destroyed  all children of  " + victim + " CHECK: "+((Group)victim).numChildren());
      }
      
      if (victim instanceof Node)
      {
        ((Node)victim).setCapability(Node.ALLOW_BOUNDS_READ);
        ((Node)victim).setCapability(Node.ALLOW_BOUNDS_WRITE);
        ((Node)victim).setBounds(null);
        //node
        if (victim  instanceof Leaf)
        {
          if ( victim  instanceof Shape3D)
          {
            ((Shape3D)victim).setCapability(Shape3D.ALLOW_APPEARANCE_READ);
            ((Shape3D)victim).setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
            //Shape3D
            Appearance appearance = ((Shape3D)victim).getAppearance();
            if (appearance != null) 
            {
              appearance.setTexture(null);
              appearance.setMaterial(null);
              appearance = null;
              ((Shape3D)victim).setAppearance(null);
              System.out.println("set appearance to null on " + victim+": "+((Shape3D)victim).getAppearance());
            }
            
            ((Shape3D)victim).setCapability(Shape3D.ALLOW_COLLISION_BOUNDS_WRITE);
            ((Shape3D)victim).setCollisionBounds(null);
            //Shape3D
            ((Shape3D)victim).setCapability(Shape3D.ALLOW_GEOMETRY_READ);
            ((Shape3D)victim).setCapability(Shape3D.ALLOW_GEOMETRY_WRITE);
            while(((Shape3D)victim).numGeometries() > 0)
            {
              System.out.println("Shape3D removeGeometry");
              ((Shape3D)victim).removeGeometry(((Shape3D)victim).numGeometries()-1);
            }
          }
          if ( victim  instanceof Light)
          {
            System.out.println("clearing light");
            ((Light)victim).setEnable(false);
            ((Light)victim).setCapability(Light.ALLOW_INFLUENCING_BOUNDS_WRITE);
            ((Light)victim).setCapability(Light.ALLOW_SCOPE_WRITE);
            ((Light)victim).setCapability(Light.ALLOW_SCOPE_READ);
            ((Light)victim).setCapability(Light.ALLOW_COLOR_WRITE);
            ((Light)victim).setCapability(Light.ALLOW_STATE_WRITE);
            while (((Light)victim).numScopes() > 0)
            {
              System.out.println("Light removeScope");
              ((Light)victim).removeScope(((Light)victim).numScopes()-1);
            }
            //((Light)victim).setColor(null);
            ((Light)victim).setInfluencingBounds(null);
            ((Light)victim).setInfluencingBoundingLeaf(null);
          }
        }
      }
    } 
  }



} // end of class

