/*

 * JavASketch.java

 * 

 * Version 2.0

 * 

 * Written by:  Mark Masse

 * Date:  7-28-96  (original version: 12-23-95)

 * 

 * This software is in the public domain, furnished "as is", without technical

 * support, and with no warranty, express or implied, as to its usefulness for

 * any purpose.

 */



import java.applet.Applet;

import java.awt.*;



/**

 * An Applet that implements a JavASketch drawing "toy".

 * @author     Mark Masse

 * @version    2.0

 */

public class JavASketch extends Applet {



  //DATA MEMBERS



  /**

   * The current x coordinate of the sketch-point.

   */

  protected int x;



  /**

   * The current y coordinate of the sketch-point.

   */

  protected int y;



  /**

   * Is true when drawing up and false otherwise.

   */

  protected boolean up;



  /**

   * Is true when drawing down and false otherwise.

   */

  protected boolean down;



  /**

   * Is true when drawing left and false otherwise.

   */

  protected boolean left;



  /**

   * Is true when drawing right and false otherwise.

   */

  protected boolean right;



  /**

   * The image used to create the graphics. 

   */

  protected Image img;



  /**

   * The dimensions of the JavASketch.

   */

  protected Dimension dim;



  /**

   * The graphic content of the JavASketch.

   */

  protected Graphics gra;



  /**

   * The width of the JavASketch.

   */

  protected int w;



  /**

   * The height of the JavASketch.

   */

  protected int h;



  /**

   * The previous x-coordinate.

   */

  protected int lastx;



  /**

   * The previous y-coordinate.

   */

  protected int lasty;



  /**

   * Determines whether the first point has been added to the JavASketch.

   */

  protected boolean gotFirstPoint;



  /**

   * Determines whether the JavASketch needs to be updated.

   */

  protected boolean updateSketch = true;



  /**

   * Determines whether the Jav A Sketch was erased .

   */

  protected boolean shaken;



  /**

   * The initial angle of the left knob's ridges. 

   */

  protected float leftKnobAngle;



  /**

   * The initial angle of the right knob's ridges. 

   */

  protected float rightKnobAngle;



  //METHODS





  /**

   * Initialization of the JavASketch Applet

   */

  public void init() {

    

    // Set the bg color to white

    setBackground(Color.white);



    // Set the starting point

    x = 200;

    y = 100;



    // Add the starting point to the JavASketch

    addPoint(x,y);

    showStatus("Jav A Sketch written by Mark Masse");

  }





  /**

   * Info

   * @return Info about the Applet's author

   */  

  public String getAppletInfo() {

    return "JavASketch by Mark Masse";

  }





  /**

   * The event-handler for the JavASketch Applet.

   * @param evt         The Event

   */  

  public boolean handleEvent(Event evt) {

    switch(evt.id) {



      case Event.KEY_PRESS:

      case Event.KEY_ACTION:



	// Bind Space to erase the Jav A Sketch

	if(evt.key == ' ') {

          showStatus("Shaking Jav A Sketch");

          shake();

          addPoint(x, y);

          repaint();

        }



	//

	// Bind the key press events to "turn on" direction

	//



        else if(evt.key == 'l' || evt.key == 'L' || evt.key == Event.UP) {

	  draw("UP", true);

        }

        else if(evt.key == 'k' || evt.key == 'K' || evt.key == Event.DOWN) {

	  draw("DOWN", true);

        }

        else if(evt.key == 'a' || evt.key == 'A' || evt.key == Event.LEFT) {

	  draw("LEFT", true);

        }          

        else if(evt.key == 's' || evt.key == 'S' || evt.key == Event.RIGHT) {

	  draw("RIGHT", true);

        }

	break;



      case Event.KEY_RELEASE:

      case Event.KEY_ACTION_RELEASE:



	//

	// Bind the key release events to "turn off" direction 

	//



        if(evt.key == 'a' || evt.key == 'A' || evt.key == Event.LEFT) {

	  draw("LEFT", false);

	}

        else if(evt.key == 's' || evt.key == 'S' || evt.key == Event.RIGHT) {

	  draw("RIGHT", false);

	}

        else if(evt.key == 'k' || evt.key == 'K' || evt.key == Event.DOWN) {

	  draw("DOWN", false);

	}

        else if(evt.key == 'l' || evt.key == 'L' || evt.key == Event.UP) {

	  draw("UP", false);

	}



	break;

      case Event.MOUSE_DOWN:

        showStatus("a = left, s = right, k = down, l = up," +

		   " and space = erase");

        break;

    }

    return true;

  }

 



  /**

   * Paints the JavASketch with the current graphic content

   * @param g            The graphics content

   */  

  public void paint(Graphics g) { 

  	update(g); 

  }





  /**

   * Updates the graphic content of the JavASketch   

   * @param ig           The graphics content

   */  

  public void update(Graphics igra) {

    Dimension d = size();

    if ((img == null) || (d.width != dim.width) || (d.height != dim.height)) {

      w   = d.width;

      h   = d.height;  

      img  = createImage(w, h);

      dim = d;

      gra  = img.getGraphics();

      updateSketch = true;

    } 



    // Check to see if the erasing "shake" should be performed

    if(shaken) {



      int i, j;

      int distance = 50;



      // Shake up and down

      for(i=0; i < 3; i++) {

	distance -= 10;



	for(j=0; j >= -100; j-=distance) {

	  igra.drawImage(img, 0, j, null);

	}

	

	for(j=-100; j <= 100; j+=distance) {

	  igra.drawImage(img, 0, j, null);

	}

	

	for(j=100; j >= 0; j-=distance) {

	  igra.drawImage(img, 0, j, null);

	}



      }

      shaken = false;

    }



    if(updateSketch) {

      // Redraw the JavASketch  

      // NOTE:  This will erase the current sketch

      drawSketch();                

      updateSketch = false;

    }      



    igra.drawImage(img, 0, 0, null);  

  } 





  /**

   * Draws all of the graphics for the JavASketch.  Including the

   * red border, and the "Jav A sketch" title

   */  

  public void drawSketch() {



    // Draw the red border 

    gra.setColor(Color.red);        

    gra.fillRoundRect(0, 0, w, h, 80, 80);  



    // Draw main rectangular drawing surface

    gra.setColor(Color.gray);  

    gra.fillRoundRect(40, 40, w-80, h-130, 20, 20);  

    gra.setColor(Color.lightGray);

    gra.fillRoundRect(43, 43, w-86, h-136, 20, 20);



    // Create the color fdd017

    Color Gold = new Color(253, 208, 23); 

    gra.setColor(Gold);               



    // Create Polygon for left arrow

    Polygon leftArrow = new Polygon();  



    // Create Polygon for right arrow

    Polygon rightArrow = new Polygon(); 



    // Create Polygon for up arrow

    Polygon upArrow = new Polygon();    



    // Create Polygon for down arrow

    Polygon downArrow = new Polygon();  



    // Add points to leftArrow Polygon

    leftArrow.addPoint(10,h-95);        

    leftArrow.addPoint(20,h-105);

    leftArrow.addPoint(20,h-85);



    // Add points to rightArrow Polygon

    rightArrow.addPoint(34,h-95);       

    rightArrow.addPoint(24,h-105);

    rightArrow.addPoint(24,h-85);



    // Add points to downArrow Polygon

    downArrow.addPoint(w-20,h-85);      

    downArrow.addPoint(w-10,h-95);

    downArrow.addPoint(w-30,h-95);



    // Add points to upArrow Polygon

    upArrow.addPoint(w-20,h-109);       

    upArrow.addPoint(w-10,h-99);

    upArrow.addPoint(w-30,h-99);



    // Fill the Arrow Polygons

    gra.fillPolygon(leftArrow);         

    gra.fillPolygon(rightArrow);

    gra.fillPolygon(downArrow);

    gra.fillPolygon(upArrow);



    // Draw left knob

    drawKnob(0, h - 80, 80, leftKnobAngle);



    // Draw right knob

    drawKnob(w - 80, h - 80, 80, rightKnobAngle);                  

  

    // Print "Jav A sketch" at the top 

    Font JS = new Font("JS", Font.ITALIC, 25);  

    gra.setFont(JS);

    FontMetrics fm = gra.getFontMetrics();

    int sWidth = fm.stringWidth("Jav A Sketch");

    gra.drawString("Jav A Sketch",(w - sWidth)/2, 25);



    // If we didn't just erase then show author info.

    if(!shaken) {

      showStatus("Jav A Sketch written by Mark Masse");

    }

  }





  /**

   * Clears the JavASketch screen.

   */

  public void shake() {

    shaken = true;

    updateSketch = true;

    up = false;

    down = false;

    left = false;

    right = false;

    repaint();

  }  





  public void drawKnob(int x, int y, int diameter, float startAngle) {

    Color oldColor = gra.getColor();



    // Draw the knob's border

    gra.setColor(Color.lightGray);        

    gra.fillOval(x, y, diameter, diameter);    



    float radius = (float) diameter/2;

    int centerX = x + (int) radius;

    int centerY = y + (int) radius;



    // Draw the knotches that will "move"

    gra.setColor(Color.gray);        



    for(float angle = startAngle; 

	angle <= (360.0f + startAngle); angle += 10.0f) {



      int borderX = centerX + (int) (radius * 

			   ((float) Math.cos((double) angle))); 



      int borderY = centerY + (int) (radius * 

			   ((float) Math.sin((double) angle))); 



      gra.drawLine(centerX, centerY, borderX, borderY);

    } 



    gra.setColor(Color.white);

    gra.fillOval(x + 4, y + 4, diameter - 8, diameter - 8);



    // Draw a dot in the center

    gra.setColor(Color.lightGray);        

    gra.fillOval(centerX - 1, centerY - 1, 2, 2);    



    gra.setColor(oldColor);

  }





  public void turnLeftKnob(String direction) {



    if(direction.equalsIgnoreCase("RIGHT")) {

      leftKnobAngle -= 2.5f;

    }

    else {

      leftKnobAngle += 2.5f;

    }



    if(leftKnobAngle >= 360.0f) {

      leftKnobAngle = 0.0f;

    }



    // Draw left knob

    drawKnob(0, h - 80, 80, leftKnobAngle);

  } 





  public void turnRightKnob(String direction) {

    

    if(direction.equalsIgnoreCase("UP")) {

      rightKnobAngle -= 2.5f;

    }

    else {

	rightKnobAngle += 2.5f;

    }

    if(rightKnobAngle >= 360.0f) {

      rightKnobAngle = 0.0f;

    }



    // Draw right knob

    drawKnob(w - 80, h - 80, 80, rightKnobAngle);

  } 





  /**

   * First checks to make sure the point specified by the parameters x and y

   * is in the sketching area, and if so it adds the point.  If the point is

   * outside the sketching area, the Applet's x and y values are reset to be

   * inside the area.

   * @param x              The x coordinate of the point to be added

   * @param y              The y coordinate of the point to be added

   */

  public void checkAndAdd(int X, int Y) {

    int border = 45;

    int bottomBorder = 95;



    if((X > border && X < w - border) && 

       (Y > border && Y < h - bottomBorder)) {   

      addPoint(X, Y);

      repaint();

    }

    else if(X < border)

    this.x = border + 2;

    else if(X > w - border)

    this.x = w - border - 2;

    else if(Y < border)

    this.y = border + 2;

    else if(Y > h - bottomBorder)

    this.y = h - bottomBorder - 2;

  }





  /**

   * Adds a "sketch"-point to the JavASketch. 

   * @param x              The x coordinate of the point to be added.

   * @param y              The y coordinate of the point to be added.

   */  

  public void addPoint(int x, int y) {

    if(gotFirstPoint) {



      // "Connect the dots" 

      gra.setColor(Color.black);

      gra.drawLine(x , y, lastx, lasty);



      // Draw the cursor as a light gray pixel

      gra.setColor(Color.lightGray);

      gra.drawLine(x, y, x, y);

    }



    // Set the "last" variables for the next call to this function

    lastx = x;

    lasty = y;

    gotFirstPoint = true;  // Set because this function has been called

  }





  public void draw(String direction, boolean state) {



    if(state) {

      if(direction.equalsIgnoreCase("UP") || 

	 direction.equalsIgnoreCase("DOWN")) { 



	if(direction.equalsIgnoreCase("UP")) {

	  up = true;

	  down = false;

	  y = y - 4;

	  turnRightKnob("UP");

	} 

	else {

	  down = true;

	  up = false;

	  y = y + 4; 

	  turnRightKnob("DOWN");

	}



	if(left) {

	  x = x - 4;

	  turnLeftKnob("LEFT");

	} 

	else if(right) {

	  x = x + 4;

	  turnLeftKnob("RIGHT");

	}

      } 

      else if(direction.equalsIgnoreCase("LEFT") || 

	     direction.equalsIgnoreCase("RIGHT")) { 

	

	if(direction.equalsIgnoreCase("LEFT")) {

	  left = true;

	  right = false;

	  x = x - 4;

	  turnLeftKnob("LEFT");

	} 

	else {

	  right = true;

	  left = false;

	  x = x + 4;

	  turnLeftKnob("RIGHT");

	}



	if(up) {

	  y = y - 4;

	  turnRightKnob("UP");

	} 

	else if(down) {

	  y = y + 4;

	  turnRightKnob("DOWN");

	}



      } 

      checkAndAdd(x, y);

    } 

    else {

      if(direction.equalsIgnoreCase("UP")) {

	up = false;

      } 

      else if(direction.equalsIgnoreCase("DOWN")) { 

	down = false;

      } 

      else if(direction.equalsIgnoreCase("LEFT")) {

	left = false;

      } 

      else if(direction.equalsIgnoreCase("RIGHT")) {

	right = false;

      } 

    }

  }



}