/* 
* jCountdown 1.3.3 jQuery Plugin
* Copyright 2011 Tom Ellis http://www.webmuse.co.uk | MIT Licensed (license.txt)
*/
(function($) {

$.fn.countdown = function( method /*, options*/ ) {

	var defaults = {
			date: new Date(),
			updateTime: 1E3,
			htmlTemplate: "<div class='stamp'><span><div class='line'></div>%{d}</span></div><div class='stamp'><span><div class='line'></div>%{h}</span></div><div class='stamp'><span><div class='line'></div>%{m}</span></div><div class='stamp right'><span><div class='line'></div>%{s}</span></div><div class='cd-time'>days</div><div class='cd-time'>hours</div><div class='cd-time'>minutes</div><div class='cd-time right'>seconds</div>",
			minus: false,
			onChange: null,
			onComplete: null,
			onResume: null,
			onPause: null,
			leadingZero: false,
			offset: null,
			servertime:null,
			hoursOnly: false,
			direction: "down"
		},
        slice = [].slice,
		floor = Math.floor,
		msPerHr = 36E5,
		msPerDay = 864E5,
		rDate = /(%\{d\}|%\{h\}|%\{m\}|%\{s\})/g,
		rDays = /%\{d\}/,
		rHrs = /%\{h\}/,
		rMins = /%\{m\}/,
		rSecs = /%\{s\}/,
		getTZDate = function( offset, difference ) {					
			
			var hrs,
				dateMS,
				extra,
				tmpDate = new Date();
			
			if( offset === null ) {
				dateMS = tmpDate.getTime() - difference;
			} else {				
				hrs = offset * msPerHr;
				curHrs = tmpDate.getTime() - ( ( -tmpDate.getTimezoneOffset() / 60 ) * msPerHr ) + hrs,
				dateMS = tmpDate.setTime( curHrs );
			}
			return new Date( dateMS );
		},			
		timerFunc = function() {
			//Function runs at set interval updating countdown
			var $this = this,
				template,
				now,
				date,
				timeLeft,
				eDaysLeft,
				daysLeft,
				eHrsLeft,
				hrsLeft,
				minsLeft,					
				eMinsleft,
				secLeft,
				time = "",
				settings = $this.data("jcdData");
				
			if( !settings ) {
				return false;
			}
			
			template = settings.htmlTemplate;
			
			if( settings.offset === null && settings.servertime === null ) {
				now = new Date();
			} else 	if( settings.offset !== null ) {
				now = getTZDate( settings.offset );
			} else {
				now =  getTZDate( null, settings.difference ); //Date now
			}
			
			
			date = new Date( settings.date ); //Date to countdown to
			
			timeLeft = ( settings.direction === "down" ) ? date.getTime() - now.getTime() : now.getTime() - date.getTime();	
					
			
			eDaysLeft = timeLeft / msPerDay;
			daysLeft = floor( eDaysLeft );
			eHrsLeft = ( eDaysLeft - daysLeft ) * 24;
			hrsLeft = floor( eHrsLeft );
			minsLeft = floor( ( eHrsLeft - hrsLeft ) * 60 );				
			eMinsleft = ( eHrsLeft - hrsLeft ) * 60;
			//secLeft = floor( (eMinsleft - minsLeft ) * 60 );
			secLeft = Math.round( (eMinsleft - minsLeft ) * 60 );
			percent = 100 - parseInt( (daysLeft / startDays ) * 100, 10);
			
			
			if( settings.hoursOnly ) {
				hrsLeft += daysLeft * 24;
				daysLeft = 0;
			}
			
			settings.daysLeft = daysLeft;
			settings.hrsLeft = hrsLeft;
			settings.minsLeft = minsLeft;
			settings.secLeft = secLeft;
			
			if( secLeft == 60 ) { 
				secLeft = 0;
			}
			
			if ( settings.leadingZero ) {			
				if ( daysLeft < 10 && !settings.hoursOnly ) {
					daysLeft = "0" + daysLeft;
				}
				if ( hrsLeft < 10 ) {
					hrsLeft = "0" + hrsLeft;
				}
				if ( minsLeft < 10 ) {
					minsLeft = "0" + minsLeft;
				}
				if ( secLeft < 10 ) {
					secLeft = "0" + secLeft;
				}
			}

			if ( settings.direction === "down" && ( now <= date || settings.minus ) ) {
				time = template.replace( rDays, daysLeft ).replace( rHrs, hrsLeft ).replace( rMins, minsLeft ).replace( rSecs, secLeft );
			} else if ( settings.direction === "up" && ( date <= now || settings.minus ) ) {
				time = template.replace( rDays, daysLeft ).replace( rHrs, hrsLeft ).replace( rMins, minsLeft ).replace( rSecs, secLeft );
			} else {
				time = template.replace( rDate, "00");
				settings.hasCompleted = true;
			}
							
			$this.html( time ).trigger("change.jcdevt", [settings] );
			
			if ( settings.hasCompleted ) {
				$this.trigger("complete.jcdevt");
				clearInterval( settings.timer );
			}
		},			
		methods = {		
			init: function( options ) {
				
				var opts = $.extend( {}, defaults, options ),
					template = opts.htmlTemplate;
				
				return this.each(function() {
					var $this = $(this),
						settings = {},
						func;

					//If this element already has a countdown timer, just change the settings
					if( $this.data("jcdData") ) {
						$this.countdown("changeSettings", options);
						return true;
					}
					
					//Add event handlers where set
					if( opts.onChange ) {
						$this.bind("change.jcdevt", opts.onChange );
					}
					
					if( opts.onComplete ) {
						$this.bind("complete.jcdevt", opts.onComplete );
					}
					
					if( opts.onPause ) {
						$this.bind("pause.jcdevt", opts.onPause );
					}

					if( opts.onResume ) {
						$this.bind("resume.jcdevt", opts.onResume );
					}
					
					settings = {
						originalContent : $this.html(),
						date : opts.date,
						hoursOnly : opts.hoursOnly,
						leadingZero : opts.leadingZero,
						updateTime : opts.updateTime,
						direction : opts.direction,
						template : opts.htmlTemplate,
						htmlTemplate : opts.htmlTemplate,
						minus : opts.minus,
						offset : opts.offset,
						servertime: opts.servertime,
						difference: null,
						onChange : opts.onChange,
						onComplete : opts.onComplete,
						onResume : opts.onResume,
						onPause : opts.onPause,
						hasCompleted : false,
						timer : 0	
					};
					
					if( opts.servertime !== null ) {
						var local = new Date(),
							difference = local.getTime() - settings.servertime;
							difference = Number(difference);

						settings.difference = difference;
					}

					func = $.proxy( timerFunc, $this );
					settings.timer = setInterval( func, settings.updateTime );

					$this.data( "jcdData", settings );
					
					func();
				});
			},
			changeSettings: function( options ) {
				//Like resume but with resetting/changing options
				return this.each(function() {
					var $this  = $(this),
						settings,
						func = $.proxy( timerFunc, $this );
						
					if( !$this.data("jcdData") ) {
						return true;
					}
					
					settings = $.extend( {}, $this.data("jcdData"), options );						
					
					$this.unbind(".jcdevt");
					//Clear the timer, as it might not be needed
					clearInterval( settings.timer );

					if( settings.onChange ) {
						$this.bind("change.jcdevt", settings.onChange);
					}

					if( settings.onComplete ) {
						$this.bind("complete.jcdevt", settings.onComplete);
					}
					
					if( settings.onPause ) {
						$this.bind("pause.jcdevt", settings.onPause );
					}

					if( settings.onResume ) {
						$this.bind("resume.jcdevt", settings.onResume );
					}
					
					settings.timer = setInterval( func, settings.updateTime );
					$this.data("jcdData", settings);
					func(); //Needs to run straight away when changing settings							
				});
			},
			resume: function() {			
				//Resumes a countdown timer
				return this.each(function() {
					var $this = $(this),
						settings = $this.data("jcdData"),
						func = $.proxy( timerFunc, $this );
					
					if( !settings ) {
						return true;
					}
					
					settings.timer = setInterval( func, settings.updateTime );
					$this.data("jcdData", settings).trigger("resume.jcdevt")
					func();
				});
			},
			pause: function() {	
				//Pause a countdown timer			
				return this.each(function() {
					var $this = $(this),
						settings = $this.data("jcdData");

					if( !settings ) {
						return true;
					}
					//Clear interval (Will be started on resume)
					clearInterval( settings.timer );
					//Trigger pause event handler
					$this.data("jcdData", settings).trigger("pause.jcdevt");					
				});
			},
			complete: function() {
				return this.each(function() {
					var $this = $(this),
						settings = $this.data("jcdData");

					if( !settings ) {
						return true;
					}
					//Clear timer
					clearInterval( settings.timer );
					settings.hasCompleted = true;
					//Update setting, trigger complete event handler, then unbind all events
					//We don"t delete the settings in case they need to be checked later on
					$this.data("jcdData", settings).trigger("complete.jcdevt").unbind(".jcdevt");
				});		
			},
			destroy: function() {				
				return this.each(function() {
					var $this = $(this),
						settings = $this.data("jcdData");
					
					if( !settings ) {
						return true;
					}
					//Clear timer
					clearInterval( settings.timer );
					//Unbind all events, remove data and put DOM Element back to its original state (HMTL wise)
					$this.unbind(".jcdevt").removeData("jcdData").html( settings.originalContent );
				});
			},
			getSettings: function( name ) {
				var $this = $(this),
					settings = $this.data("jcdData");
				
				if( !settings ) {
					return undefined;
				}
				//If an individual setting is required
				if( name ) {
					//If it exists, return it
					if( settings.hasOwnProperty( name ) ) {
						return settings[name];
					}
					return undefined;
				}
				//Return all settings
				return settings;
			}
		};
	
	if( methods[ method ] ) {
		return methods[ method ].apply( this, slice.call( arguments, 1 ) );
	} else if ( typeof method === "object" || !method ) {
		return methods.init.apply( this, arguments );
	} else {
		$.error("Method "+ method +" does not exist in the jCountdown Plugin");
	}
};

})(jQuery);
