/**
 *	@(#)SwatchITime.java
 *	@version	0.5 01/09/99
 *	@version	1.0 01/10/99
 *	@author		Peter Theill	[peter@theill.com]
 *
 *	This Applet displays current time using Internet Time: a new 
 *	international timeformat invented by Swatch. The SwatchITime 
 *	applet automatically updates every second (or in userdefined
 *	intervals) to symbolize a running clock. Furthermore, you'll
 *	be able to use <code>SwatchITime</code> as a standard 'local
 *	time' clock.
 *
 *	Copyright(c) 1999 Peter Theill, ConquerWare
 *	All Rights Reserved.
 *
 */

import java.applet.Applet;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Event;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MediaTracker;
import java.util.Date;

public final class SwatchITime extends Applet implements Runnable
{

	final String VERSION = "1.0";
	
	Thread thread = null;
	
	private Image osImage;
	private Graphics osGraphics;
	private Dimension osSize;
	
	private Font m_font;
	private Image m_imgBackground;
	private FontMetrics fm = null;
	
	private boolean bUsingITime = true;
	private int m_updateInterval = 1000;
	private int m_userInterval;
	private Color m_color;
	
	public void init()
	{
		String paramFontName, paramFontSize, paramColor, paramImage;
	
		// Get parameters
		if ( (paramFontName = getParameter("font")) == null)
			paramFontName = "SansSerif";

		if ( (paramFontSize = getParameter("size")) == null)
		  paramFontSize = "8";
		  
		if ( (paramColor = getParameter("color")) == null)
		  paramColor = "#000000";
	
		if ( (paramImage = getParameter("image")) == null)
			paramImage = "";
	
		try
		{
			m_userInterval = Integer.parseInt(getParameter("interval"));
		}
		catch (NumberFormatException nfe)
		{
			m_userInterval = 1000;
		}
		
		m_updateInterval = m_userInterval;
		
		// parse colorstring from e.g. #FF0000 to (255, 0, 0)
		try
		{
			int r = Integer.parseInt(paramColor.substring(1, 3), 16);
			int g = Integer.parseInt(paramColor.substring(3, 5), 16);
			int b = Integer.parseInt(paramColor.substring(5, 7), 16);
			m_color = new Color(r, g, b);
		}
		catch(Exception e)
		{
			e.printStackTrace();
			m_color = new Color(0, 0, 0);
		}
		
		// which mode do we have to start in?
		if ( getParameter("localtime") != null)
			bUsingITime = false;
		
		m_font = new Font(paramFontName, Font.PLAIN, Integer.parseInt(paramFontSize));
		
		// Load image used as background
		m_imgBackground = getImage(getCodeBase(), paramImage);
		
		// Show user information
		this.showStatus("Please wait while backgroundimage is loading...");
		
		// Add to our image tracker
		MediaTracker tracker = new MediaTracker(this);
		tracker.addImage(m_imgBackground, 0);
		
		// Make sure you've downloaded all images before proceeding
		try { tracker.waitForAll(); }
		catch(InterruptedException e) { System.err.println("Err: Images not loaded"); }
		
		this.showStatus("Running SwatchItime v" + VERSION);
	
	} // --> public void init()
  

	/**
	 *	Starts thread
	 *
	 */
	public synchronized void start()
	{
	
		if (thread == null) {
		
			thread = new Thread(this);
			thread.start();
			System.out.println("Thread started");
		
		}
	
	} // --> public synchronized void start()


	/**
	 *	Stops thread
	 *
	 */
	public synchronized void stop()
	{
		
		thread.stop();
		thread = null;
		System.out.println("Thread stopped");
		
		// Release font  
		m_font = null;
		
		// Release image
		m_imgBackground.flush();
		m_imgBackground = null;
		
	} // --> public synchronized void stop()

  
	/**
	 *	Mainloop for thread. Paints canvas then goes to sleep
	 *	for a specified number of milliseconds. When it wakes
	 *	up (after specified time OR caused by a notify())
	 *	it just loops it all over again.
	 *
	 */
	public void run()
	{

		while (thread != null) {
			
			// paint canvas
			repaint();
			
			// go to sleep
			try { Thread.sleep(m_updateInterval); }
			catch (InterruptedException e) { ; }
	
		}

	} // --> public void run()


	/**
	 *	The "paint" method is called by AWT when it wants us to
	 *	display our current state on the screen.
	 *
	 */
	public synchronized void paint(Graphics g)
	{
	
		if (osImage != null)
			g.drawImage(osImage, 0, 0, this);
	
	} // --> public synchronized void paint(Graphics g)

  
	/**
	 *	Update canvas by drawing backgroundimage and text (either
	 *	Internet Time or Local Time) on a offscreen image. When
	 *	this is done, we update applet canvas by drawing offscreen
	 *	image to it.
	 *
	 */
	public synchronized void update(Graphics g)
	{
	
		// Get dimensions of appletcanvas
		Dimension d = size();

		if( (osImage == null) || (d.width != osSize.width) || (d.height != osSize.height) )
		{
			osImage = createImage(d.width, d.height);
			osSize = d;
			osGraphics = osImage.getGraphics();
			osGraphics.setFont(m_font);
			fm = getFontMetrics(m_font);
		}
		
		osGraphics.clearRect(0, 0, d.width, d.height);

		if (m_imgBackground != null)
			osGraphics.drawImage(m_imgBackground, 0, 0, this);
			
		String out;
		if (bUsingITime)
			out = "Internet Time @ " + calculateITime(new Date());
		else
			out = "Local Time is " + formatLocalTime(new Date());
			
		int x = (int)((d.width - fm.stringWidth(out)) / 2.0);
		int y = (int)((d.height - fm.getHeight()) / 2.0 + fm.getAscent());
			
		osGraphics.setColor(m_color);
		osGraphics.drawString(out, x, y);

		// update applet canvas
		g.drawImage(osImage, 0, 0, this);
		
	} // --> public synchronized void update(Graphics g)

  
	/**
	 *	Converts local time to Swatch Internet Time.
	 *
	 *	@param	t		Date object with local time
	 *	@return	String	ITime between 000 and 999
	 *
	 */
	public String calculateITime(Date t)
	{
		
		String ITime = "00" + (int)(( ( ( t.getHours() + (t.getMinutes()/60.0) + (t.getSeconds()/3600.0) ) ) / 24.0 ) * 1000);
		return (ITime.substring(ITime.length()-3));
		
	} // --> public int calculateITime(Date t)

	
	/**
	 *	Formats a Date object by appending it with '0' where
	 *	appropriate.
	 *
	 *	@param	t		Date object with local time
	 *	@return	String	Local time nicely formatted.
	 *
	 */
	public String formatLocalTime(Date t)
	{
		StringBuffer sb = new StringBuffer();
		int h, m, s;
		
		if ( (h = t.getHours()) < 10 )
			sb.append("0");
			
		sb.append(h + ":");
		
		if ((m = t.getMinutes()) < 10)
			sb.append("0");
			
		sb.append(m + ":");
		
		if ((s = t.getSeconds()) < 10)
			sb.append("0");
			
		sb.append(s);
		
		return (sb.toString());		
		
	} // --> public String formatLocalTime(Date t)


	/**
	 *  Switch between Internet Time and Local Time. We'll have to
	 *  change 'update interval' too, since Local Time changes every
	 *  second, while Internet Time only changes every every 86th
	 *  second.
	 *
	 */
	public boolean mouseDown(Event evt, int x, int y)
	{
		String mode;
  	
  		// change boolean mode
  		bUsingITime = !bUsingITime;

		/**
		 * Set Intervaltime (in ms). Interval specified by user
		 * is in seconds, though.
		 */
		if (bUsingITime)
		{
			m_updateInterval = m_userInterval;
			mode = "Internet Time";
		}
		else
		{
			m_updateInterval = 1000; // one (1) second
			mode = "Local Time";
		}

		repaint();
		thread.notify();
		
		this.showStatus("Running SwatchItime v" + VERSION + " in " + mode + " mode");

    	return true;
    	
	} // --> public boolean mouseDown(Event evt, int x, int y)
	
}