import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.util.Date;

/* 

 Date: February 8th, 1996
 Version 1.0b1
 Updated:

 Encompassed all functionality in the same file. Previously
 I had a number of different object classes that did things
 like provide the behaviour of LEDs. But this seemed to make things
 a little difficult for people to install.

 Date: December 17th, 1995
 Version: 1.0a1
 Description:

 BigTime uses the BigLEDdigit class to display a rather
 large LED clock. BigLEDdigit is a metaphor of the 7 segment
 LED generally used in "old-fashioned" digital clocks.
 BigTime is based on the Clock class which basically
 implements a runnable thread that is executed every 1/4
 second, or so, in order to regularly update the appearance
 of the clock.

 Coder: John Criswick, Ottawa, criswick@conveyor.com
 Copyright (c) 1995, John R. Criswick. All rights reserved.
 */

public class BigTime extends Applet implements Runnable {

	int lastHour, lastMinute, lastSecond;
	Thread tickTock;
	int speed = 1000; // Update every 1 second
	int lastTenHour, lastTenMinute, lastTenSecond;
	Color LEDColour;
	Color BackGround;
	Color FrameColour;

	public String getAppletInfo() {
		return new String(
				"BigClock Ver 1.0b1 Feb.8.96 by John Criswick, Ottawa, criswick@conveyor.com");
	}

	public void init() {
		String param;
		lastHour = 0;
		lastMinute = 0;
		lastSecond = 0;
		lastTenHour = 0;
		lastTenMinute = 0;
		lastTenSecond = 0;
		param = getParameter("backcolor");
		BackGround = (param == null) ? Color.black : GetColourFromString(param);

		param = getParameter("ledcolor");
		LEDColour = (param == null) ? Color.green : GetColourFromString(param);

		param = getParameter("framecolor");
		FrameColour = (param == null) ? Color.green
				: GetColourFromString(param);

		resize(120, 36);
	}

	/*
	 * Given a string like "Green" or "green" this function returns
	 * 
	 * the actual Color value corresponding.
	 * 
	 */
	public Color GetColourFromString(String theParam) {
		if (theParam.equalsIgnoreCase("BLACK")) {
			return Color.black;
		} else if (theParam.equalsIgnoreCase("BLUE")) {
			return Color.blue;
		} else if (theParam.equalsIgnoreCase("CYAN")) {
			return Color.cyan;
		} else if (theParam.equalsIgnoreCase("DARKGRAY")) {
			return Color.darkGray;
		} else if (theParam.equalsIgnoreCase("GRAY")) {
			return Color.gray;
		} else if (theParam.equalsIgnoreCase("GREEN")) {
			return Color.green;
		} else if (theParam.equalsIgnoreCase("LIGHTGRAY")) {
			return Color.lightGray;
		} else if (theParam.equalsIgnoreCase("MAGENTA")) {
			return Color.magenta;
		} else if (theParam.equalsIgnoreCase("ORANGE")) {
			return Color.orange;
		} else if (theParam.equalsIgnoreCase("PINK")) {
			return Color.pink;
		} else if (theParam.equalsIgnoreCase("RED")) {
			return Color.red;
		} else if (theParam.equalsIgnoreCase("WHITE")) {
			return Color.white;
		} else if (theParam.equalsIgnoreCase("YELLOW")) {
			return Color.yellow;
		}
		return Color.black; // as a default
	}

	public void paint(Graphics g) {
		Date theDate = new Date();
		Color oldColour;
		oldColour = g.getColor();
		g.setColor(BackGround);
		g.fillRect(0, 0, bounds().width - 1, bounds().height - 1);
		g.setColor(FrameColour);
		g.drawRect(0, 0, bounds().width - 1, bounds().height - 1);
		DrawClock(g, theDate);
		g.setColor(oldColour);
	}

	/*
	 * Updates the clock appearance. This method overides the
	 * same method in the Clock class since we only want to draw
	 * the portion of the clock that changed (as oposed to redrawing
	 * the entire clock as the Clock method would do).
	 */
	public final synchronized void update(Graphics g) {
		int theHour, theMinute, theSecond;
		int theTenHour, theTenMinute, theTenSecond;
		Color oldColour;
		Date aDate = new Date();
		theSecond = aDate.getSeconds();
		theMinute = aDate.getMinutes();
		theHour = aDate.getHours();

		theTenHour = theHour / 10;
		theHour = theHour - theTenHour * 10;
		theTenMinute = theMinute / 10;

		theMinute = theMinute - theTenMinute * 10;
		theTenSecond = theSecond / 10;
		theSecond = theSecond - theTenSecond * 10;

		/*
		 * Here we only draw digits that need redrawing because they
		 * have changed since the last time through this code.
		 */
		oldColour = g.getColor();
		if (theSecond != lastSecond)
		{
			DrawSecond(theSecond);
			lastSecond = theSecond;
		}

		if (theTenSecond != lastTenSecond)
		{
			DrawTenSecond(theTenSecond);
			lastTenSecond = theTenSecond;
		}

		if (theMinute != lastMinute)
		{
			DrawMinute(theMinute);
			lastMinute = theMinute;
		}

		if (theTenMinute != lastTenMinute)
		{
			DrawTenMinute(theTenMinute);
			lastTenMinute = theTenMinute;
		}

		if (theHour != lastHour)
		{
			DrawHour(theHour);
			lastHour = theHour;
		}

		if (theTenHour != lastTenHour)
		{
			DrawTenHour(theTenHour);
			lastTenHour = theTenHour;
		}
		DrawColons();
		g.setColor(oldColour);
	}

	/*
	 * Draw everything in the clock. Typically called when we get
	 * a screen update. Not called when the time has changed.
	 */
	public synchronized void DrawClock(Graphics g, Date aDate) {
		int theHour, theMinute, theSecond;
		int theTenHour, theTenMinute, theTenSecond;
		theSecond = aDate.getSeconds();
		theMinute = aDate.getMinutes();
		theHour = aDate.getHours();
		theTenHour = theHour / 10;
		theHour = theHour - theTenHour * 10;
		theTenMinute = theMinute / 10;
		theMinute = theMinute - theTenMinute * 10;
		theTenSecond = theSecond / 10;
		theSecond = theSecond - theTenSecond * 10;
		/*
		 * Now draw every digit in the clock
		 */
		DrawSecond(theSecond);
		DrawTenSecond(theTenSecond);
		DrawMinute(theMinute);
		DrawTenMinute(theTenMinute);
		DrawHour(theHour);
		DrawTenHour(theTenHour);
		DrawColons();
	}

	/*
	 * Following set up size methods are used to draw each of the
	 * six digits in the clock. Each digit has its own draw method
	 * because we want to be able to draw only those parts of the
	 * clock that have changed.
	 */
	public synchronized void DrawSecond(int theValue) {
		DrawSevenSegments(getGraphics(), theValue, 99, 5);
	}

	public synchronized void DrawTenSecond(int theValue) {
		DrawSevenSegments(getGraphics(), theValue, 81, 5);
	}

	public synchronized void DrawMinute(int theValue) {
		DrawSevenSegments(getGraphics(), theValue, 61, 5);
	}

	public synchronized void DrawTenMinute(int theValue) {
		DrawSevenSegments(getGraphics(), theValue, 43, 5);
	}

	public synchronized void DrawHour(int theValue) {
		DrawSevenSegments(getGraphics(), theValue, 23, 5);
	}

	public synchronized void DrawTenHour(int theValue) {
		DrawSevenSegments(getGraphics(), theValue, 5, 5);
	}

	/*
	 * Draw the 2 pairs of colons between the hours and minutes digits
	 * and the minutes and seconds digits.
	 */
	public synchronized void DrawColons() {
		Graphics g = getGraphics();
		g.setColor(LEDColour);
		g.fillRect(39, 13, 2, 2);
		g.fillRect(39, 22, 2, 2);
		g.fillRect(77, 13, 2, 2);
		g.fillRect(77, 22, 2, 2);
	}

	private synchronized void DrawSevenSegments(Graphics g, int theValue,
			int x, int y) {
		// Need to implement a state machine to turn on the correct LED
		// segments to draw the number correctly.
		// This is a rather simple way to implement the state machine,
		// but it was quick to code. Its based on a switch statement for
		// each of ten possible digits.
		switch (theValue) {
		case 0:
			DrawSegment0On(g, x, y);
			DrawSegment1On(g, x, y);
			DrawSegment2On(g, x, y);
			DrawSegment3Off(g, x, y);
			DrawSegment4On(g, x, y);
			DrawSegment5On(g, x, y);
			DrawSegment6On(g, x, y);
			break;
		case 1:
			DrawSegment0Off(g, x, y);
			DrawSegment1Off(g, x, y);
			DrawSegment2On(g, x, y);
			DrawSegment3Off(g, x, y);
			DrawSegment4Off(g, x, y);
			DrawSegment5On(g, x, y);
			DrawSegment6Off(g, x, y);
			break;
		case 2:
			DrawSegment0On(g, x, y);
			DrawSegment1Off(g, x, y);
			DrawSegment2On(g, x, y);
			DrawSegment3On(g, x, y);
			DrawSegment4On(g, x, y);
			DrawSegment5Off(g, x, y);
			DrawSegment6On(g, x, y);
			break;
		case 3:
			DrawSegment0On(g, x, y);
			DrawSegment1Off(g, x, y);
			DrawSegment2On(g, x, y);
			DrawSegment3On(g, x, y);
			DrawSegment4Off(g, x, y);
			DrawSegment5On(g, x, y);
			DrawSegment6On(g, x, y);
			break;
		case 4:
			DrawSegment0Off(g, x, y);
			DrawSegment1On(g, x, y);
			DrawSegment2On(g, x, y);
			DrawSegment3On(g, x, y);
			DrawSegment4Off(g, x, y);
			DrawSegment5On(g, x, y);
			DrawSegment6Off(g, x, y);
			break;
		case 5:
			DrawSegment0On(g, x, y);
			DrawSegment1On(g, x, y);
			DrawSegment2Off(g, x, y);
			DrawSegment3On(g, x, y);
			DrawSegment4Off(g, x, y);
			DrawSegment5On(g, x, y);
			DrawSegment6On(g, x, y);
			break;
		case 6:
			DrawSegment0On(g, x, y);
			DrawSegment1On(g, x, y);
			DrawSegment2Off(g, x, y);
			DrawSegment3On(g, x, y);
			DrawSegment4On(g, x, y);
			DrawSegment5On(g, x, y);
			DrawSegment6On(g, x, y);
			break;
		case 7:
			DrawSegment0On(g, x, y);
			DrawSegment1Off(g, x, y);
			DrawSegment2On(g, x, y);
			DrawSegment3Off(g, x, y);
			DrawSegment4Off(g, x, y);
			DrawSegment5On(g, x, y);
			DrawSegment6Off(g, x, y);
			break;
		case 8:
			DrawSegment0On(g, x, y);
			DrawSegment1On(g, x, y);
			DrawSegment2On(g, x, y);
			DrawSegment3On(g, x, y);
			DrawSegment4On(g, x, y);
			DrawSegment5On(g, x, y);
			DrawSegment6On(g, x, y);
			break;
		case 9:
			DrawSegment0On(g, x, y);
			DrawSegment1On(g, x, y);
			DrawSegment2On(g, x, y);
			DrawSegment3On(g, x, y);
			DrawSegment4Off(g, x, y);
			DrawSegment5On(g, x, y);
			DrawSegment6Off(g, x, y);
			break;
		}
	}

	/*
	 * Segments 0, 3 and 6 are the horizontal line segments. Segments
	 * 1, 2, 4 and 5 are the vertical line segments.
	 */
	private synchronized void DrawSegment0On(Graphics g, int x, int y) {
		g.setColor(LEDColour);
		DrawHorizontalLine(g, x + 3, y + 1, 9);
	}

	private synchronized void DrawSegment0Off(Graphics g, int x, int y) {
		g.setColor(BackGround);
		DrawHorizontalLine(g, x + 3, y + 1, 9);
	}

	private synchronized void DrawSegment3On(Graphics g, int x, int y) {
		g.setColor(LEDColour);
		DrawHorizontalLine(g, x + 3, y + 12, 9);
	}

	private synchronized void DrawSegment3Off(Graphics g, int x, int y) {
		g.setColor(BackGround);
		DrawHorizontalLine(g, x + 3, y + 12, 9);
	}

	private synchronized void DrawSegment6On(Graphics g, int x, int y) {
		g.setColor(LEDColour);
		DrawHorizontalLine(g, x + 3, y + 23, 9);
	}

	private synchronized void DrawSegment6Off(Graphics g, int x, int y) {
		g.setColor(BackGround);
		DrawHorizontalLine(g, x + 3, y + 23, 9);
	}

	private synchronized void DrawSegment1On(Graphics g, int x, int y) {
		g.setColor(LEDColour);
		DrawVerticalLine(g, x + 1, y + 3, 9);
	}

	private synchronized void DrawSegment1Off(Graphics g, int x, int y) {
		g.setColor(BackGround);
		DrawVerticalLine(g, x + 1, y + 3, 9);
	}

	private synchronized void DrawSegment2On(Graphics g, int x, int y) {
		g.setColor(LEDColour);
		DrawVerticalLine(g, x + 12, y + 3, 9);
	}

	private synchronized void DrawSegment2Off(Graphics g, int x, int y) {
		g.setColor(BackGround);
		DrawVerticalLine(g, x + 12, y + 3, 9);
	}

	private synchronized void DrawSegment4On(Graphics g, int x, int y) {
		g.setColor(LEDColour);
		DrawVerticalLine(g, x + 1, y + 14, 9);
	}

	private synchronized void DrawSegment4Off(Graphics g, int x, int y) {
		g.setColor(BackGround);
		DrawVerticalLine(g, x + 1, y + 14, 9);
	}

	private synchronized void DrawSegment5On(Graphics g, int x, int y) {
		g.setColor(LEDColour);
		DrawVerticalLine(g, x + 12, y + 14, 9);
	}

	private synchronized void DrawSegment5Off(Graphics g, int x, int y) {
		g.setColor(BackGround);
		DrawVerticalLine(g, x + 12, y + 14, 9);
	}

	private synchronized void DrawHorizontalLine(Graphics g, int x, int y,
			int width) {
		g.drawLine(x + 1, y - 1, x + width - 3, y - 1);
		g.drawLine(x, y, x + width - 1, y);
		g.drawLine(x + 1, y + 1, x + width - 3, y + 1);
	}

	private synchronized void DrawVerticalLine(Graphics g, int x, int y,
			int height) {
		g.drawLine(x - 1, y + 1, x - 1, y + height - 3);
		g.drawLine(x, y, x, y + height - 1);
		g.drawLine(x + 1, y + 1, x + 1, y + height - 3);
	}

	/*
	 * Code to operate the thread
	 */
	public void start() {
		if (tickTock == null) {
			tickTock = new Thread(this);
			tickTock.start();
		}
	}

	public void stop() {
		if (tickTock != null) {
			tickTock.stop();
			tickTock = null;
		}
	}

	public void run() {
		while (true) {
			try {
				Thread.currentThread().sleep(speed);
			}
			catch (InterruptedException e) {
			}
			super.repaint();
		}
	}
}


