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

/**
 * A Calaveras Crossing game.  A game consists of a level (which contains lanes
 * that in turn contain obstacles and animals) together with the player's
 * frog.
 *
 * @author Jim Glenn
 * @version 0.1 10/7/2008
 */

public class CalaverasCrossingGame
{
    /**
     * Constants for scores
     */

    public static final int FORWARD_JUMP_SCORE = 10;
    public static final int FROG_HOME_SCORE = 50;
    public static final int REMAINING_TIME_SCORE = 10;
    public static final int ESCORT_SCORE = 200;
    public static final int FLY_EATEN_SCORE = 200;
    public static final int LEVEL_COMPLETE_SCORE = 1000;

    /**
     * The amount of time the player has to being a frog home.
     */

    public static final int FROG_TIME = 45;

    /**
     * The time to wait before starting a new frog.
     */

    public static final double NEW_FROG_WAIT = 3.0;

    /**
     * The default number of lives at the start of the game.
     */

    public static final int DEFAULT_LIVES = 3;

    /**
     * This game's current level.
     */

    private Level level;

    /**
     * The player's score.
     */

    private int score;

    /**
     * The time this game was last updated, in milliseconds.  -1 indicates
     * no update has taken place.
     */

    private long lastUpdate;

    /**
     * The number of frogs left in this game.
     */

    private int frogsLeft;

    /**
     * The number of frogs that have reached home during the current level.
     */

    private int frogsHome;

    /**
     * The player's frog.
     */

    private Frog playerFrog;

    public CalaverasCrossingGame()
    {
	level = null;
	lastUpdate = -1;
	playerFrog = new Frog(Color.GREEN.darker(), Lane.SCREEN_WIDTH / 2, 12, FROG_TIME);
	frogsLeft = DEFAULT_LIVES - 1;
	frogsHome = 0;
	score = 0;
    }

    /**
     * Starts the given level in this game.
     *
     * @param l a level
     */

    public void startLevel(Level l)
    {
	if (l == null)
	    throw new IllegalArgumentException("null level");

	level = l;
    }

    /**
     * Returns the player's frog from this game.
     */

    public Frog getPlayerFrog()
    {
	return playerFrog;
    }

    /**
     * Returns an iterator over the lanes in this game's current level.
     *
     * @return an iterator over the lanes in this game's current level
     */

    public Iterator laneIterator()
    {
	return level.laneIterator();
    }

    /**
     * Returns the given lane from this game's current level.
     *
     * @param index a lane index
     */

    public Lane getLane(int index)
    {
	return level.getLane(index);
    }

    /**
     * Updates this game.
     */

    public synchronized void update()
    {
	long t = System.currentTimeMillis();

	if (lastUpdate != -1 && level != null)
	    {
		// compute time since last update and notify everything in
		// this game

		double interval = (t - lastUpdate) / 1000.0;

		level.update(interval);

		playerFrog.update(interval, this);

		if (!playerFrog.isVisible()
		    && frogsHome < 5
		    && playerFrog.getStateTime() >= NEW_FROG_WAIT)
		    {
			playerFrog = new Frog(Color.GREEN.darker(), Lane.SCREEN_WIDTH / 2, 12, FROG_TIME);
		    }
		else if (playerFrog.isDead()
			 && playerFrog.getStateTime() > NEW_FROG_WAIT
			 && frogsLeft > 0)
		    {
			playerFrog = new Frog(Color.GREEN.darker(), Lane.SCREEN_WIDTH / 2, 12, FROG_TIME);
			frogsLeft--;
		    }			
	    }

	lastUpdate = t;
    }

    /**
     * Adds the given amount to the player's score for this game.
     *
     * @param s the amount to add
     */

    public void addScore(int s)
    {
	score += s;
    }

    /**
     * Updates the game statistics to reflect a forward jump.
     */

    public void forwardJump()
    {
	addScore(FORWARD_JUMP_SCORE);
    }

    /**
     * Updates game statistics to reflect the fact that a frog was brought
     * home.
     */

    public void frogHome()
    {
	frogsHome++;
	addScore(FROG_HOME_SCORE);

	addScore((FROG_TIME - (int)(playerFrog.getLifeTime())) * REMAINING_TIME_SCORE);

	if (frogsHome == 5)
	    {
		addScore(LEVEL_COMPLETE_SCORE);
	    }
    }

    /**
     * Returns the number of lives left in this game.
     *
     * @return the number of lives left in this game
     */

    public int countLives()
    {
	return frogsLeft;
    }

    /**
     * Returns the score for the game.
     *
     * @return the score for the game
     */

    public int getScore()
    {
	return score;
    }
}

