        // Uses double buffering in paint to avoid flicker.
import java.awt.*;
import java.util.*;

class Clock extends Canvas implements Runnable {
    public void update(Graphics g){
        // Don't clear first.
        paint(g);
    }

    public void paint(Graphics thisGraphics){
        // Get the bounds of this frame.
        Rectangle r = getBounds();
        // Make sure there is room.
        int diameter = r.width;
        if(r.height < diameter){
            diameter = r.height;
        }
        // Remove the borders from the diameter.
        diameter -= 2*border;
        if(diameter > minDiameter){
            Image image = createImage(r.width,r.height);
            Graphics g = image.getGraphics();
            centreX = r.width/2;
            centreY = r.height/2;
            radius = diameter/2;
            // Specify the top-left, width, and height.
            g.drawOval(centreX-radius,centreY-radius,diameter,diameter);
            // Put in the minute ticks.
            final int hourTickLength = 10;
            final int minuteTickLength = hourTickLength/2;
            ticks(g,minuteTickLength,minutesPerHour);
            // Put in the hour ticks.
            ticks(g,hourTickLength,numHours);
            Calendar now = new GregorianCalendar();
            final int hour = now.get(Calendar.HOUR_OF_DAY);
            final int minute = now.get(Calendar.MINUTE);
            final int second = now.get(Calendar.SECOND);

            // Draw the hands.
            drawHourHand(g,hour,minute);
            drawMinuteHand(g,minute,second);
            drawSecondHand(g,second);
            thisGraphics.drawImage(image,0,0,this);
        }
    }

    public void run(){
        final int sleepTime = 200;
        while(true){
            try{
                Thread.sleep(sleepTime);
                repaint();
                // Make sure we haven't been suspended.
                checkStatus();
            }
            catch(InterruptedException e){
            }
        }
    }

        // Check to see whether we are running or not.
    protected void checkStatus(){
        while(!getAnimationRunning()){
            try{
                wait();
            }
            catch(InterruptedException e){
            }
        }
    }

    public synchronized boolean getAnimationRunning(){
        return animationRunning;
    }

    public void setAnimationRunning(boolean r){
        synchronized(this){
            animationRunning = r;
            if(animationRunning){
                notify();
            }
            else{
                // This will suspend itself by polling via checkStatus.
            }
        }
    }

    private void ticks(Graphics g,int tickLength, int howMany){
        final double anglePerTick = 2*Math.PI/howMany;
        for(int tick = 1; tick <= howMany; tick++){
            double angle = tick*anglePerTick-angleCorrection;
            g.drawLine(
                    (int)(centreX+(radius-tickLength)*Math.cos(angle)),
                    (int)(centreY+(radius-tickLength)*Math.sin(angle)),
                    (int)(centreX+radius*Math.cos(angle)),
                    (int)(centreY+radius*Math.sin(angle)));
        }
    }

    private void drawHourHand(Graphics g,int hour, int minute){
        final double hourHandLength = 4*radius/8.0;
        final double hourAngle = hourHandAngle(hour,minute);
        g.drawLine(centreX,centreY,
                (int)(centreX+hourHandLength*Math.cos(hourAngle)),
                (int)(centreY+hourHandLength*Math.sin(hourAngle)));
    }

    private void drawMinuteHand(Graphics g,int minute, int second){
        final double minuteHandLength = 7*radius/8.0;
        final double minuteAngle = minuteHandAngle(minute,second);
        g.drawLine(centreX,centreY,
                (int)(centreX+minuteHandLength*Math.cos(minuteAngle)),
                (int)(centreY+minuteHandLength*Math.sin(minuteAngle)));
    }

    private void drawSecondHand(Graphics g,int second){
        final double secondHandLength = 5*radius/8.0;
        final double secondAngle = secondHandAngle(second);
        g.drawLine(centreX,centreY,
                (int)(centreX+secondHandLength*Math.cos(secondAngle)),
                (int)(centreY+secondHandLength*Math.sin(secondAngle)));
    }

    private double hourHandAngle(int hour,int minute){
        // Calculate the position of the hour mark.
        double basicAngle = hour*(2*Math.PI/numHours)-angleCorrection;
        // Now add a correction for the minutes past the hour.
        return basicAngle+minute*anglePerHour/minutesPerHour;
    }

    private double minuteHandAngle(int minute, int second){
        double basicAngle = minute*(2*Math.PI/minutesPerHour)-angleCorrection;
        // Now add a correction for the minutes past the hour.
        return basicAngle+second*anglePerMinute/secondsPerMinute;
    }

    private double secondHandAngle(int second){
        return second*(2*Math.PI/secondsPerMinute)-angleCorrection;
    }

    // Whether the animation is suspended or not.
    private boolean animationRunning = true;

    private int radius;
    private int centreX, centreY;

    // A small border around the edge.
    private final int border = 10;
    // Stipulate a minimum smallest dimension for the window.
    private final int minDiameter = 40;
    private static final int numHours = 12;
    private static final int minutesPerHour = 60;
    private static final int secondsPerMinute = 60;
    // Angle, in degrees for each time period.
    private static final double anglePerHour = 2*Math.PI/numHours;
    private static final double anglePerMinute = 2*Math.PI/minutesPerHour;
    private static final double anglePerSecond = 2*Math.PI/secondsPerMinute;
    // Because the Math package measures angles from the 3 o'clock position
    // it is necessary to correct by 90 degrees.
    private static final double angleCorrection = Math.PI/2;
}
