import java.awt.*;
import java.awt.image.*;
import java.util.Vector;

class AnimatedSprite extends Sprite {
  /**
   *This class implements an animated sprite; that is, a sprite that has
   *multiple frames that can be displayed sequentially to create an animation
   *The Animated Sprite has the following properties
   *tracks- different possible animation sequences- 
   *        ex: 1)the monkey walks 2)The monkey turns his head
   *frames- the actual animation frames in a given track
   *ticks- You can specific the number of ticks of time that each frame is displayed
   *dx, dy- For each frame, you can control the amount that the sprite shifts
   *The Draw method draws the next frame in the animation sequence
   */
  int frameWidth;  //the width of a frame in the animation sequence
  int curTrack;  //the current track being drawn
  int curIndex;  //the current frame index in the current track
  Raster pictures;  //the set of all the frames in one raster
  int clock;  //counts out the time that an animation frame is displayed

  class AnimationFrame {
    /**
     *This class is used as a data structure in the vectors defined below
     *Each frame in each track has the characteristic data types defined here
     */
    int frame;  //the sprite frame that belongs at this point in animation sequence
    int ticks;  //the number of ticks of time that sprite is displayed
    int dx; //dx to the next frame
    int dy; //dy to the next frame
    
    AnimationFrame(int f, int t, int deltax, int deltay) {
      /**
       *constructor method for animation frame- puts the data into the
       *the class variables.
       */
      frame= f;
      ticks= t;
      dx= deltax;
      dy= deltay;
    }
  }
  Vector movement; //the vector movement will hold type AnimationFrame    
  Vector tracks = new Vector(0); //each track is a vector of frames
  /**
   *Note that this arrangement of tracks and frames creates what is in
   *effect an extensible 2D array.  The array does not even have to be
   *rectangular- Track 0 could have 5 frames and track 1 could have 3 frames
   */

  public AnimatedSprite(Image images, int frames) {
    /**
     *This is the constructor for the AnimatedSprite
     *The idea is to have all of sprites in one image, and know the number of total
     *sprites, and then partition off the big image into each of the actual sprites
     *sprite_size = images_size/ frames
     *Sprite frames should be stored side by side in the image
     *For example, a sprite of size 10x10 with 3 frames would have an image
     *of size 10x30 (height=10, width=30).
     */
    super.x=300; //Make the default starting spot for the sprite be at (300,100)
    super.y=100;
    pictures= new Raster(images);  //load the images into a raster
    frameWidth= pictures.getWidth() / frames;  //the frame width of each sprite
    clock=0;  /**reset the clock, which counts out how long the sprite has
	       *been in a certain frame
	       */
  }
  
  public void addState(int track, int frame, int ticks, int dx, int dy) {
    /**
     *Adds another animation frame (referenced by frame) to the end of the
     *indicated track.  This frame will be displayed for the given number of
     *clock ticks and then increment the sprite position by dx,dy
     */
    if (track >= tracks.size()) {  
      //higher track number; need to create a new track at the correct number
      tracks.setSize(track+1);
    }
    if (((Vector) tracks.elementAt(track)) == null) {
      //this is the first frame in this track, so need to create a movement vector
      tracks.insertElementAt(new Vector(0), track);
    }
    //create a new animation frame with the new state info
    AnimationFrame nextFrame= new AnimationFrame(frame, ticks, dx, dy);
    //add the new frame to the end of the specified track
    ((Vector) tracks.elementAt(track)).addElement(nextFrame);
  }
  
  public void Draw(Raster bgnd) {
    /**
     *Draws the current animation frame for this animated sprite.  The variables
     *curTrack and curIndex (not curFrame!) keep track of which frame is
     *current.
     */
    
    //curFrame is used to make it easier to reference the current frame in
    //the 2D Vector structure
    AnimationFrame curFrame= ((AnimationFrame) 
			      ((Vector) 
			       tracks.elementAt(curTrack)).elementAt(curIndex));

    //Note that this is very similar to the Sprite.Draw method
    for (int j= Math.max(y,0);  //the minimum y pixel to draw
	 j< Math.min((y+pictures.getHeight()), bgnd.getHeight());//the max y pixel
	 j++) {
      for (int i= Math.max(x,0);  //the min x pixel to draw
	   i< Math.min((x+frameWidth), bgnd.getWidth()); //the max x pixel
	   i++) {
	if (notTransparent(pictures.getPixel(i-x+(curFrame.frame*frameWidth),j-y)))
	  //only draw the pixels that aren't transparent
	  bgnd.setPixel(pictures.getPixel(i-x+(curFrame.frame*frameWidth),j-y), 
			i, j);
      }
    }
  }

  public void nextState() {
    /**
     *This function increments the AnimatedSprite curTrack and curIndex variables
     *to whichever frame should be displayed at the next call of Draw.
     *The clock variable keeps track of how long a frame is displayed.  If
     *the clock is less than number of ticks for a frame, then nextState()
     *does not increment curTrack and curIndex counters.
     */


    //curFrame is used to make it easier to reference the current frame in
    //the 2D Vector structure
    AnimationFrame curFrame= ((AnimationFrame) ((Vector) tracks.elementAt(curTrack))
			      .elementAt(curIndex));
    //increment clock each time
    clock++; 
    if ((clock >= curFrame.ticks) &&
	((curIndex+1) < ((Vector) tracks.elementAt(curTrack)).size())){
      //if it's time to display a new Frame and there are frames left in track
      //if there are no frames left, just keep displaying the last frame
      clock=0;  //reset the clock for the new frame
      curIndex++;  //change to the next frame
      x+= curFrame.dx;  //increment the sprite position
      y+= curFrame.dy;
    }
  }

  public void startAtXY(int clickX, int clickY) {
    /**
     *This allows the user to set the location of the sprite to a certain
     *place.  It is assume that the (clickX,clickY) location is legal.
     *The sprite is also reset to use the track 0 frame 0
     */
    x=clickX;
    y=clickY;
    clock=0;  
    curTrack=0;
    curIndex=0;
  }

  public void setTrack(int t) {
    /**
     *allows the user to set the track for the sprite (this enables different
     *animations for different user events
     */
    curTrack= t;
  }
}







