//___________________________________________________________________________________
//___________________________________________________________________________________
//
//	This file contains JavaScript functions to write countdown timers at various 
//	places on an HTML page.  Each timer is independent of the others and can be 
//	counting down to a separate target date/time.

//  This script is loosely based on one written by Peter Gehrig, but it has been 
//  enhanced by Randall Ingermanson.

// CREDITS:
// Dynamic Countdown Player
// by Peter Gehrig
// Copyright (c) 2004 Peter Gehrig and Urs Dudli. All rights reserved.
// Permission given to use the script provided that this notice remains as is.
// Additional scripts can be found at http://www.24fun.com
// info@24fun.com
// 2/28/2004

// IMPORTANT:
// If you add this script to a script-library or a script-archive
// you have to insert a link to http://www.24fun.com 
// right into the webpage where the script will be displayed.

// Revised by Randy Ingermanson, 3/4/2006
// Revisions are copyright 2006, Randall Ingermanson.  All rights reserved.
// Permission given to use the script provided that this notice remains as is.
// Home web page:  http://www.ingermanson.com

//___________________________________________________________________________________
//___________________________________________________________________________________


//__Countdown index. Since any page can have multiple countdown timers, each 
//__instance on the page is indexed by a 0-based index.  The ID of the element 
//__is "countdownTimer_0", "countdownTimer_1", etc.
var iCountdown = -1;

//__Global data for the various timers.
var countdownID = new Array();
var futureDate = new Array();
var formatArray = new Array();
var expiredArray = new Array();

//__Set the update interval to subsecond resolution and convert to msec.
var updateIntervalSeconds = 0.5;
var updateIntervalMsec = 1000*updateIntervalSeconds;

//__Determine which browser we're using.
var browserInfo = navigator.userAgent;
var ns4 = document.layers;
var opera = browserInfo.match(/Opera/);
var ie4 = !document.getElementById && document.all && !opera;
var ie5 = document.getElementById && document.all && !opera;
var ns6 = document.getElementById && !document.all && !opera;

/**
 * Initialize another timer and write it to the document.
 * @param newCountdownID The ID of the new countdown timer ID.
 * This should be a string that is unique to this element on the HTML page.
 * As an example, use "countdownTimer_0", "countdownTimer_1", etc.
 * @param newFutureDate The Date object to which this timer is 
 * counting down.
 * @param newFormat A string that specifies the display format.  
 * Currently there are two allowed formats:
 * "dhms" means to display it as "_ days __h __m __s"
 * "dayClock" means to display it as "_ days __:__:__"
 * @param newExpiredMessage The message to display if the timer has expired. 
 * Default is "Expired".
 */
function writeCountdownTimer(newCountdownID, newFutureDate, newFormat, newExpiredMessage) 
{
	 if (ns4 || ie4 || ie5 || ns6 || opera) 
	 {	
	 	//__Increment my internal list of countdown timers.
		iCountdown++;
		
		//__Save the countdown timer ID.
		countdownID[iCountdown] = newCountdownID;
		futureDate[iCountdown] = newFutureDate;
		formatArray[iCountdown] = newFormat;
		expiredArray[iCountdown] = newExpiredMessage;
		
		//__Write the countdown timer element to the page with a note that it is 
		//__not working. The first time the timer fires, the note will be replaced
		//__with the actual time to the expiration time.
		document.write("<span id='" + newCountdownID + "' style='position:relative'>Not Working</span>");
	 }
}	//__End writeCountdownTimer().

/**
 * Begins the countdown for all timers.
 * This only needs to be called once.
 * Typically, it will be called from the onload function of a page 
 * that uses a countdown timer.
 */
function doCountdown() 
{ 
	//__Update all the timers.
	updateTimers();
	
	//__Call myself after the appropriate update interval.
	setTimeout("doCountdown()", updateIntervalMsec);
}	//__End doCountdown().

/**
 * Returns the next instance of a date in either this month or the next one,
 * depending on whether the date has already passed in this one.
 * @return Returns the new Date object.
 * @param day The day of the desired month. This is 1-based, and should be between 
 * 1 and 31 inclusive.
 * @param hour The hour of the day. This should be between 0 and 23 inclusive.
 * @param minute The minute of the hour. This should be between 0 and 59 inclusive.
 * @param second The second of the minute. This should be between 0 and 59 inclusive.
 * @param timeZone The number of hours east of UTC. For example, California is 8 
 * hours east of the UTC meridian, so timeZone would be 8.
 */
function getNextDateInMonth(day, hour, minute, second, timeZone)
{
	//__Get the current date.
	var todaysDate = new Date();
	
	//__Extract the year, month, and day.
	var thisYear = todaysDate.getUTCFullYear();
	var thisMonth = todaysDate.getUTCMonth();
	var thisDay = todaysDate.getUTCDate();
	
	//__Construct the date as if it were for this month.
	var result = new Date(todaysDate.getTime());
	result.setUTCDate(day);
	result.setUTCHours(hour + timeZone);
	result.setUTCMinutes(minute);
	result.setUTCSeconds(second);
	result.setUTCMilliseconds(0);
	
	//__See if the date has already passed.
	//__If so, then set the date for next month.
	var timeDifference = result.getTime() - todaysDate.getTime();
	if (timeDifference < 0) 
		result.setUTCMonth(thisMonth + 1);
	
	//__Return the result.
	return result;
}	//__End getNextDateInMonth().

/**
 * Returns the next instance of a specified weekday in either this month or 
 * the next one, depending on whether the date has already passed in this one.
 * As an example, you can specify the next "first Tuesday of the month".
 * @return Returns the new Date object.
 * @param weekDay The day of the week that we're looking for. This is 0-based, 
 * so Sunday is 0 and Saturday is 6.
 * @param weekNum The number of the week. If you want the first Tuesday, this should 
 * be 1. If you want the 4th Thursday, then this should be 4.
 * @param hour The hour of the day. This should be between 0 and 23 inclusive.
 * @param minute The minute of the hour. This should be between 0 and 59 inclusive.
 * @param second The second of the minute. This should be between 0 and 59 inclusive.
 * @param timeZone The number of hours east of UTC. For example, California is 8 
 * hours east of the UTC meridian, so timeZone would be 8.
 */
function getNextIthWeekdayInMonth(weekDay, weekNum, hour, minute, second, timeZone)
{
	//__Get the current date.
	var todaysDate = new Date();
	
	//__Extract the year, month, and day.
	var thisYear = todaysDate.getUTCFullYear();
	var thisMonth = todaysDate.getUTCMonth();
	var thisDay = todaysDate.getUTCDate();
	
	//__Construct the date as if it were for this month.
	var result = getIthWeekday(thisYear, thisMonth, weekDay, weekNum, hour, minute, second, timeZone);
		
	//__See if the date has already passed.
	//__If so, then set the date for next month.
	var timeDifference = result.getTime() - todaysDate.getTime();
	if (timeDifference < 0) 
		result = getIthWeekday(thisYear, thisMonth + 1, weekDay, weekNum, hour, minute, second, timeZone);
	
	//__Return the result.
	return result;
}	//__End getNextIthWeekdayInMonth().

/**
 * Returns a specified weekday in a given month.
 * As an example, you can specify the "first Tuesday of November".
 * @return Returns the new Date object.
 * @param year The full 4-digit year required.  (Example, 2005).
 * @param month The month required.
 * @param weekDay The day of the week that we're looking for. This is 0-based, 
 * so Sunday is 0 and Saturday is 6.
 * @param weekNum The number of the week. If you want the first Tuesday, this should 
 * be 1. If you want the 4th Thursday, then this should be 4.
 * @param hour The hour of the day. This should be between 0 and 23 inclusive.
 * @param minute The minute of the hour. This should be between 0 and 59 inclusive.
 * @param second The second of the minute. This should be between 0 and 59 inclusive.
 * @param timeZone The number of hours east of UTC. For example, California is 8 
 * hours east of the UTC meridian, so timeZone would be 8.
 */
function getIthWeekday(year, month, weekDay, weekNum, hour, minute, second, timeZone)
{
	//__Construct the date for the first day of the month.
	var result = new Date();
	result.setUTCFullYear(year);
	result.setUTCMonth(month);
	result.setUTCDate(1);
	result.setUTCHours(hour + timeZone);
	result.setUTCMinutes(minute);
	result.setUTCSeconds(second);
	result.setUTCMilliseconds(0);
	
	//__See what day of the week it is in the timezone requested.
	var dayOfWeek = result.getDay();
	
	//__Add in the number of days required to get to the desired week day
	//__and the desired week.
	var correctionDays = (weekDay - dayOfWeek + 7)%7 + (weekNum - 1)*7;
	var newTime = result.getTime() + correctionDays*24*60*60*1000;
	result.setTime(newTime);
	
	//__Return the result.
	return result;
}	//__End getIthWeekday().

/**
 * Updates all the timer displays.
 */
function updateTimers()
{
	//__Get the current time.
	var nowDate = new Date()
	
	//__Loop through all the timers displayed on the page.
	for (i = 0; i <= countdownID.length - 1; i++) 
	{
		//__Get the displayString for this timer.
		var thisDisplayString = computeDisplayString(futureDate[i], nowDate, formatArray[i], expiredArray[i]);
		
		//__Get the next countdown ID.
		var thisID = countdownID[i];
		if (!thisID) continue;
		
		//__Get the clock element for this timer.
		var thisClock = (ie4 ? eval(thisID) : document.getElementById(thisID));
			
		//__Set its content.
		if (thisClock)
			thisClock.innerHTML = thisDisplayString;
	}	//__End for-loop over all timers.
}	//__End updateTimers().

/**
 * Computes the string to be displayed in a given timer, based on the 
 * future date and the current date.
 * @return Returns a string to be displayed.
 * If the future date has been passed, then the string "Expired" is returned.
 * @param thisFutureDate The date to which to count down.
 * @param nowDate The current date.
 * @param thisFormat The format in which to display the result.
 * @param thisExpiredMessage The message to display if the timer has expired.
 * If this is null, then "Expired" is displayed.
 *
 */
function computeDisplayString(thisFutureDate, nowDate, thisFormat, thisExpiredMessage)
{
	//__Get the time difference in seconds, minutes, hours, days.
	var differenceMsec = thisFutureDate.getTime() - nowDate.getTime();
	if (differenceMsec < 0)
	{
		if (thisExpiredMessage != null)
			return thisExpiredMessage;
		else
			return "Expired";
	}
		
	var differenceSeconds = Math.floor(differenceMsec/1000);
	var differenceMinutes = Math.floor(differenceSeconds/60);
	var differenceHours = Math.floor(differenceMinutes/60);
	var differenceDays = Math.floor(differenceHours/24);
	
	//__Mod them out to get the results for display.
	var resultDays = differenceDays;
	var resultHours = differenceHours%24;
	var resultMinutes = differenceMinutes%60;
	var resultSeconds = differenceSeconds%60;
	
	//__Init the result.
	var resultString = "";
	
	if (resultDays > 0)
	{
		//__Add the days.
		resultString += resultDays; 
		if (resultDays > 1) 
			resultString += " days ";
		else 
			resultString += " day ";
	}
		
	//__Add the hours.
	if (resultHours < 10) 
		resultString += "0";
	resultString += resultHours;
	if (thisFormat == "dhms")
		resultString += "h ";
	else if (thisFormat == "dayClock")
		resultString += ":";
	else 
		resultString += " ";
	
	//__Add the minutes.
	if (resultMinutes < 10) 
		resultString += "0";
	resultString += resultMinutes;
	if (thisFormat == "dhms")
		resultString += "m ";
	else if (thisFormat == "dayClock")
		resultString += ":";
	else 
		resultString += " ";
	
	//__Add the seconds.
	if (resultSeconds < 10) 
		resultString += "0";
	resultString += resultSeconds;	
	if (thisFormat == "dhms")
		resultString += "s";	

	//__Return the result.
	return resultString;
}	//__End computeDisplayString().


