import java.awt.*;
import javax.swing.*;
import java.util.*;

        // Track ships moving and plot them on the canvas.
        // A ship added to the ocean will be observed by a dedicated
        // ShipTracker object. The complete set of trackers is kept
        // in a LinkedList.
class Ocean extends JComponent {
    public Ocean(){
        final int width = 325, height = 250;
        setPreferredSize(new Dimension(width,height));
    }

        // Add a vessel to the sea.
    public void add(Ship ship){
        // Create an associated tracker to
        // track the ship's movements.
        ShipTracker tracker = new ShipTracker(ship,this);
        getSea().add(tracker);
        repaint();
    }

        // Draw the current state of the sea.
    public void paintComponent(Graphics g){
        final Dimension size = getSize();
        g.clearRect(0,0,size.width,size.height);

        // Iterate over the trackers.
        for(Iterator ships = getSea().iterator(); ships.hasNext(); ){
            ShipTracker tracker = (ShipTracker) ships.next();

            // Ask each tracker to give us the path of its ship.
            Iterator details = tracker.getShipTrack();
            if(details.hasNext()){
                // Draw the path in red.
                g.setColor(Color.red);
                // Join up the points on the path.
                CourseAndPosition lastDetails =
                                (CourseAndPosition) details.next();
                IntPoint lastPoint = mapPositionToPoint(lastDetails.getPosition());
                int lastXPix = lastPoint.getX(), lastYPix = lastPoint.getY();
                while(details.hasNext()){
                    CourseAndPosition where = (CourseAndPosition) details.next();
                    IntPoint nowPoint = mapPositionToPoint(where.getPosition());
                    int nowXPix = nowPoint.getX(), nowYPix = nowPoint.getY();

                    g.drawLine(lastXPix,lastYPix,nowXPix,nowYPix);

                    // Set up for next time around.
                    lastDetails = where;
                    lastXPix = nowXPix;
                    lastYPix = nowYPix;
                }

                // Mark where it is now as a circle in a different colour.
                final int width = 5, height = 5;
                g.setColor(Color.black);
                // Centre the circle about the position.
                final double xPos = lastXPix,
                             yPos = lastYPix;
                g.drawArc((int) Math.rint(xPos-width/2),
                          (int) Math.rint(yPos-height/2),
                          width,height,0,360);
                // Draw a line indicating the ship's direction.
                double course = Math.toRadians(lastDetails.getCourse());
                g.drawLine((int) Math.rint(xPos),(int) Math.rint(yPos),
                           (int) Math.rint(xPos+width*Math.cos(course)),
                           (int) Math.rint(yPos+width*Math.sin(course)));
            }
        }
    }

        // Is p within the drawable area?
    public boolean inBounds(Position position){
        IntPoint p = mapPositionToPoint(position);
        double x = p.getX(), y = p.getY();

        if((x < 0) || (y < 0)){
            return false;
        }
        else{
            Dimension size = getSize();
            return (x < size.width) && (y < size.height);
        }
    }

        // An integer (x,y) position.
    protected class IntPoint {
        public IntPoint(int x, int y){
            this.x = x;
            this.y = y;
        }

        public int getX(){
            return x;
        }

        public int getY(){
            return y;
        }

        private final int x, y;
    }

        // Turn a ship position into a pixel point.
    protected IntPoint mapPositionToPoint(Position p){
        // Scaling to make movement more obvious.
        final int xScale = 2, yScale = 2;
        return new IntPoint((int) Math.rint(p.getX()*xScale),
                         (int) Math.rint(p.getY()*yScale));
    }

    private LinkedList getSea(){
        return sea;
    }

    // Define a container for the ShipTrackers;
    private final LinkedList sea = new LinkedList();
}
