import java.util.Vector;
import java.awt.Image;
import java.awt.Color;


class AnimatedSprite extends Sprite {
  private Vector track;   // Vector of tracks (each track = Vector of Frames)
  private int ticks;
  private int track_num, frame_num, dx, dy;
  private boolean stopped = false;
  public boolean wallBounce = true;
  public boolean reverse = false;

  private Raster frame[];
  private Frame current;
  private AnimatedSpriteStateChanger stateChanger;

  public AnimatedSprite(Image images, int frames) {
    this(images, frames, 0, 0);
  }

  public AnimatedSprite(Image images, int frames, int dx, int dy) {
    Raster source = new Raster(images);
    width = source.getWidth() / frames;
    height = source.getHeight();
    
    frame = new Raster[frames];
    for (int i=0; i < frames; i++)
      frame[i] = new Raster(source, width*i, 0, width, height);

    init(dx, dy);
  }

  public AnimatedSprite(Image image[]) {
    this(image, 0, 0);
  }


  public AnimatedSprite(Image image[], int dx, int dy) {
    frame = new Raster[image.length];
    for (int i = 0; i < frame.length; i++) 
      frame[i] = new Raster(image[i]);


    init(dx, dy);
  }

  private void init(int dx, int dy) {
    this.dx = dx; this.dy = dy;
    stateChanger = null;
    ticks = track_num = frame_num = 0;
    track = new Vector();
    // Add default track, 0: 1 tick per frame, stationary
    for (int i=0; i < frame.length; i++)
      addState(0, i, 1);
    
    current=(Frame)((Vector)track.elementAt(track_num)).elementAt(frame_num);
    width = frame[0].getWidth();
    height = frame[0].getHeight();

    changeToRaster(frame[current.frame_num]);
  }
  
  private void changeToRaster(Raster r) {
    this.pixel = r.pixel;   // Not copying!
  }

  public void setStateChanger(AnimatedSpriteStateChanger assc) {
    stateChanger = assc;
  }

  public void addState(int track, int frame, int ticks) {
    /* Create track if necessary */
    if (this.track.size() <= track)
      this.track.insertElementAt(new Vector(), track);

    ((Vector)this.track.elementAt(track)).addElement(new Frame(ticks, frame));
  }
  
  public void pause() { stopped = true; }
  public void resume() { stopped = false; }
  public void toggle() { stopped = !stopped; }

  public int impacted(Sprite s, int side) {
    /* Bounce by default */
    switch (side) {
    case Sprite.HORIZONTAL:
      dx *= -1;
      x += dx;
      break;
    case Sprite.VERTICAL:
      dy *=-1;
      y += dy;
      break;
      /*    case DIAGONAL:
      dx += dx/3;
      dx *= -1;
      dy -= dy/3;
      dy *= -1; 
      */
    }
    reverse = !reverse;
    return Playfield.BOUNCE;
  }

  public int leftPlayfield() {
    return Playfield.DESTROY_SELF;
  }

  public int impactedPlayfieldBoundary(int side) {
    if (wallBounce)
      return impacted(null, side);
    else return Playfield.CONTINUE;
  }

  public void impactedBy(Sprite s, int consequence) {
  }

  public void nextState() {
    nextState(null);
  }

  public void nextState(Playfield p) {
    if (stopped) return;
    if (++ticks >= current.ticks) {
      ticks = 0;

      if (stateChanger == null) {
	if (!reverse) {
	  if (++frame_num >= ((Vector)track.elementAt(track_num)).size()) 
	    frame_num = 0;
	} else {
	  if (--frame_num < 0)
	    frame_num = ((Vector)track.elementAt(track_num)).size() - 1;
	}
	x += dx;
	y += dy; 
      }
      else {
	Pointer tptr = new Pointer(new Integer(track_num)),
	  fptr = new Pointer(new Integer(frame_num)),
	  xptr = new Pointer(new Integer(x)),
	  yptr = new Pointer(new Integer(y));

	stateChanger.changeState(p, this, tptr, fptr, xptr, yptr, dx,
				 dy, frame);
	track_num = ((Integer)tptr.thing).intValue();
	frame_num = ((Integer)fptr.thing).intValue();
	x = ((Integer)xptr.thing).intValue();
	y = ((Integer)yptr.thing).intValue();
      }
      current = 
	(Frame)((Vector)track.elementAt(track_num)).elementAt(frame_num);
      changeToRaster(frame[current.frame_num]);
    }
  }

  public void setTrack(int track_num) {
    this.track_num = track_num;
    frame_num = 0;
  }

  private class Frame {
    int ticks;
    int frame_num;

    public Frame(int ticks, int frame_num) {
      this.ticks = ticks;
      this.frame_num = frame_num;
    }
  }

public void clicked() {
  toggle();
}

}

