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

/**
 * The Playfield class implements a field on which sprites can "play".
 */

public class Playfield extends Raster implements Runnable {
    private Raster background; // The background of the Playfield.
    private Vector sprites;    // The sprites of the Playfield.

    ///////////////////////// Constructors //////////////////////

    /**
     * Constructs a new playfield with background b as a background image.
     * Unlike the interface given in class, it is not necessary to supply
     * numSprites, since we use a Vector not an Array to store the sprites;
     * This allows us to have an undetermined number of sprites.
     */
    public Playfield(Image b) {
	// Use background as the initial picture for the Raster.
	super(b);

	// Also save a copy since we're going to paint over the Raster.
	background = new Raster(b);
	sprites = new Vector();
    }

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

    /**
     * Adds the AnimatedSprite s to the Playfield.
     * Unlike the interface given in class, you don't select a slot for
     * the sprite to go in; it picks one for you.
     */
    public void addSprite(AnimatedSprite s) {
	sprites.addElement(s);
    }

    /**
     * Called when a tick passes to update the Playfield.
     */
    public void tick() {
	int i;
	AnimatedSprite s;

	// Undraw all sprites to restore the background.
	for (i=0; i < sprites.size(); i++) {
	    s = (AnimatedSprite)sprites.elementAt(i);
	    if (s != null) {
		s.undraw(this, background);
	    }
	}
	
	// Call tick() on all the sprites to that they update.
	for (i=0; i < sprites.size(); i++) {
	    s = (AnimatedSprite)sprites.elementAt(i);
	    if (s != null) {
		try {
		    s.tick();
		} catch (DestroyMe e) {
		    // If a sprite throws the DestroyMe exception,
		    // it no longer wants to exist anymore.
		    sprites.removeElementAt(i);
		}
	    }
	}

	// Redraw all the sprites on the empty background.
	for (i=0; i < sprites.size(); i++) {
	    s = (AnimatedSprite)sprites.elementAt(i);
	    if (s != null) {
		s.draw(this);
	    }
	}

	// Call update image to indicate our changes are done and update
	// any consumers.
	updateImage();
    }

    /**
     * Handles a mouse click by the user at location (x,y).
     * Returns true if we actually handled it.
     */
    public boolean click(int x, int y) {
	AnimatedSprite s;
	boolean clicked = false; // true if one of our sprites handled it.
	
	for (int i = 0; i < sprites.size(); i++) {

	    s = (AnimatedSprite)sprites.elementAt(i);

	    // Only test and call click() on sprites that implement the 
	    // Clickable interface.
	    if (s != null && s instanceof Clickable && s.inside(x,y)) {
		((Clickable)s).click();
		clicked = true;
	    }

	}
	
	return clicked;
    }

    ////////////////////////// Special //////////////////////////

    /**
     * Loops forever, calling tick() when every "tick" passes..
     */
    public void run() {
	while (true) {

	    // If we actually had a fast machine, a delay loop would go here.

	    this.tick();
	}
    }

}
