/**
 * Sparo Javascript Framework
 * @author Chris Bigelow
 * @version 1.0
 * Use and distribute freely but please credit this author.
 */

sparo = {};
sparo.path = (function(){
	    var s = document.getElementsByTagName('SCRIPT');
	    var sLen = s.length;
	    var str = '';
	    var ndx = -1;
	    for (var i = 0; i < sLen; i++) {
	        ndx = s.item(i).src.indexOf('sparo.js');
	        if (ndx != -1) {
	            str = s.item(i).src.substring(0, ndx);
	            break;
	        }
	    }
	    return str;
	})() + 'library/';


/**
 * Document Load Events
 */
function onDOMLoad(fn){
    if (document.addEventListener) { //Mozilla
        document.addEventListener("DOMContentLoaded", fn, false);
    }
    else 
        if (document.readyState) { //IE
            if (!sparo.onDOMLoaded) {
                sparo.onDOMLoaded = [];
            }
            sparo.onDOMLoaded.push(fn);
            document.onreadystatechange = function(){
                if (document.readyState == 'complete') {
                    for (var i = 0; i < sparo.onDOMLoaded.length; i++) {
                        sparo.onDOMLoaded[i]();
                    }
                    delete sparo.onDOMLoaded;
                }
            };
        }
}

// onload events
function onLoad(fn){
    addEvent(window, 'load', fn, true);
}

var addEvent = (function(){
	var docEl = document.documentElement;
	var f;
	if (docEl.addEventListener) {
		f = function addEvent(el, evType, fn, useCap){
			if (typeof el === 'string') {
				el = document.getElementById(el);
			}
			el.addEventListener(evType, fn, useCap ? useCap : false);
			return true;
		};
	}
	else 
		if (docEl.attachEvent) {
			f = function addEvent(el, evType, fn){
				if (typeof el === 'string') {
					el = document.getElementById(el);
				}
				return el.attachEvent('on' + evType, fn);
			};
		}
		else {
			f = function addEvent(el, evType, fn){
				if (typeof el === 'string') {
					el = document.getElementById(el);
				}
				el['on' + evType] = fn;
			};
		}
	var addEvent = null;
	return f;
})();


/**
 * Adding Scripts and Styles
 */
if (!window.addScript) {
	function addScript(name){
		var scs = document.getElementsByTagName('SCRIPT');
		var scsLen = scs.length;
		for (var i = 0; i < scsLen; i++) {
			if (scs[i].src.indexOf(name) != -1) {
				return;
			}
		}
		var newjs = document.createElement('SCRIPT');
		newjs.type = 'text/javascript';
		newjs.src = name;
		document.getElementsByTagName('HEAD')[0].appendChild(newjs);
	}
}

if (!window.addCSS) {
	function addCSS(name){
		var css = document.createElement('LINK');
		css.rel = 'stylesheet';
		css.type = 'text/css';
		css.href = name;
		document.getElementsByTagName('HEAD')[0].appendChild(css);
	}
}

if (!window.addStyle) {
	function addStyle(css){
		var s = document.createElement('STYLE');
		s.type = "text/css";
		if (s.styleSheet) {
			s.styleSheet.cssText = css;
		}
		else {
			s.appendChild(document.createTextNode(css));
		}
		document.getElementsByTagName('HEAD')[0].appendChild(s);
	}
}


/**
 * Set and Get Style Attributes
 */
sparo.getStyle = (function(){
	var f;
	if (document.documentElement.currentStyle !== undefined && document.documentElement.style.opacity === undefined) { //IE
		f = function getStyle(el, st){
			var ret = el.currentStyle[st];
			if (st === 'opacity') {
				if (el.style.filter && el.style.filter.indexOf("opacity=") >= 0) {
					ret = (parseFloat(el.style.filter.match(/opacity=([^)]*)/)[1]) / 100) + '';
				}
				else {
					ret = 1;
				}
			}
			return ret;
		};
	}
	else 
		if (document.defaultView && document.defaultView.getComputedStyle) { //Firefox
			f = function getStyle(el, st){
				return document.defaultView.getComputedStyle(el, null)[st];
			};
		}
		else { //try and get inline style
			f = function getStyle(el, st){
				return el.style[st];
			};
		}
	var getStyle = null;
	return f;
})();
sparo.setStyle = (function(){
	var f = function setStyle(el, st, val){
		if (st === 'opacity' && el.currentStyle !== undefined && el.style.opacity === undefined) {
			st = 'filter';
			val = (el.style.filter || "").replace(/alpha\([^)]*\)/, "") +
			(parseInt(val, 10) + '' == "NaN" ? "" : "alpha(opacity=" + val * 100 + ")");
		}
		el.style[st] = val;
	};
	var setStyle = null;
	return f;
})();

/**
 * Extend Funcionality
 */
// wrap to avoid global namespace
(function(){
	// Add indexOf method to all Arrays
	// returns -1 unless it is an exact match (no partial matches)
	if (!Array.prototype.indexOf) {
		Array.prototype.indexOf = function indexOf(el){
			var len = this.length >>> 0;
			var f = Number(arguments[1]) || 0;
			f = (f < 0) ? Math.ceil(f) : Math.floor(f);
			if (f < 0) {
				f += len;
			}
			for (; f < len; f++) {
				if (f in this && this[f] === el) {
					return f;
				}
			}
			return -1;
		};
		var indexOf = null;
	}
	
	// ForEach in Array
	// runs fun( array[i], i, array );
	// within fun() "this" -> thisp
	if (!Array.prototype.forEach) {
		Array.prototype.forEach = function forEach(fun /*, thisp*/){
			if (typeof fun != "function") {
				return;
			}
			var len = this.length >>> 0;
			var thisp = arguments[1];
			for (var i = 0; i < len; i++) {
				if (i in this) {
					fun.call(thisp, this[i], i, this);
				}
			}
		};
		var forEach = null;
	}
	
	// add or improve function.name method
	if (!Function.prototype.getName) {
		Function.prototype.getName = function getName(){
			if (this.name) {
				return this.name;
			}
			else {
				var str = this.toString();
				str = str.substring(0, str.indexOf('('));
				str = str.split(' ').join('');
				str = str.substring(8);
				if (!str) {
					return 'anonymous';
				}
				else {
					return str;
				}
			}
		};
		var getName = null;
	}
	
	// replace special characters with HTML entities for display in HTML
	if (!String.prototype.toHTML) {
		String.prototype.toHTML = function toHTML(){
			var h = this.replace(/\&/g, "&amp;");
			h = h.replace(/\</g, "&lt;");
			h = h.replace(/\>/g, "&gt;");
			h = h.replace(/\"/g, "&quot;");
			h = h.replace(/\'/g, "&#039;");
			return h;
		};
		var toHTML = null;
	}
	
	// format numbers as currency
	// @param(symbol) = appears in front of number, can include spaces, default "$"
	if (!Number.prototype.toCurrency) {
		Number.prototype.toCurrency = function toCurrency(symbol){
			var n = this.toString().replace(/\$|\,/g, '');
			if (isNaN(n)) {
				n = "0";
			}
			sign = (n == (n = Math.abs(n)));
			n = Math.floor(n * 100 + 0.50000000001);
			c = n % 100;
			n = Math.floor(n / 100).toString();
			if (c < 10) {
				c = "0" + c;
			}
			for (var i = 0; i < Math.floor((n.length - (1 + i)) / 3); i++) {
				n = n.substring(0, n.length - (4 * i + 3)) + ',' +
				n.substring(n.length - (4 * i + 3));
			}
			return (((sign) ? '' : '-') + (symbol ? symbol : '$') + n + '.' + c);
		};
		var toCurrency = null;
	}
	
})();



// returns the type of the object that is passed (more informative than 'typeof')
function typeOf(v){
	try {
		if (v === null) {
			return 'null';
		}
		if (v === undefined) {
			return 'undefined';
		}
		var oType = Object.prototype.toString.call(v).match(/\s(.+?)\]/)[1].toLowerCase();
		if (v.nodeType) {
			return 'dom';
		}
		if (oType === 'htmlcollection') {
			return 'nodelist';
		}
		if (oType === 'jsxmlhttprequest') {
			return 'xmlhttprequest';
		}
		if (oType === 'global' || oType === 'domwindow') {
			return 'window';
		}
		if (oType.indexOf('event')!== -1) {
			return 'event';
		}
		if (Object.prototype.toString.call(document).match(/\s(.+?)\]/)[1].toLowerCase() !== 'object') {
			return oType;
		}
		// only IE continues here
		if (oType === 'object') {
			if (v.nodeType) {
				return 'dom';
			}
			else 
				if (v.location) {
					return 'window';
				}
				else 
					if (typeof v.length === 'number' && typeof v.splice === 'function') {
						return 'array';
					}
					else 
						if (v.back && v.forward) {
							return 'history';
						}
						else 
							if (typeof v.length === 'number' && v.item && v[0] && v[0].nodeType) {
								return 'nodelist';
							}
							else 
								if (v.cssText !== undefined && v.rules) {
									return 'cssstylesheet';
								}
								else 
									if (v.cssText !== undefined) {
										return 'cssstyledeclaration';
									}
									else 
										if (v.colorDepth) {
											return 'screen';
										}
										else 
											if (v.userAgent) {
												return 'navigator';
											}
											else 
												if (v.reload && v.replace && v.assign) {
													return 'location';
												}
												else 
													if (v.getResponseHeader) {
														return 'xmlhttprequest';
													}
													else 
														if (v.type && typeof v.cancelBubble === 'boolean') {
															return 'event';
														}
			return 'object';
		}
		else {
			return oType;
		}
	}
	catch (e) {
		return 'default';
	}
}

// get an array of elements by class name
function getElementsByClass(name, node, tag){
	if (!node) {
		node = document;
	}
	try {
		return node.getElementsByClassName(name);
	} 
	catch (e) {
		var classElements = [];
		if (!tag) {
			tag = '*';
		}
		var els = node.getElementsByTagName(tag);
		var elsLen = els.length;
		var p = new RegExp("(^|\\s)" + name + "(\\s|$)");
		for (var i = 0, j = 0; i < elsLen; i++) {
			if (p.test(els[i].className)) {
				classElements[j] = els[i];
				j++;
			}
		}
		return classElements;
	}
}


/**
 * Utilities
 */
function disableSelection(target){
	if (typeof target === 'string') {
		target = document.getElementById(target);
	}
	if (typeof target.onselectstart != "undefined") {
		target.onselectstart = function(){
			return false;
		}; //IE route
	}
	else 
		if (typeof target.style.MozUserSelect != "undefined") {
			target.style.MozUserSelect = "none"; //Firefox route
			
		}
		else {
			target.onmousedown = function(){
				return false;
			}; //All other route (ie: Opera)
		}
	if (target.style.cursor === 'text') {
		target.style.cursor = "default";
	}
}





