import java.awt.*;
import java.awt.event.*;

/**
 * whiteCanvas is the actual surface on which the user draws. It provides 
 * a double-buffered, persistant drawing area, that implements multiple 
 * builtin shapes and thicknesses. It is instantiated by the drawPanel,
 * which controls it.
 *
 * @author Johan Andersen
 * @version $Revision: 1.5 $        $Date: 1998/05/06 14:36:21 $
 *
 * @see Canvas
 * @see drawPanel
 */
public class whiteCanvas extends Canvas
{
  /** The current color */
  private Color currentColor = Color.black;

  /** The current thickness to draw objects in */
  private int thickness = 1;

  /** The image we draw to, which is then dumped to the screen */
  private Image buffer = null;

  /** The graphics object assosciated with out buffer */
  private Graphics buffer_gfx;

  /**
   * This function clears the drawing area
   */

  public void clear()
  {
    if(buffer_gfx != null) {
      buffer_gfx.setColor(Color.white);
      buffer_gfx.fillRect(0, 0, getSize().width, getSize().height);
      getGraphics().drawImage(buffer,0,0,this);
    }
  }

  /**
   * This function draws a line of the current color and thickness from
   * x1,y1 to x2,y2, in a buffer, and then copies that buffer to the screen
   *
   * @param x1 the x coordinate of the first point
   * @param y1 the y coordinate of the first point
   * @param x2 the x coordinate of the second point
   * @param y2 the y coordinate of the second point
   */

  public void drawLine(int x1, int y1, int x2, int y2)
  {
    int i;

    if (buffer == null) {
      buffer = createImage(getSize().width, getSize().height);
      buffer_gfx = buffer.getGraphics();
      buffer_gfx.setColor(Color.white);
      buffer_gfx.fillRect(0, 0, getSize().width, getSize().height);
    }
    
    buffer_gfx.setColor(currentColor);
    if (thickness == -1) {
      buffer_gfx.drawLine(x1,y1,x2,y2);
    } else {
      int hs = thickness/2;
      int w = (int) (((double) hs) / Math.sqrt(2.0));
      if((x1 < x2 && y1 < y2) || (x1 > x2 && y1 > y2)) {
        int xvec[] = {x1-w-1, x1+w, x2+w, x2-w-1};
        int yvec[] = {y1+w+1, y1-w, y2-w, y2+w+1};
        buffer_gfx.fillPolygon(xvec, yvec, 4);
      } else {
        int xvec[] = {x1-w-1, x1+w, x2+w, x2-w-1};
        int yvec[] = {y1-w-1, y1+w, y2+w, y2-w-1};
        buffer_gfx.fillPolygon(xvec, yvec, 4);
      }

    }
    getGraphics().drawImage(buffer,0,0,this);
  }

  /**
   * This function draws a rectangle of the current color and thickness 
   * starting at x,y with width w and height h
   *
   * @param x the x coordinate of the top left point
   * @param y the y coordinate of the top left point
   * @param w the width of the rectangle
   * @param h the height of the rectangle
   */

  public void drawRect(int x, int y, int w, int h)
  {
    int i = 0;
    if (buffer == null) {
      buffer = createImage(getSize().width, getSize().height);
      buffer_gfx = buffer.getGraphics();
      buffer_gfx.setColor(Color.white);
      buffer_gfx.fillRect(0, 0, getSize().width, getSize().height);
    }
    
    buffer_gfx.setColor(currentColor);
    if (thickness == -1) {
      buffer_gfx.fillRect(x,y,w,h);
    } else {
      for(i=0;i<thickness;i++) {
	buffer_gfx.drawRect(x+i,y+i,w-(2*i),h-(2*i));
      }
    }

    getGraphics().drawImage(buffer,0,0,this);
  }

  /**
   * This function draws an oval of the current color and thickness 
   * bound by the rectangle whose upper left corner is at  x,y 
   * and whose width=w and height=h
   *
   * @param x the x coordinate of the top left point
   * @param y the y coordinate of the top left point
   * @param w the width of the bounding rectangle
   * @param h the height of the bounding rectangle
   */

  public void drawOval(int x, int y, int w, int h)
  {
    int i = 0;

    if (buffer == null) {
      buffer = createImage(getSize().width, getSize().height);
      buffer_gfx = buffer.getGraphics();
      buffer_gfx.setColor(Color.white);
      buffer_gfx.fillRect(0, 0, getSize().width, getSize().height);
    }
    
    buffer_gfx.setColor(currentColor);
    if (thickness == -1) {
      buffer_gfx.fillOval(x,y,w,h);
    } else {
      for(i=0;i<thickness;i++) {
	buffer_gfx.drawOval(x+i,y+i,w-(2*i),h-(2*i));
      }
    }

    getGraphics().drawImage(buffer,0,0,this);
  }

  /**
   * Routine to set the current drawing color
   *
   * @param c The color to set the current color to.
   */
  public void setColor(Color c)
  {
    currentColor = c;
  }

  /**
   * Routine to get the current drawing color
   *
   * @return the current color
   */
  public Color getColor()
  {
    return(currentColor);
  }

  /**
   * Routine to set the thickness of the current object
   *
   * @param s the new thickness
   */
  public void setThickness(int s)
  {
    thickness = s;
  }

  /**
   * Routine to set the thickness of the current object
   *
   * @return the current thickness
   */
  public int getThickness()
  {
    return(thickness);
  }


  public void paint(Graphics g)
  {
    if(buffer != null) {
      g.drawImage(buffer,0,0,this);
    } else {
      g.setColor(Color.white);
      g.fillRect(0,0,getSize().width, getSize().height);
    }
  }
}
