import java.awt.*;
import java.awt.image.*;

/**
 * Animated Sprite Class
 */

class AnimatedSprite extends Sprite {

  int numframes;  // number of image frames in animation
  int numstates;  // number of states in animation track
  Raster frame[]; // stores image frame
  State track[];  // animation track
  int current_state; 
  int ticker; // timer

  /**
   * Class for animation state
   */

  class State extends Object {
    public int dx,  // change in x
               dy,  // change in  y 
	       numticks, // display time for frame
	       frame; // index to frame array

    // Constructor

    public State(int numticks, int dx, int dy, int frame)
    {
      this.numticks = numticks;
      this.dx = dx;
      this.dy = dy;
      this.frame = frame;
    }
  }

  ////////////////////// Constructors and Initializers ///////////////////////

  /**
   *  Initialize animated sprite from image strip and number of frames
   */

  public AnimatedSprite(Image images, int numframes)
  {   
    super(images);
    
    // Initialize members

    this.numframes = numframes;
    current_state = 0;
    frame = new Raster[numframes];
    ticker = 0;

    // Set up temporary raster to read images

    Raster r = new Raster(images);
    width = r.getWidth()/numframes;
    height = r.getHeight();

    int w = r.getWidth();
    int [] pixels;
    pixels = r.getPixels();

    // copy each image from strip into a frame

    for (int f = 0; f < numframes; f++)
      {
	frame[f] = new Raster(width, height);
	for (int i = 0; i < width; i++)
	  for (int j = 0; j < height; j++)
	    {
	
	      frame[f].setPixel(pixels[j*w + f*width+i], i, j);
	    }
      }

    // initialize Sprite with the first frame

    for (int i = 0; i < width; i++)
      for (int j = 0; j < height; j++)
	{
	  setPixel(pixels[j*w+i], i , j);
	}
  }


  /**
   *  Initialize animation track
   */

  public void setTrack(int numstates)
  {
    this.numstates = numstates; 
    track = new State[numstates];
  }

  /**
   * Add animation state
   */

  public void addState(int state, int ticks, int dx, int dy, int frame)
  {
    track[state] = new State(ticks, dx, dy, frame);
  }


  //////////////////////////// Methods ///////////////////////////////

  /**
   * Draw animated sprite into background
   */

  public void Draw(Raster bgnd)
  {
    int w = bgnd.getWidth();
    int h = bgnd.getHeight();
    
    // Implements wraparound

    if (x < -width)
      x = w-1;
    if (x >= w)
      x = -width;
    if (y < -height)
      y = h-1;
    if (y >= h)
      y = -height;

    super.Draw(bgnd);
  }

  /**
   * Update Animation state
   */

  public void nextState()
  {
    
    if (ticker == track[current_state].numticks)  /* Time to change frames */
      {
	// update Sprite position change to next state

	ticker = 0;
	x += track[current_state].dx;
	y += track[current_state].dy;
	current_state++;
	if (current_state == numstates)  /* Wraparound to first state */
	  current_state = 0;

	// copy new frame pixels into Sprite

	int pixels[];
	pixels = frame[track[current_state].frame].getPixels();
	for (int i = 0; i < width; i++)
	  for (int j = 0; j < height; j++)
	    {
	      setPixel(pixels[width*j+i], i , j);
	    }
      }
    ticker++;
  }

  /**
   * Reset animated sprite to first state in track
   */

  public void resetTrack()
  {
    // reset state variables

    current_state = 0;
    ticker = 0;

    // copy first state frame

    int pixels[];
    pixels = frame[track[0].frame].getPixels();
    for (int i = 0; i < width; i++)
      for (int j = 0; j < height; j++)
	setPixel(pixels[width*j+i], i , j);
  }
}







