import java.util.*;

/**
 * A Calaveras Crossing level.  Each Calaveras Crossing level has 13
 * lanes, including the starting lane and the home lane.
 *
 * @author Jim Glenn
 * @version 0.2 1/8/2009 changed for x-coordinates measured in frog widths
 * @version 0.1 10/7/2008
 */

public class Level
{
    /**
     * The number of lanes per level, including the starting lane and the
     * home lane.
     */

    public static final int NUM_LANES = 13;

    /**
     * The number of homes in a level.
     */

    public static final int NUM_HOMES = 5;

    /**
     * The lanes in this level.
     */

    private Lane[] lanes;

    /**
     * Create a new level with 12 empty grass lanes and the home lane.
     */

    public Level()
    {
	lanes = new Lane[NUM_LANES];

	// create empty lanes of grass
	
	for (int l = 1; l < NUM_LANES; l++)
	    {
		lanes[l] = new Lane();
	    }

	// create home lane

	Lane homeLane = new Lane();
	
	// compute home spacing so that homes are evenly spaced at
	// positions that are integer multiples of frog widths;
	// this assumes that the screen is at least 5 frogs wide.

	int spacing = 0;
	while (NUM_HOMES * (spacing + 1) - 1 <= Lane.SCREEN_WIDTH)
	    {
		spacing++;
	    }

	// compute position of 1st home that centers things

	double firstHome = (Lane.SCREEN_WIDTH / 2 - (Home.HOME_WIDTH - 1.0) / 2) - (NUM_HOMES / 2 * spacing);

	for (int h = 0; h < NUM_HOMES; h++)
	    {
		homeLane.addObstacle(new Home(), firstHome + h * spacing);
	    }

	lanes[0] = homeLane;
    }

    /**
     * Adds the given lane to this level at the given position.  Lanes
     * are numbered from top to bottom starting with 0 for the niche lane.
     *
     * @param l a lane
     * @param p lane position
     */

    public void addLane(Lane l, int p)
    {
	if (l == null)
	    throw new IllegalArgumentException("null lane");

	if (p < 0 || p >= NUM_LANES)
	    throw new IllegalArgumentException("Invalid lane index: " + p);

	if (p == NUM_LANES - 1)
	    throw new IllegalArgumentException("Can't replace home lane: " + p);

	lanes[p] = l;
    }

    /**
     * Returns the number of lanes in this level.  In the current
     * implementation all levels have 13 lanes.
     *
     * @return the number of lanes in this level
     */

    public int countLanes()
    {
	return NUM_LANES;
    }

    /**
     * Returns the lane at the given position in this level.
     *
     * @param p a lane index
     */

    public Lane getLane(int p)
    {
	if (p < 0 || p >= NUM_LANES)
	    throw new IllegalArgumentException("Invalid lane index: " + p);

	return lanes[p];
    }

    /**
     * Updates this level and everything in it.
     *
     * @param t the time since the last update
     */

    public void update(double t)
    {
	for (int l = 0; l < NUM_LANES; l++)
	    lanes[l].update(t);
    }

    /**
     * Returns an iterator over this level's lanes.
     *
     * @return an iterator over this level's lanes
     */

    public Iterator laneIterator()
    {
	return new LaneIterator();
    }

    /**
     * An iterator over this level's lanes.
     */

    private class LaneIterator implements Iterator
    {
	/**
	 * The index of the lane this iterator is currently positioned before.
	 */

	private int index;

	/**
	 * Creates an iterator positioned before this level's first lane.
	 */

	public LaneIterator()
	{
	    index = 0;
	}

	/**
	 * Determines if this iterator has a next lane to iterate over.
	 */

	public boolean hasNext()
	{
	    return (index < NUM_LANES);
	}
	
	/**
	 * Returns the next lane this iterator iterates over and positions
	 * this iterator just after that lane.
	 */

	public Object next()
	{
	    if (!hasNext())
		throw new IllegalStateException("no next lane: " + index);

	    index++;

	    return lanes[index - 1];
	}

	/**
	 * Unsupported.
	 *
	 * @throws UnsupportedOperationException
	 */

	public void remove()
	{
	    throw new UnsupportedOperationException();
	}
    }
}

