/**
 *	utils from sleepbot.com
 */

if ((typeof Sleepbot) == 'undefined')  { Sleepbot = {}; }

//- - -
//- - - public : Utils
//- - -

Sleepbot.Util = {
	propsCopy: function(oFrom, oTo) {
		var k;
		if (! oTo) {
			if (! oFrom)  { return oTo; }
			else  { oTo = { }; }
		}
		for (k in oFrom)
			oTo[k] = oFrom[k];
		return oTo;
	},
	propsFill: function(oFrom, oTo) {
		var k;
		if (! oTo) {
			if (! oFrom)  { return oTo; }
			else  { oTo = { }; }
		}
		for (k in oFrom)
			if (! (k in oTo))
				oTo[k] = oFrom[k];
		return oTo;
	}
};
Sleepbot.Util.propsCopy({
	_debugNode: null,
	debug: function(/* ... */) {
		var o = window['console'], f, a = arguments;
		if (! a.length)  { return; }
		if (o) {
			if ((typeof a[0]) == 'object')  { f = o['dir']; }
			f = (f || o['debug'] || o['log']);
		}
		if (f) {
			f.apply(o, a);
			return;
		}
		if (! this._isOnLoad) {
			//	delay before node-ing
			var me = this;
			this.addOnLoad(function() {
				me.debug.apply(me, a);
			});
			return;
		}
		var n = this._debugNode;
		if (! n) {
			var d = document, ctnr = d.createElement('div');
			this.propsCopy({
				width: '99%',
				height: '105px',
				overflow: 'auto'
			}, ctnr.style);
			this._debugNode = n = d.createElement('div');
			this.propsCopy({
				margin: '5px',
				'fontSize': '11px',
				'fontFamily': 'monospace'
			}, n.style);
			d.body.appendChild(ctnr);
			ctnr.appendChild(n);
			n.innerHTML = '';
		}
		n.innerHTML += this._argArray(a).join(' ') + '<br />';
	},
	// ...
	fBlank: function() { return ''; },
	fIdentity: function(o) { return o; },
	// ...
	exists: function(o) {
		return ((! this.isUndefined(o)) && (o != null));
	},
	isUndefined: function(o) {
		return ((typeof o) == 'undefined');
	},
	isObject: function(o) {
		return (o && (typeof o == 'object' || this.isFunction(o) || this.isArray(o))) || false;
	},
	isArray: function(o) {
		return (o && (o instanceof Array || typeof o == 'array')) || false;
	},
	isString: function(o) {
		return ((o === '') || (o && (o instanceof String || typeof o == 'string'))) || false;
	},
	isFunction: function(o) {
		return (o && (o instanceof Function || typeof o == 'function')) || false;
	},
	asString: function(o) {
		if (this.isString(o))  { return o; }
		if (! o)  { return ''; }
		if (o.toString)  { return o.toString(); }
		return new String(o);
	},
	toArray: function(x) {
		if ((! x) || this.isUndefined(x['length']))  { return; }
		var a = [];
		for (var i=0; i<x.length; ++i)  { a.push(x[i]); }
		return a;
	},
	asArray: function() {
		var a = arguments;
		if (! a)  { return []; }
		return Array.prototype.slice.call(a, 0, a.length);
	},
	_argArray: function(a) {
		return this.asArray.apply(this, a);
	},
	trim: function(s) {
		if ((! s) || (! this.isString(s)))  { return s; }
		return s.replace(/^\s+/, '').replace(/\s+$/, '');
	},
	//	...
	namespace: function(n) {
		if (! n)  { return; }
		var aN = n.split('.'), nn = '';
		for (var i=0; i<aN.length; ++i) {
			nn = nn + (nn ? '.' : '') + aN[i];
			eval("if (typeof " + nn + " == 'undefined')  { " + nn + " = { }; }");
		}
		return eval(n);
	},
	chain: function(/* ... */) {
		var a = arguments; // this._argArray(arguments);
		var me = this;
		return function() {
			for (var i=0; i<a.length; ++i) {
				if (me.isFunction(a[i]))  { a[i](); }
			}
		};
	},
	hitch: function(o, fn) {
		o = o || this;
		return function()  { return fn.apply(o, arguments); }
	},
	partial: function(o, fn) {
		//	fn is called in context of o with all remaining args passed
		//	it's hitch with partial parameter propagation
		var o = o || this;
		var args = [];
		for (var a=arguments, i=2, len=a.length; i<len; ++i)  { args.push(a[i]); };
		return function()  { return fn.apply(o, args.concat(Sleepbot.Util._argArray(arguments))); };
	},
	// ...
	_isOnLoad: false,
	addOnLoad: function(f)  { window.onload = this.chain(window.onload, f); },
	addOnUnload: function(f)  { window.onunload = this.chain(f, window.onunload); },
	afterOnLoad: function(f)  { this.addOnLoad(function() { window.setTimeout(f, 0); }) },
	// ...
	asNode: function(node) {
		if (this.isString(node))  { node = this.byId(node); }
		return node;
	},
	byId: function(id) {
		var d = document;
		if (d['getElementById'])  { return d.getElementById(id); }
		if (document['all'])  { return d.all(id); }
		return null;
	},
	toggleShow: function(node) {
		node = this.asNode(node);
		this.show(node, (! this.isShown(node)));
	},
	show: function(node, b) {
		node = this.asNode(node);
		if (! node)  { return; }
		if (this.isUndefined(b))  { b = true; }
		var d = (node.tagName || '').toLowerCase();
		switch (d) {
			case 'span':  d = 'inline';  break;
			case 'div':  d = 'block';  break;
			default:  d = '';
		}
		node.style.display = (b ? d : 'none');
	},
	isShown: function(node) {
		node = this.asNode(node);
		if (! (node && node.style))  { return false; }
		var d = node.style.display;
		return ((d === '') || (d && (d != 'none')));
	},
	visible: function(node, b) {
		node = this.asNode(node);
		if (! node)  { return; }
		if (this.isUndefined(b))  { b = true; }
		node.style.visibility = (b ? 'visible' : 'hidden');
	},
	isVisible: function(node) {
		node = this.asNode(node);
		return (node && node.style && (node.style.visibility != 'hidden'));
	},
	getContent: function(node) {
		node = this.asNode(node);
		if (! node)  { return null; }
		if (node.innerHTML) { return node.innerHTML; }
		if (node.innerText) { return node.innerText; }
		return null;
	},
	setContent: function(node, s) {
		node = this.asNode(node);
		if (! node)  { return; }
		s = this.asString(s);
		if (node.innerHTML)  { node.innerHTML = s; }
		else if (node.innerText)  { node.innerText = s; }
		else  { node.innerHTML = s; }
	},
	// ...
	propNames: function(o) {
		if (o) {
			var a = [];
			for (var n in o)  { a.push(n); }
			return a;
		}
	},
	propNoCase: function(o, prop) {
		if (! o)  { return o; }
		if (! prop)  { return prop; }
		return (o[prop] || o[prop.toLowerCase()] || o[prop.toUpperCase()]);
	},
	propFixCase: function(o, prop) {
		if (! o)  { return o; }
		if (! prop)  { return prop; }
		var v = o[prop];
		if (! v) {
			var f = function(p) {
				var vv = o[p];
				if (vv) {
					delete o[p];
					o[prop] = vv;
				}
				return vv;
			}
			v = (f(prop.toLowerCase()) || f(prop.toUpperCase()));
		}
		return v;
	},
	propsFilter: function(o, a) {
		if ((! o) || (! a))  { return o; }
		if (! this.isArray(a))  { a = this.propNames(a); }
		var oo = {};
		for (var i=0; i<a.length; ++i) {
			var p = a[i];
			if (p in o)  { oo[p] = o[p]; }
		}
		return oo;
	},
	propsFixCase: function(o, props) {
		if (! o)  { return o; }
		if (! props)  { return props; }
		var a = [];
		for (var i=0; i<props.length; ++i)
			a.push(this.propFixCase(o, props[i]));
		return a;
	},
	propUsurp: function(o, old, young) {
/*
		usurp : child takes the place of the parent
			operation is case insensitive
		if ((base contains a child old) and (old contains a child young))
			base loses connection to old
			old loses connection to young
			base gains connection to young (by young's name NOT old's)
*/
		if (! o)  { return o; }
		var oy, oo = this.propNoCase(o, old);
		if (oo) {
			oy = this.propNoCase(oo, young);
			if (oy) {
				//	normalize THEN delete
				this.propFixCase(o, old);
				delete o[old];
				this.propFixCase(oo, young);
				delete oo[young];
				o[young] = oy;
			}
		}
		return oy;
	},
	propFilicide: function(o, old, young) {
/*
		filicide : child kills the parent
			operation is case insensitive
		if ((base contains a child old) and (old contains a child young))
			young replaces old on base (by old's name)
			old is unaffected
*/
		if (! o)  { return o; }
		var oy, oo = this.propNoCase(o, old);
		if (oo) {
			oy = this.propNoCase(oo, young);
			if (oy) {
				//	normalize THEN replace
				this.propFixCase(o, old);
				o[old] = oy;
			}
		}
		return oy;
	}
}, Sleepbot.Util);

/*
	convenience
*/
Sleepbot.Util.propsCopy({
	debug: Sleepbot.Util.hitch(Sleepbot.Util, Sleepbot.Util.debug),
	byId: Sleepbot.Util.hitch(Sleepbot.Util, Sleepbot.Util.byId)
}, Sleepbot);

Sleepbot.Util.addOnLoad(function() {
	Sleepbot.Util._isOnLoad = true;
});

