import java.awt.*;

class AnimatedSprite extends Sprite
{
	private int tracks;	// number different tracks
	private int frames[][],frameTotal;	// array of frames [track#][frame#]
//	private int trackOffsets[];	// offset distance from track 0 for ea frame
	private int curFrame, curTrack;
	private int dx[][], dy[][];
	private Raster allFrames;	// holds all the frames
	private int fullWidth, fullHeight; // size of full frameimage
	
	/* A note on implementation:
	 * 		The various images are expected to be parts of a single
	 *		image, all lined up horizontally.  Track 0 first, followed
	 *		by 1, etc [ie, 00 01 02 ... 0n 10 11 12 ... 1m 20 21 22 ...]
	 *		in case it wasn't obvious, all must be the same size.
	 *
	 *		Also, the dx,dy values for a frame are added upon ENTERING
	 *		the state.
	 *
	 *		You *must* initialize tracks and frames before it will
	 *		function properly.
	 */
    
	/**
	 * The Empty Constructor
	 *
	 */
	public AnimatedSprite()
	{
	}
	
	/**
	 * Another constructor -- spec # frames, tracks
	 *
	 */
	public AnimatedSprite(Image img, int frames, int tracks)
	{
		super();	// set up the sprite superclass with the image
		allFrames=new Raster(img);	// load all the frames
		fullWidth=allFrames.getWidth();
		fullHeight=allFrames.getHeight();

		frameTotal=frames;	// number of frames in file
		width=fullWidth/frameTotal;	// width of each frame
		height=fullHeight;
		x=0; y=0;	// put it in upper left corner
		xOff=0; yOff=0;	// reference from upper-left
		
		// Unfortunately, must hand-init all the raster stuff
		pixel=new int[width*height];
		
		this.tracks=tracks;
		this.frames=new int [tracks][];	// set up tracklist
		dx=new int[tracks][];
		dy=new int[tracks][];
		curFrame=0;
		curTrack=0;
	}
	
	/**
	 * This one also does x and y
	 *
	 */
	public AnimatedSprite(Image img, int frames, int tracks, int x, int y)
	{
		super();	// set up the sprite superclass with the image
		allFrames=new Raster(img);	// load all the frames
		fullWidth=allFrames.getWidth();
		fullHeight=allFrames.getHeight();

		frameTotal=frames;	// number of frames in file
		width=fullWidth/frameTotal;	// width of each frame
		height=fullHeight;
		this.x=x; this.y=y;	// put it in upper left corner
		xOff=0; yOff=0;	// reference from upper-left
		
		// Unfortunately, must hand-init all the raster stuff
		pixel=new int[width*height];
		
		this.tracks=tracks;
		this.frames=new int [tracks][];	// set up tracklist
		dx=new int[tracks][];
		dy=new int[tracks][];
		curFrame=0;
		curTrack=0;
	}	
	
	/**
	 * This one also does x and y, now with offsets
	 *
	 */
	public AnimatedSprite(Image img, int frames, int tracks,
				int x, int y, int xOff, int yOff)
	{
		super();	// set up the sprite superclass with the image
		allFrames=new Raster(img);	// load all the frames
		fullWidth=allFrames.getWidth();
		fullHeight=allFrames.getHeight();

		frameTotal=frames;	// number of frames in file
		width=fullWidth/frameTotal;	// width of each frame
		height=fullHeight;
		this.x=x; this.y=y;	// put it in upper left corner
		this.xOff=xOff; this.yOff=yOff;	// reference from upper-left
		
		// Unfortunately, must hand-init all the raster stuff
		pixel=new int[width*height];
		
		this.tracks=tracks;
		this.frames=new int [tracks][];	// set up tracklist
		dx=new int[tracks][];
		dy=new int[tracks][];
		curFrame=0;
		curTrack=0;
	}	
	
	///	Other Routines ///
	
	/**
	 * Adds a new track to the sprite.  Must add frames with addFrame
	 *
	 */
	public boolean addTrack(int trackNum, int numFrames)
	{
		if(trackNum > tracks) return false;	 // overshot end of array
		
		frames[trackNum]=new int[numFrames];
		dx[trackNum]=new int[numFrames];
		dy[trackNum]=new int[numFrames];
		return true;
	}

	/**
	 * Add a frame to an already-defined track.
	 *
	 * trackNum is number of track to add to, trackFrameNum is number
	 * of frame in the track, frameNum is absolute number of the frame
	 * in the animation image.  dx, dy are obvious
	 */
	public boolean addFrame(int trackNum, int trackFrameNum, int frameNum,
								int dx, int dy)
	{
		if(frameNum > frames[trackNum].length)	// overshot array
			return false;
		
		frames[trackNum][trackFrameNum]=frameNum;
		this.dx[trackNum][trackFrameNum]=dx;
		this.dy[trackNum][trackFrameNum]=dy;
		return true;
	}
	
	/**
	 * Set the current track; it will start from frame 0
	 *
	 */
	public boolean setTrack(int trackNum)
	{
		if(trackNum>tracks) return false; // not that many tracks!
		
		curTrack=trackNum;
		return true;
	}
	
	/**
	 * Set the current track and specify the starting frame
	 *
	 */
	public boolean setTrackStart(int trackNum, int trackStartFrame)
	{
		if (trackNum>tracks) return false;
		if (trackStartFrame>frames[trackNum].length)
			return false;
			
		curTrack=trackNum;
		curFrame=trackStartFrame;
		return true;
	}
	
	/**
	 * Move to the next frame in the track
	 *
	 */
	public void nextFrame( )
	{
		curFrame=(curFrame+1)%(frames[curTrack].length); // increment w/ wrap-around
		x+=dx[curTrack][curFrame];
		y+=dy[curTrack][curFrame];
	}
						
	/**
	 * Draws the current frame into bg
	 *
	 */
	public void draw(Raster bg)
	{
		if (curFrame > frames[curTrack].length)
			return;	// should only happen if we are called by a
				// a thread that interrupts a track switch
							
		for(int i=0;i<width;i++)
			for(int j=0;j<height;j++)
			{
				int pix=allFrames.getPixel(i+(frames[curTrack][curFrame])*width,j);
				setPixel(pix,i,j);
			}
			super.draw(bg); // call the regular sprite draw routine
	}

	public boolean setAlpha(Raster alpha)
	{
		if((alpha.getWidth() != fullWidth) || (alpha.getHeight() != fullHeight))
			return false;	// not same size!
			
		int i, j;
		
		for(i=0;i<fullWidth;i++)
			for(j=0;j<fullHeight;j++)
				allFrames.setPixel((allFrames.getPixel(i,j)&0x00FFFFFF) |
					(alpha.getPixel(i,j)&0x00FF0000)<<8,i,j);
		// above just masks out all but red channel, moves to alpha
		
		return true;
	}
}
