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

/**
 * A painter for Calaveras Crossing games.
 *
 * @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 CalaverasCrossingPainter
{
    /**
     * The game this painter paints.
     */

    private CalaverasCrossingGame game;

    /**
     * Creates a painter to paint the given game.
     *
     * @param g a CalaverasCrossing game
     */

    public CalaverasCrossingPainter(CalaverasCrossingGame g)
    {
	game = g;
    }

    /**
     * Paints this painter's game on the given graphics context.
     *
     * @param g the graphics context to paint in
     * @param w the width of the area to paint in
     * @param h the height of the area to paint in
     */

    public void paint(Graphics g, int w, int h)
    {
	// compute the height in pixels of each lane

	int laneHeight = h / Level.NUM_LANES;

	// paint all the lanes
	
	Iterator i = game.laneIterator();
	int laneIndex = 0;
	while (i.hasNext())
	    {
		Lane l = (Lane)(i.next());

		Graphics laneClip = g.create(0,
					     laneIndex * laneHeight,
					     w,
					     laneHeight);

		paintLane(laneClip, w, laneHeight, l);
		laneIndex++;
	    }

	// draw score, time, and remaining frogs

	g.setColor(Color.WHITE);
	g.drawString("SCORE: " + game.getScore() + " TIME: " + (int)(game.getPlayerFrog().getRemainingTime()) + " LIVES: " + game.countLives(), 0, 13 * laneHeight - 2);

	// paint the player's frog

	Frog frog = game.getPlayerFrog();

	// does the clipping region not get rotated along with the
	// coordinate system or is something else wrong here?

	Graphics frogClip;
	if (frog.getDirection() == Frog.UP || frog.getDirection() == Frog.DOWN)
	    {
		frogClip = g.create((int)(w * frog.getX() / Lane.SCREEN_WIDTH),
				    (int)(frog.getY() * laneHeight),
				    (int)(w * (frog.getX() + frog.getWidth()) / Lane.SCREEN_WIDTH),
				    (int)(frog.getHeight() * laneHeight));
	    }
	else
	    {
		frogClip = g.create((int)(w * frog.getX() / Lane.SCREEN_WIDTH),
				    (int)(frog.getY() * laneHeight),
				    (int)(frog.getHeight() * laneHeight),
				    (int)(w * (frog.getX() + frog.getWidth()) / Lane.SCREEN_WIDTH));
	    }

	Graphics2D g2 = (Graphics2D)frogClip;

	if (frog.getDirection() == Frog.LEFT)
	    {
		g2.rotate(-Math.PI / 2);
		g2.translate(-(int)(w * frog.getWidth() / Lane.SCREEN_WIDTH) + 1, 0);
	    }
	else if (frog.getDirection() == Frog.DOWN)
	    {
		g2.rotate(Math.PI);
		g2.translate(-(int)(w * frog.getWidth()/ Lane.SCREEN_WIDTH) + 1, -(int)(frog.getHeight() * laneHeight));
	    }
	else if (frog.getDirection() == Frog.RIGHT)
	    {
		g2.rotate(Math.PI / 2);
		g2.translate(0, -(int)(frog.getHeight() * laneHeight));
	    }

	paintFrog(g2, (int)(w * frog.getWidth() / Lane.SCREEN_WIDTH), (int)(frog.getHeight() * laneHeight), frog);
    }

    /**
     * Paints the given lane on the given graphics context.
     *
     * @param g the graphics context to paint in
     * @param w the width of the area to paint in
     * @param h the height of the area to paint in
     * @param l the lane to paint
     */

    private void paintLane(Graphics g, int w, int h, Lane l)
    {
	// paint the background

	switch (l.getType())
	    {
	    case Lane.ROAD:
		g.setColor(Color.GRAY);
		break;

	    case Lane.GRASS:
		g.setColor(Color.GREEN);
		break;

	    case Lane.RIVER:
		g.setColor(Color.BLUE);
		break;
	    }

	g.fillRect(0, 0, w, h);

	// if you're paying attention to my comments and want to paint some
	// lane markers, this is the place to do it -- the upper left corner
	// of the lane we're currently working on is (0, 0) and the lower
	// right corner is (w - 1, h - 1); some thin white rectangles along
	// the top edge might do the trick

	// paint the obstacles in the lane

	Iterator i = l.obstacleIterator();
	while (i.hasNext())
	    {
		Pair p = (Pair)(i.next());
		Obstacle o = (Obstacle)(p.getFirst());
		double pos = ((Double)(p.getSecond())).doubleValue();

		int obsX = (int)(w * pos / Lane.SCREEN_WIDTH);
		int obsW = (int)(w * o.getWidth() / Lane.SCREEN_WIDTH);

		Graphics2D obstacleClip = (Graphics2D)(g.create(obsX, 0, obsW, h));

		if (l.getVelocity() < 0)
		    {
			/*
			obstacleClip.rotate(Math.PI);
			obstacleClip.translate(-(int)(w * o.getWidth() / Lane.SCREEN_WIDTH), -h);
			*/

			obstacleClip.scale(-1.0, 1.0);
			obstacleClip.translate(-(int)(w * o.getWidth() / Lane.SCREEN_WIDTH), 0);
		    }

		paintObstacle(obstacleClip, obsW, h, o);
	    }
    }
    
    /**
     * Paints the given obstacle.
     *
     * @param g the graphics context to paint in
     * @param w the width to paint in
     * @param h the height to paint in
     * @param o the obstacle to paint
     */

    public void paintObstacle(Graphics g, int w, int h, Obstacle o)
    {
	if (o instanceof Truck)
	    paintTruck(g, w, h, (Truck)o);
	else if (o instanceof Tractor)
	    paintTractor(g, w, h, (Tractor)o);
	else if (o instanceof Car)
	    paintCar(g, w, h, (Car)o);
	else if (o instanceof Racecar)
	    paintRacecar(g, w, h, (Racecar)o);
	else if (o instanceof Log)
	    paintLog(g, w, h, (Log)o);
	else if (o instanceof Turtles)
	    paintTurtles(g, w, h, (Turtles)o);
	else if (o instanceof Home)
	    paintHome(g, w, h, (Home)o);
	else
	    {
		g.setColor(Color.WHITE);
		g.fillRect(0, 0, w, h);
	    }
    }

    /**
     * Paints the given truck.
     * @param g the graphics context to paint in
     * @param w the width to paint in
     * @param h the height to paint in
     * @param t the truck to paint
     */

    public void paintTruck(Graphics g, int w, int h, Truck t)
    {
	paintVehicle(g, w, h, t);
    }

    /**
     * Paints the given truck.
     * @param g the graphics context to paint in
     * @param w the width to paint in
     * @param h the height to paint in
     * @param t the truck to paint
     */

    public void paintTractor(Graphics g, int w, int h, Tractor t)
    {
	paintVehicle(g, w, h, t);
    }

    /**
     * Paints the given car.
     * @param g the graphics context to paint in
     * @param w the width to paint in
     * @param h the height to paint in
     * @param c the car to paint
     */

    public void paintCar(Graphics g, int w, int h, Car c)
    {
	paintVehicle(g, w, h, c);
    }
    
    /**
     * Paints the given truck.
     * @param g the graphics context to paint in
     * @param w the width to paint in
     * @param h the height to paint in
     * @param c the car to paint
     */

    public void paintRacecar(Graphics g, int w, int h, Racecar c)
    {
	paintVehicle(g, w, h, c);
    }

    /**
     * Paints the given vehicle.
     * @param g the graphics context to paint in
     * @param w the width to paint in
     * @param h the height to paint in
     * @param v the vehicle to paint
     */

    public void paintVehicle(Graphics g, int w, int h, Vehicle v)
    {
        g.setColor(Color.BLUE.darker());
	g.fillRect(1, 1, w - 2, h - 2);
    }

    /**
     * Paints the given log.
     * @param g the graphics context to paint in
     * @param w the width to paint in
     * @param h the height to paint in
     * @param l the log to paint
     */

    public void paintLog(Graphics g, int w, int h, Log l)
    {
	g.setColor(Color.BROWN);
	g.fillRect(0, 0, w, h);
    }

    /**
     * Paints the given group of turtles.
     * @param g the graphics context to paint in
     * @param w the width to paint in
     * @param h the height to paint in
     * @param t the turtles to paint
     */

    public void paintTurtles(Graphics g, int w, int h, Turtles t)
    {
	int turtleWidth = w / t.getCount();

	for (int i = 0; i < t.getCount(); i++)
	    {
		Graphics turtleClip = g.create(turtleWidth * i,
					       0,
					       turtleWidth,
					       h);

		paintTurtle(turtleClip, turtleWidth, h, t);
	    }
    }

    /**
     * Paints a single turtle within a group
     * @param g the graphics context to paint in
     * @param w the width to paint in
     * @param h the height to paint in
     * @param t the group of turtles the one to paint is in
     */

    public void paintTurtle(Graphics g, int w, int h, Turtles t)
    {
	g.setColor(Color.RED);
	g.fillOval(0, 0, w, h);
    }

    /**
     * Paints a frog home.
     * @param g the graphics context to paint in
     * @param w the width to paint in
     * @param h the height to paint in
     * @param home the home to paint
     */

    public void paintHome(Graphics g, int w, int h, Home home)
    {
	g.setColor(Color.BLUE);
	g.fillRect(0, 0, w, h);
    }

    /**
     * Paints a frog.
     * @param g the graphics context to paint in
     * @param w the width to paint in
     * @param h the height to paint in
     * @param frog the frog to paint
     */

    public void paintFrog(Graphics g, int w, int h, Frog frog)
    {
	g.setColor(frog.getColor());
	g.fillOval(0, 0, w, h);
    }
}

