///////////////////////////////////////////////////////////////////////////////
//
//  Utils.js   			version 1.0
//  2007 Julia Yu, Lenny Burdette
//
//  Javascript utilities of use
//
//	OBJECTS:
//			HSN.tracker
//
//  FUNCTIONS:
//			Array.from
//			Array.push
//			Array.pop
//			Function.bind
//			HSN.extend
//			HSN.debug
//			HSN.DomLoaded
//			HSN.dispatch
//			HSN.make
//
///////////////////////////////////////////////////////////////////////////////

if ( !window.HSN ) { window.HSN = {}; }

if (!Array.prototype.push) {
	Array.prototype.push = function() {
		for (var i = 0, j = arguments.length; i < j; i++) {
			this[this.length] = arguments[i];
		}
		return this.length;
	};
}

if (!Array.prototype.pop) {
	Array.prototype.pop = function() {
		var lastElement = this[this.length - 1];
		this.length = Math.max(this.length - 1, 0);
		return lastElement;
	};
}

/** 
 * function.bind Adapted from prototype.js
 * uses Arrary From 
 */
 
if (!Function.bind) {
	Function.prototype.bind = function() {
		var from = function(iterable) {
			if (!iterable) {
				return [];
			}
			if (iterable.toArray) {
				return iterable.toArray();
			} else {
				var results = [];
				for (var i = 0, length = iterable.length; i < length; i++) {
					results.push(iterable[i]);
				}
				return results;
		    }
		};
	
		var method = this, 
			args = from(arguments), 
			object = args.shift();
		
		return function() {
	        return method.apply(object, args.concat(from(arguments)));
		};

	};
}

/**
 * Crockford's inheritance expanded
 */
HSN.extend = function(subClass, superClass) {
	var F = function() {}
	F.prototype = superClass.prototype; 			// Create temp class of super
	subClass.prototype = new F(); 					// chain sub with super
	subClass.prototype.constructor = superClass; 		// override constructor of super with sub
	
	if (superClass) { 
		for (var i in superClass) { 
			subClass.prototype[i] = superClass[i];	// add methods/properties from objectExtend
		}
	}
};

/**
 * wrap console.log and alert in generic function
 *
 * USAGE: HSN.debug("this is broken");
 * USAGE: HSN.debug.on = true; 
 */
 
HSN.debug = function(msg){
	if (HSN.debug.on) {
		if (window.console) {
			console.log(msg);
		} else {
			alert(msg);
		}
	}
	return { on : false } // default state of debug is off
}

/**
 * event stack for DOM load
 * http://www.cherny.com/demos/onload/domloaded.js
 *
 * USAGE: HSN.DomLoaded.load(functionthatrunswhendomloads);
 */
 
HSN.DomLoaded = {
	onload: [],
	loaded: function()
	{
		if (arguments.callee.done) return;
		arguments.callee.done = true;
		for (var i = 0;i < HSN.DomLoaded.onload.length;i++) HSN.DomLoaded.onload[i]();
	},
	load: function(fireThis)
	{
		this.onload.push(fireThis);
		if (document.addEventListener) 
			document.addEventListener("DOMContentLoaded", HSN.DomLoaded.loaded, null);
		if (/KHTML|WebKit/i.test(navigator.userAgent))
		{ 
			var _timer = setInterval(function()
			{
				if (/loaded|complete/.test(document.readyState))
				{
					clearInterval(_timer);
					delete _timer;
					HSN.DomLoaded.loaded();
				}
			}, 10);
		}
		/*@cc_on @*/
		/*@if (@_win32)
		var proto = "src='javascript:void(0)'";
		if (location.protocol == "https:") proto = "src=//0";
		document.write("<scr"+"ipt id=__ie_onload defer " + proto + "><\/scr"+"ipt>");
		var script = document.getElementById("__ie_onload");
		script.onreadystatechange = function() {
		    if (this.readyState == "complete") {
		        HSN.DomLoaded.loaded();
		    }
		};
		/*@end @*/
	   window.onload = HSN.DomLoaded.loaded;
	}
};

/**
 * event dispatcher
 */
HSN.dispatch = {
	subscriptions : {},
	
	subscribe : function(someEvent, subscriber, todo) {
		if (!this.subscriptions[someEvent]) {
			this.subscriptions[someEvent] = {};
		}
		this.subscriptions[someEvent][subscriber] = todo;
	},

	broadcast : function(someEvent, broadcaster) {
		// click tracking can go in here as well
		
		if (!this.subscriptions[someEvent]) { 
			HSN.debug("no one cares about: " + someEvent + " caller: " + broadcaster);
			return;	
		}
		for (var subscriber in this.subscriptions[someEvent]) {
			var todo = this.subscriptions[someEvent][subscriber]; 
			if (typeof todo == "function" ) {
				todo(broadcaster);
			} else {
				HSN.debug("handler wasnt a function on: " + subscriber + " for event: " + someEvent);
			}
		}
	}
}

/**
 * DATA OBJECTS
 */
HSN.tracker = {}

/**
 * abstracted make an object, keep instance in tracker
 * takes object type as string, and params object, with params.name specified
 */
HSN.make = function(oType, params) {
	if (!HSN.tracker[oType]){
		HSN.tracker[oType] = {};
	}
	HSN.tracker[oType][params.name] = new HSN[oType](params);
	
	return HSN.tracker[oType][params.name];
}


