// double_buffer.java
import java.awt.*;
import java.awt.event.*;

public class double_buffer extends Frame
{
  // Initialise
  int x_pos = 100;	// x - Position of ball
  int y_pos = 100;	// y - Position of ball
  int radius = 20;	// Radius of ball
  int width = 500;
  int height = 400;
  int x_min = 5;   // frame
  int x_max = width-5;
  int y_min = 25;
  int y_max = height-5;
  int x, y, b;
  int dx = 3;
  int dy = -2;
  
  // set up double buffer
  Image dbImage;
  Graphics dbg;
  
  double_buffer()
  {
    setTitle("Java double_buffer  mouse:left=faster,right=slower");
    setSize(width,height);
    setBackground(Color.blue);
    setForeground(Color.red);
    addWindowListener(new WindowAdapter()
    {
      public void windowClosing(WindowEvent e)
      {
        System.exit(0);
      }
    });
    setVisible(true);

    this.addMouseListener (new mousePressHandler());
    new MyThread().start(); // all the action is in  run
  } // end double_buffer constructor

  class MyThread extends Thread
  {
    MyThread()
    {
      // everything in  run
    }

    public void run ()
    {
	  // maximize priority
	  Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
      // loop
      while (true)
      {
        // increment coordinate
	    x_pos = x_pos+dx;
        y_pos = y_pos+dy;
	    if(x_pos+radius>x_max) dx=-dx;
		if(x_pos-radius<x_min) dx=-dx;
		if(y_pos+radius>y_max) dy=-dy;
		if(y_pos-radius<y_min) dy=-dy;

	    // show
	    repaint(); // this calls  update, not paint

	    try
	    {
	      // delay 20 milliseconds
	      Thread.sleep (20);
	    }
	    catch (InterruptedException ex)
	    {
	      // do nothing, still must have
	    } // end try-catch

      } // end while
    } // end run
  } // end MyThread

  /* This is key to double buffering, repaint calls update, not paint */
  public void update (Graphics g)
  {
	// Initialise Double Buffers
	if (dbImage == null)
	{
	  dbImage = createImage (this.getSize().width, this.getSize().height);
	  dbg = dbImage.getGraphics ();
	}

	// clear image in RAM, dbg is off screen buffer
	dbg.setColor (getBackground ());
	dbg.fillRect (0, 0, this.getSize().width, this.getSize().height);

	// run paint on off screen buffer
	dbg.setColor (getForeground());
	paint (dbg);

	// 
	g.drawImage (dbImage, 0, 0, this);
  } // end update

  public void paint (Graphics g)
  {
	g.setColor  (Color.red);
	g.fillOval (x_pos - radius, y_pos - radius, 2 * radius, 2 * radius);
  } // end paint

  class mousePressHandler extends MouseAdapter
  {
    public void mousePressed (MouseEvent e)
    {
      x = e.getX();
      y = e.getY();
      b = e.getButton();
      if(b==1 && dx<0)dx--; // button 1 speeds up
	  if(b==1 && dx>=0)dx++;
      if(b==3 && dx<0)dx++; // button 3 slows down
	  if(b==3 && dx>=0)dx--;
	  
      requestFocus();
      System.out.println("at dx="+dx+"   dy="+dy+"   b="+b); // debug print
      repaint();
    }
  } // end mousePressHandler

  public static void main(String args[])
  {
    new double_buffer();
  } // end main
} // end class double_buffer


