import java.awt.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.ImageIO;
import java.util.Arrays;
import java.util.HashMap;

public abstract class Sprite implements Drawable, Actor{
	
	public static final byte KEY_LEFT = 0x01;
	public static final byte KEY_RIGHT = 0x02;
	public static final byte KEY_JUMP = 0x04;
	public static final byte KEY_RUN = 0x08;
	public static final byte KEY_UP = 0x04;
	public static final byte KEY_DOWN = 0x08;
	
	public static final byte KEY_FIRE = 0x10;
	
	public static final byte KEY_PRJ_LEFT = 0x01;
	public static final byte KEY_PRJ_RIGHT = 0x02;
	public static final byte KEY_PRJ_UP = 0x04;
	public static final byte KEY_PRJ_DOWN = 0x08;
	
	protected float x, y; //upper left corner of sprite object
	protected int w, h;	//width and height in 32x32 tiles

	private ClassLoader cl = HWDisplay.cl;
	
	private int hashCode;
	BufferedImage[][] sprites;
	private int spriteMode;
	private int spriteSpeed;
	protected int[] animLengths;
	protected int spriteNum;
	protected int spriteCounter;
	protected boolean animate;
	protected boolean destroy;
	
	public Sprite(HashMap<Sprite, BufferedImage[][]> sc, String picName, int[] animLengths) {
		hashCode = Arrays.hashCode(animLengths) ^ picName.hashCode();
		if (sc.containsKey(this)) {
			sprites = sc.get(this);
		} else {
			sprites = new BufferedImage[animLengths.length][];
			for (int i=0; i<animLengths.length; i++)
				sprites[i] = new BufferedImage[animLengths[i]];
			
			try {
				for (int i=0; i<sprites.length; i++) {
					for (int j=0; j<sprites[i].length; j++) {
						sprites[i][j] = ImageIO.read(cl.getResource(picName+i+j+".png"));
					}
				}
			} catch (IOException e) {
				System.out.println("Failed to load images for sprite: " + picName);
			}
			
			sc.put(this, sprites);
		}
		
		w=h=1;
		spriteCounter = 0;
		setSpriteSpeed(10);
		spriteNum = 0;
		spriteMode = 0;
		animate=true;
		destroy=false;
		this.animLengths=animLengths;
	}
	
	protected BufferedImage getNextSprite() {
		if (animate && ++spriteCounter >= spriteSpeed) {
			spriteCounter=0;
			if (++spriteNum >= sprites[spriteMode].length)
				spriteNum=0;
		}
		return sprites[spriteMode][spriteNum];
	}
	public void setSpriteMode(int mode) {
		if (mode!=spriteMode) {
			spriteMode=mode;
			spriteNum=0;
			spriteCounter=0;
		}
	}
	public void setSpriteSpeed(int speed) {
		spriteSpeed = speed;
	}
	
	public boolean isSetToDestroy() {
		return destroy;
	}
	public void setToDestroy(boolean destroy) {
		this.destroy=destroy;
	}

	
	public void draw(Graphics2D g, int x, int y) {
		g.drawImage(getNextSprite(), x, y, null);
	}
	
	public boolean hitSprite(Sprite spr) {
		return (spr.getX()+spr.getW()*32>x && x+w*32>spr.getX() &&
				spr.getY()+spr.getH()*32>y && y+h*32>spr.getY());
	}
	
	public abstract void act();
	
	public int hashCode() {
		return hashCode;
	}
	public boolean equals(Object o) {
		return (o instanceof Sprite) && o.hashCode()==hashCode();
	}


	public int getH() {
		return h;
	}
	public int getW() {
		return w;
	}
	public int getX() {
		return (int)x;
	}
	public int getY() {
		return (int)y;
	}
	public void setLoc(float x, float y) {
		this.x = x;
		this.y = y;
	}
}
