/**  Melissa Hao      6.837 Project 1      9/98

  *  This is my SpriteTest class.  This is the class to run when viewing my
  *  my project 1.  In this applet, I simulate flying through a field of
  *  flowers.  At first, you see the flowers off in the horizon; and then
  *  they come closer to you, increasing in size during the process.

  *  Each flower is displayed as an animation sequence that I achieved through
  *  my AnimationSprite class.  This class is based on the notion of Sprites
  *  and states.  Note - my class differs from the outline given in lecture...
  *  I created my class tailored to my own needs.

  *  Here is how my applet meets the five requirements:
  *
  *    -  I display two kinds of images, a short-stemmed flower and a long-
  *       stemmed one.
  *    -  the short-stemmed flowers obviously move around on the "field"
  *       (although it's supposed to look like they're stationary and you, as
  *       you, as the observer, is moving)
  *    -  my sprites obviously are properly clipped (see Sprite.Draw())
  *    -  my sprites obviously implement transparent pixels (see Sprite.Draw())
  *    -  you can click anywhere on the sprite and my applets prints out
  *       where you clicked, and also whether the pixel was transparent or not.
  *       (This is where the long-stemmed flower comes in handy... you can use
  *       that to test this procedure since it's stationary.)

  *  Enjoy!

  */



import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.lang.*;
import java.util.*;
import java.math.*;
import AnimatedSprite;

public class SpriteTest extends Applet implements MouseListener,
                                                  Runnable
{
   static final int NUM_SPRITES = 50;
   int HIGHEST_ABOVE_GROUND = 10;
   int ground = 216;
   int SLEEP_TIME = 100;

   Image output;
   Raster bg, temp;
   Thread animate;
   Sprite longstem;
   AnimatedSprite s;
   int current_states[] = new int[ NUM_SPRITES];
   Point points[] = new Point[ NUM_SPRITES];
   boolean BEHIND_HORIZON[] = new boolean[ NUM_SPRITES];
   int sprite_visible_height[] = new int[ NUM_SPRITES];
   int num_states;
   int center;
   int bg_w, bg_h;
   int s_w, s_h[] = {34, 51, 84, 84, 103, 199};
   int lastX, lastY;
   Random rand = new Random();

   public void init()
   {
      Image[] images = {
                         getImage( getDocumentBase(), "shortstem0.gif"),
                         getImage( getDocumentBase(), "shortstem1.gif"),
                         getImage( getDocumentBase(), "shortstem2.gif"),
                         getImage( getDocumentBase(), "shortstem3.gif"),
                         getImage( getDocumentBase(), "shortstem4.gif"),
                         getImage( getDocumentBase(), "shortstem5.gif"),
      };
      num_states = images.length;
      longstem = new Sprite(getImage( getDocumentBase(), "longstem.gif"));
      s = new AnimatedSprite( images);
      showStatus( "Using " + getParameter("image"));
      bg_w = getSize().width;  bg_h = getSize().height;
      s_w  = s.getWidth();   //  s_h  = s.getHeight();
      center = bg_w/2 - s_w/2;
      //System.out.println("s_w = " + s_w + "; s_h = " + s_h + "; bg_w = " + bg_w + "; bg_h = " + bg_h);
      
      for (int i = 0; i < points.length; i++)
      {
         points[i] = new Point();
         reset( i);
         //System.out.println("random() = " + random() + ";  new point is " + points[i]);
      }

      bg = new Raster( getImage( getDocumentBase(), getParameter("bg")));

      this.addMouseListener( this);

      render();
      //for (int i=0; i<6; i++)  s.Draw(bg,i*50,200,s.sprites[i].getHeight(),i);
   }

   public void start() {
      animate = new Thread( this);
      animate.start();
   }

   public void stop() {
      animate = null;
   }

   public void run()
   {
      while (true) {
         try {
            animate.sleep( SLEEP_TIME);
         }
         catch (InterruptedException e) {
         }
         render();
      }
   }

   public void render()
   {
      temp = new Raster( bg.toImage());

      //s.Draw(temp,-100,213);
      //s.Draw(temp,400,213);

      for (int i = 0; i < points.length; i++)
      {
         int x = points[i].x,  y = points[i].y;

         if (BEHIND_HORIZON[i])
            s.Draw( temp, x, y, sprite_visible_height[i], current_states[i]);
         else
            s.Draw( temp, x, y, current_states[i]);
         //System.out.println("IN RENDER: current state is " + current_states[i]);

         //System.out.print("(" + x + ", " + y + ")   ");
         //getGraphics().drawLine( 0, y, bg_w, y);
         points[i].x += translateX( x, i);
         points[i].y += translateY( y, i);
         sprite_visible_height[i] = update_visible_height( sprite_visible_height[i], i);

         if (points[i].x + s_w < 0  ||  points[i].x > bg_w  || points[i].y - s_h[current_states[i]] > bg_h)
            reset( i);
      }
      //System.out.println();
      output = temp.toImage();

      longstem.Draw( temp, 0, 300);
      //      longstem.Draw( temp, 100, 400);
      //      longstem.Draw( temp, 300, 250);

      repaint();
   }

   public void paint( Graphics g) {
      g.drawImage( output, 0, 0, this);
   }

   public void update( Graphics g)  { paint(g); }
      
   public void mousePressed( MouseEvent e)
   {
      System.out.print( "mouse clicked at (" + e.getX() + ", " + e.getY() + ")");
      System.out.println( ";   transparent pixel? : " + transparent(e.getX(),e.getY()));
      
      lastX = e.getX();
      lastY = e.getY();
      //      s.Draw( bg, lastX, lastY);
      //      output = bg.toImage();
      //      update( getGraphics());
   }

   public boolean transparent( int x, int y)
   {
      return (temp.getPixel(x,y) == bg.getPixel(x,y));
   }
      
   public void mouseReleased(MouseEvent e) {}
   public void mouseClicked( MouseEvent e) {}
   public void mouseEntered( MouseEvent e) {}
   public void mouseExited(  MouseEvent e) {}

   public void reset( int i) {
      //      p[i].setLocation( Math.abs( rand.nextInt()) % (bg_w + s_w) - s_w, ground-5);
      points[i].setLocation( random(), ground);
      BEHIND_HORIZON[i] = true;
      sprite_visible_height[i] = 1;
      current_states[i] = 0;
   }

   public int translateX( int x, int i) {
      if (BEHIND_HORIZON[i])
         return (x < center) ?  -1  :  1;
      else
         return new Float(Math.abs( x-center) * .001 * (x-center)).intValue();
   }

   public int translateY( int y, int i)
   {
      if (y == ground - HIGHEST_ABOVE_GROUND) {
         BEHIND_HORIZON[i] = false;
      //System.out.println("BEHIND_HORIZON set to false");
         return -1;
      }
      else if (BEHIND_HORIZON[i])
         return -1;
      else {
         if (current_states[i] < (num_states-1))
         {
            current_states[i] = current_states[i] + 1;
            //System.out.println("current state of sprite " + i + " is " + current_states[i]);
         }
         return 25;
      }
   }

   public int update_visible_height( int current, int i)
   {
      if (BEHIND_HORIZON[i])  return (ground - points[i].y + 2);
      else                    return (current + 15);
   }

   public int random() {
      int temp = -s_w - 1;
      while (temp < -s_w  ||  temp > bg_w)
         temp = (int) Math.round(300.0*rand.nextGaussian() + (double) (bg_w + s_w)/2);
      return temp;
   }
}
