
import java.awt.*;
import java.text.*;
import java.awt.event.*;
import java.util.Date;
import java.util.Calendar;
import java.applet.*;

public class ClockFrame extends Frame implements
		ComponentListener,
		WindowListener, Runnable
{
	Thread worker = null;
	Image offscreenImg = null;
	Graphics offscreen = null;
	private int w = 0, h = 0;
	private boolean closed = false;
	int old_s = 0;
	int s = 0;

	ClockMainAndApplet theApplet;

	public void update (Graphics g)
	{
		paint (g);
	}

	private void drawTick (Graphics offscreen, int x, int y, double theta, int start, int end)
	{
		int x1 = (int) (x + start * Math.cos (Math.PI/2 - theta));
		int y1 = (int) (y - start * Math.sin (Math.PI/2 - theta));
		int x2 = (int) (x + end * Math.cos (Math.PI/2 - theta));
		int y2 = (int) (y - end * Math.sin (Math.PI/2 - theta));
		
		offscreen.setColor (Color.black);
		offscreen.drawLine (x1,y1,x2,y2);
	}

	private void drawNumber (Graphics offscreen, int x, int y, double theta, int pos, int num)
	{
		int x3 = (int) (x + pos * Math.cos (Math.PI/2 - theta));
		int y3 = (int) (y - pos * Math.sin (Math.PI/2 - theta));

		offscreen.setColor (Color.black);
		offscreen.drawString (""+num, x3 ,y3);
	}

	public void run ()
	{
		Thread t = Thread.currentThread ();
		while (worker == t)
		{
			Calendar cl = Calendar.getInstance ();
			int ms = cl.get (Calendar.SECOND);
//(cl.get (Calendar.SECOND) + 1) * 1000 + cl.get (Calendar.MILLISECOND) - 500;

			if (ms != old_s && theApplet != null)
			{
				old_s = ms;
				theApplet.playTick ();
			}

			repaint ();

			try
			{
				Thread.sleep (25);
			}
			catch (InterruptedException e) {}
		}
	}

	ClockFrame (ClockMainAndApplet a)
	{
		super ("Peter's Clock");
		theApplet = a;

		if (worker == null)
		{
			worker = new Thread (this);
			worker.start ();
		}
		addComponentListener (this);
		addWindowListener (this);
		setVisible (true); // setVisible must come before setSize
		setSize (400, 400); // indirectly calls makeOffscreen through componentResized
	}

	private void makeOffscreen ()
	{
		w = Math.max (1, getSize ().width);
		h = Math.max (1, getSize ().height);
		s = Math.min (w, h);

		offscreenImg = createImage (w, h); // if setVisible(true) is not called first createImage returns null !
		offscreen = offscreenImg.getGraphics ();

		repaint ();
	}

	private int scale (int v)
	{
		return v * s / 175;
	}

	public void destroy ()
	{
		setVisible (false);
		removeWindowListener (this);
		removeComponentListener (this);
		dispose ();
		cleanupOffscreen ();
		theApplet = null;
		worker = null;
	}

	public boolean is_not_closed () { return !closed; }

	public void paint (Graphics g)
	{
		Calendar c = Calendar.getInstance (); //Call to get a new time
		int lastSecond = c.get (Calendar.SECOND);
		int cx = w / 2;
		int cy = (h - scale (18)) / 2;

		Date date = new Date (); //Call to get a new time and date

		//Second hand's position
		double rs = c.get(Calendar.SECOND) * 2.0 * Math.PI / 60.0;
		
		//Minute hand's position
		double rm = (c.get(Calendar.MINUTE) + c.get (Calendar.SECOND) / 60.0) * 2.0 * Math.PI / 60.0;
		
		//Hour hand's position
		double rh = (c.get(Calendar.HOUR) + c.get (Calendar.MINUTE) / 60.0) * 2.0 * Math.PI / 12.0;

		if (offscreen != null)
		{
			FontMetrics fm = offscreen.getFontMetrics ();
			offscreen.setFont (new Font ("Arial", Font.BOLD, scale (12)));
			offscreen.setColor (Color.white);
			offscreen.fillRect (0,0,w,h);
			offscreen.setColor (Color.black);
			drawTick (offscreen, cx, cy, rs, 0, scale (50)); //draw the second hand
			drawTick (offscreen, cx, cy, rm, 0, scale (40)); //draw the minute hand
			drawTick (offscreen, cx, cy, rh, 0, scale (25)); //draw the hour hand
			offscreen.drawOval (cx - scale (55), cy - scale (55), scale (110), scale (110));
			offscreen.drawOval (cx - scale (58), cy - scale (58), scale (116), scale (116));
			offscreen.fillOval (cx - scale (3), cy - scale (3), scale (6), scale (6));

			for (int i = 0; i < 60; i++)
			{
				//Draw the little second markers around the clock face's
				//edge

				drawTick (offscreen, cx, cy, i * 2.0 * Math.PI / 60.0, scale (53), scale (55));
			}

			for (int j = 0; j < 12; j++)
			{
				//Draw the larger hour markers and then draw the numbers

				drawTick (offscreen, cx, cy, j * 2.0 * Math.PI / 12.0, scale (50), scale (55));
				drawNumber (offscreen, cx - scale (3), cy + scale (4), (j+1) * 2.0 * Math.PI / 12.0, scale (43), j+1);
			}

			//Draw the date-time string at the bottom of the applet
			offscreen.drawString (date.toString (), (w - fm.stringWidth (date.toString ())) / 2, h - fm.getHeight () - 15);

			g.drawImage (offscreenImg, 0,0, this);
		}


	}
	
	private void cleanupOffscreen ()
	{
		if (offscreen != null)
			offscreen.dispose ();
		offscreen = null;
		offscreenImg = null;
	}
	
	public void componentResized (ComponentEvent evt)
	{
		cleanupOffscreen ();
		makeOffscreen ();
	}
	
	public void componentHidden (ComponentEvent evt) {}
	public void componentMoved (ComponentEvent evt)	{}
	public void componentShown (ComponentEvent evt) {}

	public void windowClosing (WindowEvent evt)
	{
		closed = true;
		setVisible (false);
		worker = null;
	}
	
	public void windowOpened (WindowEvent evt) {}
	public void windowClosed (WindowEvent evt) {}
	public void windowDeiconified (WindowEvent evt) {}	
	public void windowActivated (WindowEvent evt) {}
	public void windowIconified (WindowEvent evt) {}
	public void windowDeactivated (WindowEvent evt) {}
	
};

