<!--
// © Copyright Symmetric Designs 2006/2007/2008
// All Rights Reserved

// Minimum number of milliseconds for year, month, day, etc.  It's a
// minimum because the year and month are variable.
var ONE_SECOND = 1000;
var ONE_MINUTE =  60*ONE_SECOND;
var ONE_HOUR   =  60*ONE_MINUTE;
var ONE_DAY    =  24*ONE_HOUR;
var ONE_MONTH  =  28*ONE_DAY;
var ONE_YEAR   = 364*ONE_DAY;

// Define date types
var DAY_OF_YEAR		= 1;	// 197th      (or date selection)                              of 2008 (or all years)
var DAY_OF_MONTH	= 2;	// 6th        (or date selection) of July (or month selection) of 2008 (or all years)
var DAY_OF_WEEK		= 3;	// 2nd Monday (or week selection) of July (or month selection) of 2008 (or all years)

var WAITING=1;
var ACTIVE=2;
var COMPLETE=3;

function daysUntilDate(dateTimeString, lengthString, periodString, now, name, endDateFlag, singleDayFlag)
	{
	this.DEBUG  = 0;
	this.DEBUG2 = 0;
	this.DEBUG3 = 0;
	this.DEBUG_ALERTS  = 0;
	this.DEBUG_ALERTS2 = 0;

	if (this.DEBUG3) document.title = "Init:";
	if (this.DEBUG3) document.title = document.title + " D:" + dateTimeString;
	if (this.DEBUG3) document.title = document.title + " L:" + lengthString;
	if (this.DEBUG3) document.title = document.title + " P:" + periodString;

	// Save arguments
	this.dateTimeString = dateTimeString;
	this.lengthString   = lengthString;
	this.periodString   = periodString;
	this.now = now;
	this.name = name;
	this.endDateFlag = endDateFlag;
	this.singleDayFlag = singleDayFlag;
	this.gmtOffset = getLocalTimeOffset(now);

	if (this.DEBUG_ALERTS) alert (this.name + ":creating new daysUntilDate object");

	// Define methods
	this.calc = calc;
	this.calcDeltas = calcDeltas;

	this.getDayName2 = getDayName2;
	this.getMonthName3 = getMonthName3;
	this.getDateString2 = getDateString2;

	this.getDeltaDaysText    = getDeltaDaysText;
	this.getDeltaHoursText   = getDeltaHoursText;
	this.getDeltaMinutesText = getDeltaMinutesText;
	this.getDeltaSecondsText = getDeltaSecondsText;

	this.setDate = setDate;
	this.addIntervalsToDate = addIntervalsToDate;

	// Create working Date objects to define the beginning and end of the event
	this.workingStart = new Date();
	this.workingEnd = new Date();

	// Parse the input strings
	this.dateTime = new daysUntilDateTime(dateTimeString, true,  this.name);
	this.length   = new daysUntilDateTime(lengthString,   false, this.name);
	this.period   = new daysUntilDateTime(periodString,   false, this.name);

	if (this.DEBUG2) document.title = document.title + " S:" + getDateStringXX(this.workingStart);
	if (this.DEBUG2) document.title = document.title + " E:" + getDateStringXX(this.workingEnd);

	// Initialize the workingStart date to dateString and calculate workingEnd
	this.setDate(this.workingStart, this.dateTime);
	//+++ this won't work for non-gregorian dates.  We need to get rid of this
	//    calculation and pass in workingEnd from the php code, instead of the length +++++
	//		We can also get rid of the period (from the php code) since it's not used any more
	this.addIntervalsToDate(this.workingEnd, this.workingStart, this.length, 1);

	if (this.DEBUG2) document.title = document.title + " S::" + getDateStringXX(this.workingStart);
	if (this.DEBUG2) document.title = document.title + " E::" + getDateStringXX(this.workingEnd);

	// If the period is all zero, the event is not periodic.
	this.periodic = true;
	if (	(this.period.year    == 0) &&
			(this.period.month   == 0) &&
			(this.period.date    == 0) &&
			(this.period.hours   == 0) &&
			(this.period.minutes == 0) &&
			(this.period.seconds == 0))
		this.periodic = false;

	this.periodsAdded   = 0;
	this.eventsOccured  = 0;
	this.checkPast      = false;

	// Perform the first time calculation
	this.calc(this.now);
	}

function calc(now)
	{
	if (this.DEBUG_ALERTS) alert (this.name + ":calc() function in daysUntilDate object")
	this.now = now;
	if (this.DEBUG3) document.title = "calc:";
	if (this.DEBUG) document.title = document.title + " N" + getDateStringXX(this.now);
	if (this.DEBUG3) document.title = document.title + " S1" + getDateStringXX(this.workingStart);
	if (this.DEBUG) document.title = document.title + " E1" + getDateStringXX(this.workingEnd);

	//  All events either occured in the past, are currently active,
	//  or will occur in the future.  This is indicated below by
	//  S0 (past), S1 (active), and S2 (future).
	//	-----------------------------N--------------------------- now
	//	---S0xxE------------------------------------------------- past
	//	-----------S0xxE----------------------------------------- past
	//	-------------------S0xxE--------------------------------- past
	//	---------------------------S1xxE------------------------- active
	//	-----------------------------------S2xxE----------------- future
	//	-------------------------------------------S2xxE--------- future
	//	---lllll---lllll---lllll---lllll---lllll---lllll--------- length
	//	---pppppppp--------pppppppp--------pppppppp-------------- period
	//	-----------pppppppp--------pppppppp--------pppppppp------ period
	//
	//  In the above diagram S0 indicates the defined event date, lllll
	//  is the length of each event, and pppppppp is the period
	//  of the events.
	//  In a series of events, the current time (now) will always fall between
	//  two events (S1 & S2).  It will also fall either between the start and
	//  end of the first event (active), or between the end of the first and the start
	//  of the second event (waiting).

	if (this.singleDayFlag)
		{
		//	Check if the event will occur in the FUTURE (N < S)
		if (this.now < this.workingStart)
			{
			if (this.DEBUG3) document.title = document.title + ":future";

			// Measure the amount of time until the event starts and
			// set the event type to waiting.
			if (this.endDateFlag)
				this.timeDelta = this.workingEnd.getTime()-this.now.getTime();
			else
				this.timeDelta = this.workingStart.getTime()-this.now.getTime();

			if (this.DEBUG) document.title = document.title + ":waiting";
			this.type = WAITING;
			}

		//	The event occurred in the PAST (S <= N)
		else
			{
			if (this.DEBUG3) document.title = document.title + ":past";

			// Check if the event is COMPLETE (E <= N)
			if (this.now >= this.workingEnd)
				{
				// The event is not PERIODIC ++++ this is an old comment...nothing is periodic anymore???
				if (this.DEBUG3) document.title = document.title + "X";

				// Measure the amount of time since event completed and
				// set the event type to complete.
//+++ removed - one sec before midnight there is one second left, at MN it's 0 sec, 1 sec after
//              it's 1 sec since day started AND 1 sec since previous day ended (they happen
//              at the same instant)
//				//  -ONE_SECOND is because workingEnd
//				// is one second past the actual end (if length is 1 day it is
//				// date +1 day or the first second of following day)
				if (this.DEBUG) document.title = document.title + ":complete";
				if (this.endDateFlag)
					this.timeDelta = this.now.getTime() - this.workingEnd.getTime();
//					this.timeDelta = this.now.getTime() - (this.workingEnd.getTime() - ONE_SECOND);
				else
					this.timeDelta = this.now.getTime() - this.workingStart.getTime();
//					this.timeDelta = this.now.getTime() - (this.workingStart.getTime() - ONE_SECOND);
				this.type = COMPLETE;
				}

			// The event is still ACTIVE (S <= N < E)
			else
				{
				// Measure the amount of time until event completes and
				// set the event type to active.
				if (this.endDateFlag)
					this.timeDelta = this.workingEnd.getTime()-this.now.getTime();
				else
					this.timeDelta = this.now.getTime() - this.workingStart.getTime();
				if (this.DEBUG) document.title = document.title + ":active";
				this.type = ACTIVE;
				}
			}
		}

	// NOT singleDayFlag
	else
		{
		//	Check if the event will occur in the FUTURE (N < S)
		if (this.now < this.workingStart)
			{
			if (this.DEBUG3) document.title = document.title + ":future";
	
			// Measure the amount of time until the event starts and
			// set the event type to waiting.
			if (this.endDateFlag)
				this.timeDelta = this.workingEnd.getTime()-this.now.getTime();
			else
				this.timeDelta = this.workingStart.getTime()-this.now.getTime();
	
			if (this.DEBUG) document.title = document.title + ":waiting";
			this.type = WAITING;
			}

		//	The event occurred in the PAST (S <= N)
		else
			{
			if (this.DEBUG3) document.title = document.title + ":past";

			// Check if the event is COMPLETE (E <= N)
			if (this.now >= this.workingEnd)
				{
				// The event is not PERIODIC ++++ this is an old comment...nothing is periodic anymore???
				if (this.DEBUG3) document.title = document.title + "X";

				// Measure the amount of time since event completed and
				// set the event type to complete.
				if (this.endDateFlag)
					this.timeDelta = this.now.getTime() - this.workingEnd.getTime();
				else
					this.timeDelta = this.now.getTime() - this.workingStart.getTime();

				if (this.DEBUG) document.title = document.title + ":complete";
				this.type = COMPLETE;
				}

			// The event is still ACTIVE (S <= N < E)
			else
				{
				// Measure the amount of time until start or end of event and
				// set the event type to active.
				if (this.endDateFlag)
					this.timeDelta = this.workingEnd.getTime()-this.now.getTime();
				else
					this.timeDelta = this.now.getTime() - this.workingStart.getTime();

				if (this.DEBUG) document.title = document.title + ":active";
				this.type = ACTIVE;
				}
			}
		}

	if (this.DEBUG3) document.title = document.title + ":S2" + getDateStringXX(this.workingStart);
	if (this.DEBUG) document.title = document.title + ":E" + getDateStringXX(this.workingEnd);
	if (this.DEBUG) document.title = document.title + ":T" + this.type;
	if (this.DEBUG) document.title = document.title + ":D" + this.timeDelta;
	}

// +++ need some comments about ONE_HOUR vs. SECONDS_PER_HOUR as resolution (see calling code using SECONDS_PER_HOUR, etc.)
function calcDeltas(resolution, count)
	{
	// Just in case, don't allow too many recursive calls
	if (count > 10)
	  return;

	this.deltaString = "";

	var timeDelta = this.timeDelta;

	// Round up to the next unit of resolution.  We want to round up
	// because people naturally do that when talking about time, i.e.
	// it's one day until tomorrow, not zero days, or Thursday evening
	// it's two days until Saturday.
	var timeDeltaResolution = timeDelta / resolution;

	//+++ change this.timeDelta to a temp variable (otherwise calc needs to be called again before calling this function)
	timeDelta = Math.ceil(timeDeltaResolution) * resolution;

	// Calculate the amount of time until timeDelta will change at the
	// current resolution.  This is used by the calling function to determine
	// when to expect the next change (when to wake up).
	// (Don't recalculate this for recursive calls)
	this.nextChange = Math.floor((timeDeltaResolution - Math.floor(timeDeltaResolution)) * resolution);

	// Calculate the deltaDays and the left over milliseconds
	// We've already rounded up, so now just truncate when calculating the Days, Hours, etc.
	this.deltaDays  = Math.floor(timeDelta  / ONE_DAY);
	if (resolution == ONE_DAY && this.deltaDays == 1)
		{
		this.calcDeltas(ONE_HOUR, count+1);
		return;
		}

	timeDelta = timeDelta  - this.deltaDays  * ONE_DAY;

	if (this.deltaDays != 0)
		this.deltaString = this.deltaString  + this.getDeltaDaysText() + " ";

	// Calculate the deltaHours and the left over milliseconds
	if (resolution <= ONE_HOUR)
		{
		this.deltaHours  = Math.floor(timeDelta  / ONE_HOUR);
		timeDelta = timeDelta  - (this.deltaHours  * ONE_HOUR);
		// If there is exactly one day left, show only hours
		if (this.deltaDays == 1 && this.deltaHours == 0)
			{
			this.deltaDays = 0;
			this.deltaHours = 24;
			this.deltaString = "";
			}
		// (increase resolution if this is the last hour at hour resolution)
		if (resolution == ONE_HOUR && this.deltaDays == 0 && this.deltaHours == 1)
			{
			this.calcDeltas(ONE_MINUTE, count+1);
			return;
			}
//		timeDelta = timeDelta  - (this.deltaHours  * ONE_HOUR);

		// Display hours unless 0 and resolution is hours
		if ((this.deltaHours != 0) || (resolution == ONE_HOUR))
			this.deltaString = this.deltaString + this.getDeltaHoursText() + " ";
		}

	// Calculate the deltaMinutes and the left over milliseconds
	if (resolution <= ONE_HOUR)
		{
		this.deltaMinutes  = Math.floor(timeDelta  / ONE_MINUTE);
		timeDelta = timeDelta  - (this.deltaMinutes  * ONE_MINUTE);
		// If there is exactly one hour left, show only minutes
		if (this.deltaHours == 1 && this.deltaMinutes == 0)
			{
			this.deltaHours = 0;
			this.deltaMinutes = 60;
			this.deltaString = "";
			}
		if (resolution == ONE_MINUTE && this.deltaDays == 0 && this.deltaHours == 0 && this.deltaMinutes == 1)
			{
			this.calcDeltas(ONE_SECOND, count+1);
			return;
			}
//		timeDelta = timeDelta  - (this.deltaMinutes  * ONE_MINUTE);

		// Display minutes unless 0 and resolution is minutes
		if ((this.deltaMinutes != 0) || (resolution == ONE_MINUTE))
			this.deltaString = this.deltaString + this.getDeltaMinutesText() + " ";
		}

	if (resolution <= ONE_SECOND)
		{
		// Calculate the deltaSeconds and the left over milliseconds
		this.deltaSeconds  = Math.floor(timeDelta  / ONE_SECOND);
		timeDelta = timeDelta  - (this.deltaSeconds  * ONE_SECOND);	// any left over milliseconds - unused
		// If there is exactly one minute left, show only seconds
		if (this.deltaMinutes == 1 && this.deltaSeconds == 0)
			{
			this.deltaMinutes = 0;
			this.deltaSeconds = 60;
			this.deltaString = "";
			}
//		timeDelta  = timeDelta  - (this.deltaSeconds  * ONE_SECOND);

		this.deltaString = this.deltaString + this.getDeltaSecondsText() + " ";
		}

	return;
	}

function getDateStringXX(date)
	{
	return	date.getFullYear() + "|" +
			date.getMonth() + "|" +
			date.getDate() + "|" +
			date.getHours() + "|" +
			date.getMinutes()+  "|" +
			date.getSeconds();
	}

// Returns days until start or end of date
function getDeltaDaysText()
	{
	if (this.deltaDays == 1)
		return this.deltaDays + " day";
	else
		return this.deltaDays + " days";
	}

// Returns hours until start or end of date
function getDeltaHoursText()
	{
	if (this.deltaHours == 1)
		return this.deltaHours + " hour";
	else
		return this.deltaHours + " hours";
	}

function getDeltaMinutesText()
	{
	if (this.deltaMinutes == 1)
		return this.deltaMinutes + " minute";
	else
		return this.deltaMinutes + " minutes";
	}

function getDeltaSecondsText()
	{
	if (this.deltaSeconds == 1)
		return this.deltaSeconds + " second";
	else
		return this.deltaSeconds + " seconds";
	}

function getDayName2(date)
	{
	var days=new Array("Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday")
	var day = date.getDay()
	return days[day]
	}

function getMonthName3(date)
	{
	var months=new Array("January","February","March","April","May","June","July","August","September","October","November","December")
	var month = date.getMonth()
	return months[month]
	}

function addIntervalsToDate(result, source, interval, count)
	{
	if (this.DEBUG2) document.title = document.title + " I:" + interval.year + interval.month + interval.date + interval.hours + interval.minutes + interval.seconds;
	result.setFullYear(source.getFullYear() + count * interval.year);
	result.setMonth   (source.getMonth()    + count * interval.month);
	result.setDate    (source.getDate()     + count * interval.date);
	result.setHours   (source.getHours()    + count * interval.hours);
	result.setMinutes (source.getMinutes()  + count * interval.minutes);
	result.setSeconds (source.getSeconds()  + count * interval.seconds);
	}

function setDate(date, dateTime)
	{
	date.setFullYear(	dateTime.year,
						dateTime.month - 1, 	// Convert month to 0-11 range
						dateTime.date);
	date.setHours   (dateTime.hours);
	date.setMinutes (dateTime.minutes);
	date.setSeconds (dateTime.seconds);
	}

function getDateString2()
	{
	var dateString =
      this.getDayName2(this.workingStart)+" "+
    	this.getMonthName3(this.workingStart)+" "+
	this.workingStart.getDate();

  // If the time is 00:00:00, leave it off
  if (this.workingStart.getHours() != 0 || this.workingStart.getMinutes()!=0 || this.workingStart.getSeconds() != 0)
    dateString = dateString + " " +
         addLeading(this.workingStart.getHours(), "0")+":"+
         addLeading(this.workingStart.getMinutes(), "0")+":"+
         addLeading(this.workingStart.getSeconds(), "0")

  return dateString
	}

function daysUntilDateTime(dateTimeString, replaceZeros, name)
	{
	this.name = name;

	// Save arguments
	this.dateTimeString = dateTimeString;
	this.replaceZeros   = replaceZeros;

	// Define methods
	this.getEstMilliseconds = getEstMilliseconds;

	// If the year, month, or day is zero, use the value from the current time (now)
	this.year 	= parseInt(dateTimeString.substr(0,4),10);
	this.month	= parseInt(dateTimeString.substr(4,2),10);	// Month (in 1-12 range)
	this.date	= parseInt(dateTimeString.substr(6,2),10);

	if (replaceZeros)
		{
		if (this.year == 0)  this.year	= now.getFullYear();
		if (this.month == 0) this.month	= now.getMonth() + 1;	// Month (convert to 1-12 range)
		if (this.date == 0)  this.date  = now.getDate();
		}

	this.hours   = parseInt(dateTimeString.substr(9,2),10);		// Hours
	this.minutes = parseInt(dateTimeString.substr(11,2),10);	// Minutes
	this.seconds = parseInt(dateTimeString.substr(13,2),10);	// Seconds
	}

// This function is estimated because years and months both have
// variable lengths.  The function returns the minimum value,
// 364 day years and 28 day months.
function getEstMilliseconds()
	{
	return	this.year*ONE_YEAR +
			this.month*ONE_MONTH +
			this.date*ONE_DAY +
			this.hours*ONE_HOUR +
			this.minutes*ONE_MINUTE +
			this.seconds*ONE_SECOND;
	}

// Originally from:http://www.codeproject.com/useritems/Remote_Time_Zone.asp?df=100&forumid=339404&exp=0&select=1690270#xx1690270xx
function getLocalTimeOffset(time)
	{
	var date1 = new Date(time.getFullYear(), 0, 1, 0, 0, 0, 0);
	var temp = date1.toGMTString();
	var date2 = new Date(temp.substring(0, temp.lastIndexOf(" ")-1));
	var hoursDiffStdTime = (date1 - date2) / (1000 * 60 * 60);
	return hoursDiffStdTime;
	}
//-->
