/**
	Clock - Yet another clock Applet in Java. 
	
	@author Martin Sullivan. 

	This was written as a refresh/revision exercise. The author
	writes:

	I, like not a few people around me have waded through books
	styled "Power Java for the Very Stupid Made Easy with a CD" or
	thereabouts. Satisfied that I knew enough Java to get by, there
	was then a Hiatus where no useful Java was written. Since some
	time has now elapsed, I wrote this to refresh my memory and to
	catch up on newer Java language features. As a result the style
	may be a bit slanted toward the gratuitous use of such
	features.  Some of these features were actually stripped out
	when it made things just too clunky, at one time it was two
	Classes separated by an Interface, just for the hell of it.
	Initial attempts at compilation were marked by the Java
	Compiler whinging about "Depricated features". So the classes
	and methods were rewritten to use pure Java 1.1. This means
	that the are a number of lossages with various browsers which
	may be running this program and may not be too uptodate with
	their Java.

@version $Id: Clock.java,v 1.2 2001/03/07 14:49:10 sullivan Exp $

*/

/*
     Clock - A Clock JAVA Applet by Martin Sullivan. Copyright (C) 1999
     ZOIS Ltd.

     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published
     by the Free Software Foundation (version 1).

     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     General Public License for more details.

     A full copy of the GNU General Public License can be found at
     http://www.gnu.org/copyleft/gpl.html or can be obtained by writing
     to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
     MA 02139, USA.

     Author: Martin Sullivan.
     ZOIS Ltd., Stag House, 55 Kirkgate, Cockermouth CA13 9PH
     Email: sullivan@zois.co.uk

*/
/*
$Log: Clock.java,v $
Revision 1.2  2001/03/07 14:49:10  sullivan
Added GPL to allow publication on web-site. First published as a Class
only mid-1999.

*/

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

/** Clock - Yet another clock Aplet in Java. */
public class Clock extends Applet implements Runnable { 

    static final int POINTS = 12;

    Thread clockThread = null;

    Mark mark = new Mark ();

    SecondHand secondHand = new SecondHand ();
    MinuteHand minuteHand = new MinuteHand ();
    HourHand hourHand = new HourHand (); 

    boolean timeSet = false;

    Calendar c = Calendar.getInstance ();

    public void start () {

    	clockThread = new Thread (this);
	clockThread.start ();
    } // start

    public void stop () {

	clockThread.stop ();
	clockThread = null;
    } // stop

    static double asrads (int degrees) {

	return (((double) degrees / (double) 180.0) * (double) Math.PI);
				/* Degrees to the machine preferred
				   Radians, Note the static declaration. */

    } // asrads

    public void run () {

	while (clockThread != null) {

	    c = Calendar.getInstance ();
				/* Lossages here, The doc says c should
				   be the current time for the default
				   Time Zone and Daylight Savings Time
				   (DST). However it seems to be a
				   random value on some systems and on
				   others the DST is ignored.       */


	    secondHand.setHand (asrads (c.get (Calendar.SECOND) * 360 / 60));
    	    minuteHand.setHand (asrads (
    		(c.get (Calendar.MINUTE) * 360 / 60) +
    		(c.get (Calendar.SECOND) * 360 / 60 / 60))); 
	    hourHand.setHand (asrads (
	    	(c.get (Calendar.HOUR) * 360 / 12) +
    		(c.get (Calendar.MINUTE) * 360 / 60 / 12) +
    		(c.get (Calendar.SECOND) * 360 / 60 / 60 / 12))); 

				/* We work in Degrees for simplicity. */
		
	    timeSet = true;

	    repaint ();

	    try {
		clockThread.sleep (1000);
	    } // try
	    catch (InterruptedException e) {
	    } // catch
	} // for 
    } // run

    void drawFace (Graphics g, int maxsize, Point centre) {


	mark.drawMarks (g, maxsize, centre, POINTS);

    } // drawFace

    public void paint (Graphics g) {

	int maxsize;
	int widthOffset;
	int heightOffset;
	Point centre = new Point ();
				/* Point is a Lossage. It gives really
				   old Java implementions grief. */

				/* We use a radial coordintes system,
				   which means we figure out a cenral
				   point and the maximum size of the
				   circle.	*/

	maxsize = (getSize().width < getSize().height ? 
	    getSize().width : getSize().height);

	widthOffset = (getSize().width < maxsize ? 
	    0 : getSize().width - maxsize) / 2;
	heightOffset = (getSize().height < maxsize ? 
	    0 : getSize().height - maxsize) / 2;

	centre.setLocation ((maxsize / 2) + widthOffset, 
	    (maxsize / 2) + heightOffset);

				/* Draw the Clock. A double buffering
				   method could have been used but
				   found to be unnecessary.   */

	g.clearRect (0, 0, getSize().width, getSize().height);

	drawFace (g, maxsize, centre);

	if (timeSet) {
    	    secondHand.drawHand (g, maxsize, centre);
	    minuteHand.drawHand (g, maxsize, centre); 
	    hourHand.drawHand (g, maxsize, centre);
	} // if

    } // paint

    public String getAppletInfo () {

	return ("Yet another Java clock, this one by Martin Sullivan.");
    } // getAppletInfo


/* 
	Classes in this program are actually Inner Classes, a feature
	new to Java 1.1. Things like this should be familier to Pascal
	programmers where functions and procedures could be nested.

*/

    class Mark extends RadialLine {

	Mark () {

	    super (1.0, 0.9);
	} // Mark.Mark

	void drawMarks (Graphics g, int maxsize, Point centre, int no) {

	    int ix;

	    for (ix = 0; ix < no; ix++) {
	        this.setRadialLine (asrads (ix * 360 / no));
    	        this.drawRadialLine (g, maxsize, centre);
	    } // for
	} // drawMarks

    } // Mark

/* 
	Classes from here to class drawRadialLine are a bit over the
	top with polymorphism and inheritence.
	
*/

    class HourHand extends Hand {

	HourHand () {

	    super (0.5);

	} // HourHand::HourHand
    } // HourHand

    class MinuteHand extends Hand {

	MinuteHand () {

	    super (0.70);
	} // MinuteHand::MinuteHand
    } // MinuteHand

    class SecondHand extends Hand {

	SecondHand () {

	    super (0.85, 0.75);
	} // SecondHand::SecondHand
    } // SecondHand

    class Hand extends RadialLine {

	Hand (double length) {
		super (length);
	} // Hand.Hand

	Hand (double length, double arcStart) {
		super (length, arcStart);
	} // Hand.Hand

	void setHand (double vector) {

	    setRadialLine (vector);
	} // setHand

	void drawHand (Graphics g, int max, Point centre) {

	    drawRadialLine (g, max, centre);

	} // drawRadialLine

    } // Hand

    class RadialLine extends Applet {

	private double vector;
	private Point start = new Point ();
	private Point end = new Point ();
	private double length;
	private double arcStart = 0.05;

	RadialLine () {

	    this.length = 1.0;

	} // RadialLine.RadialLine

	RadialLine (double length) {
	    
	    this.length = length;
	} // RadialLine.RadialLine

	RadialLine (double length, double arcStart) {

	    this.length = length;
	    this.arcStart = arcStart;

	} // RadialLine.RadialLine

	void setRadialLine (double vector) {

				/* This bit of maths is to sort out the
				   co-ordinate system so that vector =
				   0 means straight up (12h00)       */

	    this.vector = vector - (Math.PI / (double) 2); 
	} // setRadialLine

	void drawRadialLine (Graphics g, int max, Point centre) {

	    double halfMax;
	    double yvec; 
	    double xvec;

	    halfMax = (double) (max / 2);

	    xvec = Math.cos (vector) * halfMax;
	    yvec = Math.sin (vector) * halfMax;

	    start.setLocation (
		(int) (xvec * arcStart) + centre.x,
		(int) (yvec * arcStart) + centre.y);

	    end.setLocation (
		(int) (xvec * length) + centre.x,
		(int) (yvec * length) + centre.y);


	    g.drawLine (start.x, start.y, end.x, end.y);

	} // draw

    } // RadialLine

} // Clock

