/**
 * The Countdown Utility provides utilities for a 
 * shared clock and multiple running countdown instances
 * 
 * @title Countdown Utility
 * @namespace wxtools
 * @requires YAHOO.util.Dom, YAHOO.util.Event
 * @author Joe Pearson
 * @version 1.0
 */

 // Created By: Joe Pearson
 // Created On: 9/22/2009
 // Last Modified By: 
 // Last Modified On: 

if (!window.wxtools){
	window.wxtools = {};
}

/**
 * The clock utility provides functions to 
 * initialize the ticks, stop the ticks, to tick, 
 * and a flag to detect whether or not the clock is ticking
 * 
 * @class Clock
 * @static
 */
wxtools.Clock = {
	/**
	 * True after the clock has been initialized, reset to false if the clock has been stopped
	 * @property running
	 * @type boolean
	 * @static
	 */
	running: false,
	
	/**
	 * Holds the setInterval handle once it has been created
	 * @property handle
	 * @type object
	 * @static
	 */
	handle: null,
	
	/**
	 * Starts the clock ticking if it is not running already, 
	 * creates a custom ping event if it does not already exist,
	 * stores the setInterval handle
	 * 
	 * @method init
	 * 
	 * @static
	 */
	init: function(){
		if (this.running === false){
			this.running = true;
			// create custom events
	
			/**
			 * Custom event thrown with every tick of the clock's second hand
			 * @property ping
			 * @type object
			 * @static
			 */
			this.ping = new YAHOO.util.CustomEvent("ping",wxtools.Clock);
			// tick once a second
			this.handle = setInterval(function(){wxtools.Clock.tick()},990);
		}
	},

	/**
	 * Fires a ping event once per second
	 * 
	 * @method tick
	 * 
	 * @static
	 */
	tick: function(){
		wxtools.Clock.ping.fire();
	},

	/**
	 * If the running property is true, 
	 * stops the setInterval using the handle property and 
	 * resets the running property to false
	 * 
	 * @method stop
	 * 
	 * @static
	 */
	stop: function(){
		if (this.running === true) {
			clearInterval(this.handle);
			this.running = false;
		}
	}
};

/**
 * The countdown utility provides functions to 
 * listen to clock pings and unsubscribe the listener
 * 
 * @class Countdown
 * @constructor
 */
wxtools.Countdown = function(cfg){
	// set the default values
	if (cfg && typeof cfg === "object"){

		/**
		 * The date and time we are counting towards
		 * @property targetDate
		 * @type object
		 */
		this.targetDate = (cfg.target) ? cfg.target : new Date();

		/**
		 * The date and time we are counting from in the same TZ as targetDate
		 * @property startDate
		 * @type object
		 */
		this.startDate = (cfg.start) ? cfg.start : new Date();

		/**
		 * An instance method that gets fired once a second
		 * 
		 * @method seconds
		 * 
		 * @param {integer}
		 */
		this.seconds = (cfg.seconds) ? cfg.seconds : function(){};

		/**
		 * An instance method that gets fired once a minute
		 * 
		 * @method minutes
		 * 
		 * @param {integer}
		 */
		this.minutes = (cfg.minutes) ? cfg.minutes : function(){};

		/**
		 * An instance method that gets fired once an hour
		 * 
		 * @method hours
		 * 
		 * @param {integer}
		 */
		this.hours = (cfg.hours) ? cfg.hours : function(){};

		/**
		 * An instance method that gets fired once a day
		 * 
		 * @method days
		 * 
		 * @param {integer}
		 */
		this.days = (cfg.days) ? cfg.days : function(){};

		/**
		 * An instance method that gets fired when the countdown hits the target
		 * 
		 * @method zero
		 */
		this.zero = (cfg.zero) ? cfg.zero : function(){};

		/**
		 * The current date and time on the user's computer when the instance was created and the clock started ticking for this instance
		 * @property now
		 * @type object
		 */
		this.now = new Date();
	}

	/**
	 * Has the target time been reached yet?
	 * @property zeroFired
	 * @type boolean
	 */
	this.zeroFired = false;
	var myT = this;

	/**
	 * A ping event listener for this countdown instance
	 * 
	 * @method handlePing
	 */
	this.handlePing = function(){
		var YUD = YAHOO.util.Dom;

		/**
		 * what time is it now on the users' computer right now?
		 * @property pingDate
		 * @type object
		 * @private
		 */
		var pingDate = new Date();

		/**
		 * what time is it now based on the countdown clock?
		 * @property newDate
		 * @type object
		 * @private
		 */
		// make a copy of the server's clock date from when the page was loaded
		var newDate = new Date(myT.startDate);
		// calculate the difference based on the users' clock and apply to the server's clock
		newDate.setMilliseconds(newDate.getMilliseconds() + (pingDate - myT.now));

		// is the target still in the future?
		if (myT.targetDate >= newDate){

			/**
			 * Stores the number of seconds between newDate and targetDate
			 * @property remainder
			 * @type integer
			 * @private
			 */
			// get the difference in milliseconds and convert to seconds
			var remainder = parseInt((myT.targetDate - newDate) / 1000);

			/**
			 * Stores the number of whole days between newDate and targetDate
			 * @property dof
			 * @type integer
			 * @private
			 */
			// how many days remain?
			var dof = (remainder >= 86400) ? parseInt((remainder / 86400)) : 0;
			// subtract the days' worth of seconds
			remainder -= dof * 86400;

			/**
			 * Stores the number of whole hours between newDate and targetDate
			 * @property ho
			 * @type integer
			 * @private
			 */
			// how many hours remain?
			var ho = (remainder >= 3600) ? parseInt((remainder / 3600)) : 0;
			// subtract the hours' worth of seconds
			remainder -= ho * 3600;

			/**
			 * Stores the number of whole minutes between newDate and targetDate
			 * @property mo
			 * @type integer
			 * @private
			 */
			// how many minutes remain?
			var mo = (remainder >= 60) ? parseInt((remainder / 60)) : 0;
			// subtract the minutes' worth of seconds
			remainder -= mo * 60;
			// all that's left in remainder is seconds

			// now call the methods and pass in the appropriate units
			myT.seconds(remainder);
			myT.minutes(mo);
			myT.hours(ho);
			myT.days(dof);
		} else {
			// the target is in the past.  Let the view know.
			if (myT.zeroFired === false){
				myT.zero();
				myT.zeroFired = true;
			}
		}
	};

	// start the ticker controller, if it isn't already going
	wxtools.Clock.init();

	// tell the controller that we want to know every time the clock ticks
	wxtools.Clock.ping.subscribe(this.handlePing,wxtools.Clock);
	// tell the controller that we don't want to know when the clock ticks


	/**
	 * An instance method for unsubscribing the instance from the ping event
	 * 
	 * @method unsub
	 */
	this.unsub = function(){
		wxtools.Clock.ping.unsubscribe(this.handlePing,wxtools.Clock);
	}
};
