import java.util.*;
import javax.swing.*;
import java.awt.*;

/** Two small utility functions (turnOffDoubleBuffering and
 *  turnOnDoubleBuffering) that turn off double buffering for all
 *  components in a hierarchy, and turn back on the ones that were
 *  previously on. Used when printing, since the speed and quality
 *  of printing suffers dramatically if any of the containers have
 *  double buffering turned on.
 *  7/99 Marty Hall, http://www.apl.jhu.edu/~hall/java/
 */

public class RecursiveDescent {
  /** Given a root component, this turns off double buffering (if it is on)
   *  for the component and, recursively, for all components contained
   *  in it. It returns a HashSet of the components that had double
   *  buffering turned on, so that you can descend the hierarchy again
   *  later and re-enable double buffering for the components that
   *  previously used it.
   */
  public static HashSet turnOffDoubleBuffering(Component root) {
    HashSet bufferedComponents = new HashSet();
    return(descendContainmentHierarchy(root,
                                       bufferedComponents,
                                       new BufferOpOff()));
  }

  /** Given a root component and a HashSet of previously double buffered
   *  components, this turns on double buffering for the component if it is
   *  in the designated set, and then recursively applies the same process
   *  for all components contained in it.
   */
  public static void turnOnDoubleBuffering(Component root,
                                           HashSet bufferedComponents) {
    descendContainmentHierarchy(root,
                                bufferedComponents,
                                new BufferOpOn());
  }

  /** Descends the containment hierarchy, either turning off double
   *  buffering (and recording the previously buffered elements), or
   *  conditionally re-enabling double buffering.
   */
  private static HashSet descendContainmentHierarchy(Component root,
                                                     HashSet bufferedComponents,
                                                     BufferOp operation) {
    if ((root instanceof JComponent) && (root.isDoubleBuffered())) {
      JComponent component = (JComponent)root;
      operation.doOp(component, bufferedComponents);
    }
    if (root instanceof Container) {
      Container container = (Container)root;
      Component[] subComponents = container.getComponents();
      for(int i=0; i<subComponents.length; i++) {
        descendContainmentHierarchy(subComponents[i],
                                    bufferedComponents,
                                    operation);
      }
    }
    return(bufferedComponents);
  }
}

