/** 
* Countdown Clock 
* 
* @version 1.0 May 15, 1996
* @author Michael Hartman 
*
* Copyright (C) 1996 Michael Hartman <hartmms@eng.auburn.edu>
* 
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Based on CTC5 Countdown Clock 
* http://www.ncsc.dni.us/ctc5/java/Countdown.html
* by Tom Carlson (tcarlson@ncsc.dni.us).   
*
* Description: This counter will countdown to the specified time if it is 
* 		in the future and countup if it is in thw past. It is just 
*		like the countdown clock NASA uses.
*
* Usage:  You must provide a Year, Month, and Day to the targer date.
*	   You can optionally specify an hour (in military), minute and 
*	   second as well: they default to 0. For those of you in the 
*	   U.S.A, you can specify if the target time is during daylight 
*	   savings time: otherwise it defaults to regular time.
*
*      On top of this, you can specify what the applet will display
*  	at the bottom of your viewer and where it will point the 
*	browser to go when the user clicks on the applet.
*	(I use it to provide a link to the source file.)
*
* There is also an option to specify a font to use. I have included only
* one font set with this, called lcdb0. You can create your own fonts, but
* make sure they are the correct size.
* colon image: 21 x 9 (in pixels)
* all other images: 21 x 16 (in pixels)
*
* example: the counter will count to Dec 13, 1996 at 1:00pm: 
* My graduation date from college :)
* <pre>
* &ltapplet code="countdown.class" width=203 height=21&gt
* &ltparam name=text value="Click on me to view my source"%gt
* &ltparam name=font value="lcdb0"&gt
* &ltparam name=dest value="countdown.java"&gt
* &ltparam name=year value=96&gt
* &ltparam name=month value=12&gt
* &ltparam name=day value=13&gt
* &ltparam name=hour value=13&gt
* &lt/applet&gt
* </pre>
* Drawbacks - 	When the rollover occurs, the counter skips a second.
* 		This problem seems to be a result of the way Java 
* 		uses its multithreading capabilities. Please email
* 		me if you can help fix this.  
*
*/
import java.util.*;
import java.awt.*;
import java.applet.*;
import java.net.*;

public class countdown extends Applet implements Runnable {
  private URL dest;
  private String saying, font;
  private Thread timer = null;
  private MediaTracker tracker = null;

  private int lastsec = 0;
  private int totalSec = 0;
  private int t_hrs, t_mins, t_secs, t_month, t_day, t_year ,t_daylight, tz_offset;
  private int s, rDays, rHours, rMinutes, rSecs;
  private boolean tminus; 

  // Array of digit images 0 - 9
  private Image[]	digit_image = new Image[10];	
  
  // Other various images needed 
  private Image	buffer_image, colon_image, frame_image, tminus_image, 
			tplus_image, blank_image;

  private Graphics	gc;

  // Height of the digits (and colons)
  private int		digit_height = 21;	
  private int		digit_width = 16;	// Width of the digits
  private int		colon_width = 9;	// Width of the colons

  // Width of the frame = (2 * 0) + (6 * digit_width) + (2 * colon_width)
  private int		applet_width = 203;        
  
  // Height of the frame = (2 * 0) + digit_height
  private int		applet_height = 42; 	

  // Array of digit and colon starting
  private int[]	image_start_x = new int[14];	
	
					  
public void init() {

	String param;

	tracker = new MediaTracker (this);

	try {
		saying = getParameter("text");
		param = getParameter("dest");
		font = getParameter("font");
		try {
			dest = new URL (getDocumentBase(), param);
		} catch(MalformedURLException mal) {
			System.out.println("Malformed URL: Check Applet tag. ");
		}



// Get parameters from html <apple> tag

		param = getParameter ("YEAR");		
		t_year = Integer.parseInt (param);

		param = getParameter ("MONTH");
		t_month = Integer.parseInt (param);

		param = getParameter ("DAY");
		t_day = Integer.parseInt (param);

		param = getParameter ("HOUR");
		if (param != null) {
			t_hrs = Integer.parseInt (param);
		} else {
			t_hrs = 0;
		}
	

		param = getParameter ("MINUTE");
		if (param != null) {
			t_mins = Integer.parseInt (param);
		} else {
			t_mins = 0;
		}

		param = getParameter ("SECOND");
		if (param != null) {
			t_secs = Integer.parseInt (param);
		} else {
			t_secs = 0;
		}
	

		param = getParameter ("TIMEZONE");
		if (param != null)
			tz_offset = Integer.parseInt (param);
		else
			tz_offset = 0;
			
		param = getParameter ("DAYLIGHT");
		if (param != null) {
			t_daylight = Integer.parseInt (param);
		} else {
			t_daylight = 0;
		}
	} catch (Exception e) {
		return;
	}
		
	// Location of first image is the 0 of the frame if there is any
     	image_start_x[0] = 0;		

	// Location of digit 1 is the width of tminus = digit_width
	image_start_x[1] = digit_width;

	image_start_x[2] = digit_width * 2;

	// Calculate other digit locations based on time format 4:2:2:2
	for (int i = 2; i < 14; i++) {			
	    if ( (i == 6) || (i == 9) || (i == 12)) {
		image_start_x[i] = image_start_x[i - 1] + colon_width;
	    } else {
 	  	image_start_x[i] = image_start_x[i - 1] + digit_width;
	    }
	}

	// Load the digit images
	for (int i = 0; i < 10; i++) {
		digit_image[i] = getImage(getCodeBase(),  i + font + ".gif");
		tracker.addImage(digit_image[i], 0);
	}

	// Load the colon image
	colon_image = getImage(getCodeBase(), "c_" + font + ".gif");
	tracker.addImage(colon_image, 1);


	// Load the tminus and plus images
	tminus_image = getImage(getCodeBase(), "tm_" + font + ".gif");
	tracker.addImage(tminus_image, 2);
	tplus_image = getImage(getCodeBase(), "tp_" + font + ".gif");
	tracker.addImage(tplus_image, 3);
	blank_image = getImage(getCodeBase(), "b_" + font + ".gif");
	tracker.addImage(blank_image, 4);

	System.out.println("Developed by: Michael Hartman");
	System.out.println("hartmms@eng.auburn.edu");

	try {
		buffer_image = createImage(applet_width, applet_height);
		gc = buffer_image.getGraphics();
	} catch (Exception e) {
		System.out.println("Error in displaying graphics\n");
		gc = null;
	}

}

 
public void paintDigClk(Graphics g) {
 
  int	s, lastsec = 0, x, tSec, i = 0;	

  Date dat = new Date();
  s = dat.getSeconds();

  // If the counter has rolled over, set tminus to false.
  if ( totalSec == -1 ) 
	tminus = false;

  // If tminus is true, display the tminus image. Otherwise display the 
  // tplus image.

  if ( tminus ) 
	g.drawImage( tminus_image, image_start_x[i++], 0, this);
  else
	g.drawImage( tplus_image, image_start_x[i++], 0, this);

  // Only update if 1 second has transpired since the last update.
  if (s != lastsec) {

	totalSec--;
	
	tSec = Math.abs(totalSec);
	rDays = (int) Math.floor (tSec / (24.0*60*60) );
    	rHours = (int) Math.floor((tSec % (24*60*60)) / 3600.0);
    	rMinutes = (int) Math.floor( (tSec % 3600) /60.0);
    	rSecs = tSec % 60; 

	if ( (rDays/1000) != 0 ) {
	        g.drawImage(digit_image[rDays / 1000], image_start_x[i++], 0, this);
	} else {
		g.drawImage(blank_image, image_start_x[i++], 0, this);
	}
  	g.drawImage(digit_image[(rDays % 1000) / 100], image_start_x[i++], 0, this);
	g.drawImage(digit_image[(rDays % 100) / 10], image_start_x[i++], 0, this);
	g.drawImage(digit_image[rDays % 10], image_start_x[i++], 0, this);
	g.drawImage(colon_image, image_start_x[i++], 0, this);
	g.drawImage(digit_image[rHours / 10], image_start_x[i++], 0, this);
	g.drawImage(digit_image[rHours % 10], image_start_x[i++], 0, this);
	g.drawImage(colon_image, image_start_x[i++], 0, this);
	g.drawImage(digit_image[rMinutes / 10], image_start_x[i++], 0, this);
	g.drawImage(digit_image[rMinutes % 10], image_start_x[i++], 0, this);
	g.drawImage(colon_image, image_start_x[i++], 0, this);
	g.drawImage(digit_image[rSecs / 10], image_start_x[i++], 0, this);
	g.drawImage(digit_image[rSecs % 10], image_start_x[i++], 0, this);

	lastsec=s;
  }

}

public void start() {

  // The array below is used to keep track of the # of days in a month
  // it is also used to keep track of the leap year 
  // if the year is 1996 and the month is 2, then 1996 mod 4 = 0
  // so days_in_month[0][2-1] = 29. 29 is used for the math.

  int days_in_month[][] = { {31,29,31,30,31,30,31,31,30,31,30,31},
                       	{31,28,31,30,31,30,31,31,30,31,30,31},
		       	{31,28,31,30,31,30,31,31,30,31,30,31},
			{31,28,31,30,31,30,31,31,30,31,30,31}};

  // The array below is used to keep track of the leap year.
  // if the year is 1996, then 1996 mod 4 = 0, and 366 would be used
  // in the computation.
 
  // Leap years are evenly mod(ed) 

  int days_in_year[] = {366,365,365,365};

  int hrs, mins, secs, month, day, year, daylight;
  int i, factor;
  int base_today = 0;
  int base_target = 0;
  int this_tz_offset = 0;
  Date today = new Date();

  secs = today.getSeconds();
  mins = today.getMinutes();
  hrs = today.getHours();

  month = today.getMonth();
  month++;
  day = today.getDate();
  year = today.getYear();
  this_tz_offset = today.getTimezoneOffset();
  year += 1900;
  daylight = 0;

  // calculate number of seconds from 00:00:00 Jan 1, 1990 until target 
  
  factor = 24 * 60 * 60;
  base_target += t_secs;
  base_target += t_mins * 60;
  base_target += t_hrs * 60 * 60;
  base_target += (t_day-1) * factor;
  for (i=1; i<t_month; i++){
	base_target += days_in_month[t_year % 4][i-1] * factor;
  }
  base_target += tz_offset * 60;


  for (i=1970; i<t_year; i++){
	base_target += days_in_year[i % 4] * factor;
  }
  if (t_daylight == 1){base_target -= 3600;}

  // calculate number of seconds from 00:00:00 Jan 1, 1990 until today 

  base_today += secs;
  base_today += mins * 60;
  base_today += hrs * 60 * 60;
  base_today += (day-1) * factor;
  for (i=1; i<month; i++){
	base_today += days_in_month[year % 4][i-1] * factor;
  }

  for (i=1970; i<year; i++){
	base_today += days_in_year[i % 4] * factor;
  }
  if (daylight == 1){base_today -= 3600;}
  base_today += tz_offset * 60;


   // Subtract the two to get the counter value.
   
   totalSec  = base_target - base_today;
   
   if (tz_offset != 0)
       totalSec += this_tz_offset * 60;

    if (totalSec <= 0) { 
	tminus = false;
    } else 
	tminus = true; 

    rDays = totalSec/(24*60*60);
    rHours = (totalSec % (24*60*60)) / 3600;
    rMinutes = (totalSec % 3600) / 60;
    rSecs = totalSec % 60;


  if(timer == null) {
      timer = new Thread(this);
      timer.start();
    }
}

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

public void run() {
  try { 
	tracker.waitForID(0);
	tracker.waitForID(1);
	tracker.waitForID(2);
	tracker.waitForID(3);
  } catch (InterruptedException e) {
	return;
  }

  while (timer != null) {
    try {
	Thread.sleep(1000);
    } catch (InterruptedException e) {}
    repaint();
  }
  timer = null;
}

public void update(Graphics g) {
		if (buffer_image != null) {
			paintDigClk(gc);
			g.drawImage(buffer_image, 0, 0, this);
		} else {
			g.clearRect(0, 0, applet_width, applet_height);
			paintDigClk(g);
		}
}

public boolean mouseEnter(Event evt, int x, int y) {

	showStatus(saying);
	return(true);
}

public boolean mouseUp(Event evt, int x, int y) {

	getAppletContext().showDocument(dest);
	return(true);

}


}
