// builds on dojo 1.0
dojo.provide("samiam.clock");

(function() {
	var staticClock = samiam.clock; 
	staticClock._timer = null;
	staticClock._tickers = [];
	staticClock.register = function(clock, methodName) {
		staticClock._tickers.push([clock, methodName || "tick"]);
		if(!staticClock._timer) {
				staticClock._timer = setInterval(function() { staticClock.tick(); }, 1000);			
		}
	};
	staticClock.unregister = function(clock) {
		var idx=0; 
		for(; idx<staticClock._tickers.length; idx++) {
			if(staticClock._tickers[idx][0] == clock) {
				staticClock._tickers.splice(idx, 1);
				if(staticClock._timer && !staticClock._tickers.length) {
					clearInterval(staticClock._timer);			
					staticClock._timer = null;
				}
				return true;
			}
		}
		return false;
	};
	
	staticClock.tick = function() {

		dojo.forEach(staticClock._tickers, function(clock_method) {
			var m = clock_method[1]; 
			var o = clock_method[0]
			o[m].apply(o);
		});
	}
})();

dojo.declare("samiam.Clock", null, {
	isRunning: false,
	endTime: new Date().getTime() + 864 * Math.pow(10, 5), // one day
	constructor: function(args, node) {
		this.domNode = node || null; 
		this.displayTemplate = "${month} ${date}, ${hours}:${minutes}:${seconds} ${pm}";
		dojo.mixin(this, args); 
		
		if(!this.domNode && this.domNode.parentNode) {
			throw new Error("samiam.Clock: no node in constructor arguments");
		}
	},
	postfix: function() {
		this.init();
	},
	init: function() {
		return;
	},
	_format: function(str, obj) {
		var re = /\$\{[^}]+\}/g;
		var str = str.replace(re, function(mstr) {
			var key = mstr.substring(2, mstr.length-1); 
			return (typeof obj[key] == "undefined") ? "" : obj[key];
		});
		return str;
	},
	start: function() {
		samiam.clock.register(this, "_tick");
		this.isRunning = true;
	},
	stop: function() {
		samiam.clock.unregister(this);
		this.isRunning = false;
	},
  onEnd: function() {
  	this.stop();
  },
	_tick: function() {
		this.tick();
		if(new Date().getTime() > this.endTime) {
			this.onEnd();
		}
	},
	tick: function() {
		var now = new Date();
		this.domNode.innerHTML = this.getDisplayTime(now);
	},
	_getDisplayTimeObject: function(date) {
		var time = {
			hours: (function(){ 
					var hr = date.getHours();
					return (hr > 12) ? hr -12 : hr;
					// return hr;
			})(),
			pm: date.getHours() > 12 ? "pm" : "am",
			minutes: date.getMinutes(),
			seconds: (function() { 
					var secs = date.getSeconds();
					return (secs > 9 || secs <= 0) ? secs : "0" + secs;
			})(),
			days: date.getDay(),
			date: (function() { 
				var intdate = date.getDate(); 
				var suffixes = ["st", "nd", "rd", "th"];
				var str = (intdate < suffixes.length) ? intdate + suffixes[intdate] : intdate+ "th"; 
				return str; 
			})(),
			day: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"][date.getDay()],
			month: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][date.getMonth()]
		};
		return time;
	},
	
	getDisplayTime: function(date) {
		var time = this._getDisplayTimeObject(date);
		return this._format(this.displayTemplate, time);
	}
			
});
dojo.declare("samiam.CountdownClock", samiam.Clock, {
	displayTemplate: "${month} ${date}, ${hours}:${minutes} ${seconds}${pm}",
  constructor: function(args, node) {
  	if(args.endDate) {
  		this.endTime = args.endDate.getTime();
  	}
  	if(!this.endTime) {
  		throw new Error("CountdownClock: invalid endTime property (count down to when?)");
  	}
  },
  _getDisplayTimeObject: function(date) {
  	var endms = this.endTime;
  	var ms = endms - date.getTime();
  	var SEC = 1000, MIN=SEC * 60, HOUR =MIN * 60, DAY=HOUR*24; 
  	var time = {
  		days: (function() { 
  			var remaining = ms % DAY;
  			var days = (ms - remaining) / DAY;
  			ms = remaining;
  			return days;
  		})(),
  		hours: (function(){ 
  			var remaining = ms % HOUR;
  			var hours = (ms - remaining) / HOUR;
  			ms = remaining; 
  			return hours;
  		})(),
  		minutes: (function(){ 
  			var remaining = ms % MIN;
  			var days = (ms - remaining) / MIN;
  			ms = remaining; 
  			return days;
  		})(),
  		seconds: (function(){ 
  			var remaining = ms % SEC;
  			var secs = (ms - remaining) / SEC;
  			ms = remaining; 
  			return (secs > 9 || secs <= 0) ? secs : "0" + secs;
  		})(),
  		pm: "",
  		date: ""
  	};
  	return time;
  }
}); 

dojo.declare("samiam.clock._RichHtmlClock", null, {
	constructor: function(args, node) {
		// expect at least a labelNode; 
		if(!this.labelNode) {
			throw new Error("samiam.clock._RichHtmlClock: no labelNode property given");
		}
		this.animNode = this.bgNode || this.domNode; 
	},
	
	setClip: function(node, edges) {
			var values = [];
			var names = ["top", "right", "bottom", "left"], name=null; 
			while(names.length) {
				name = 	names.shift();
				values.push((typeof edges[name] != "undefined") ? edges[name] + "px" : "auto");
			}
			var sClip = "rect(" + 
			values.join(" ") +
			")";
			node.style.clip = sClip;
			// console.log(sClip);
	}
});

dojo.declare("samiam.GraphicalCountdown", [samiam.CountdownClock, samiam.clock._RichHtmlClock], {
	init: function() {
		// setup initial display
		var time = this._getDisplayTimeObject(new Date());
		this.labelNode.innerHTML = this._format(this.displayTemplate, time);
	},
	start: function() {
		this.animNode.style.display = "block";
		this.inherited(arguments);
	},
	stop: function() {
		this.inherited(arguments);
	},
	tick: function() {
		var now = new Date();
		var time = this._getDisplayTimeObject(new Date());
		var unit = this.domNode.offsetWidth / 60;
		this.setClip(this.animNode, {
			right: Math.round(unit * time.seconds)
		});
		this.labelNode.innerHTML = this._format(this.displayTemplate, time);
		// console.log("unit: %d, seconds: %d, right: %d", unit, time.seconds, unit * time.seconds);
	}
}); 
