// JavaScript Document
// could use jQuery, jsCore or ExtJS
// @author shad claiborne <sclaiborne@outreachservices.com
// @status I am still working on this, please do not modify
// ajax stuff
var xhrpending = [],
	xhrPollTick = 500,
	xhrPollInt = 0;
	
// get cross-browser xhr object... if there is one

function xhr() {
	if ( window.XMLHttpRequest ) {
		return new XMLHttpRequest();
	} else if ( window.ActiveXObject ) {
		return new ActiveXObject( "Microsoft.XMLHTTP" );
	}
	return null;
}

// well keep polling until we get a valid request objects AND/OR there are not more
// items pending
function xhrPoll() {
	var request = xhr(),
		obj;

	if ( request ) {
		do {
			obj = xhrpending[ 0 ];
			xhrpending.splice( 0, 1 ); // remove the object complete form the pending list (i.e xhrpending.length = xhrpending.length - 1)
			request.callback = obj.callback;
			request.attachment = obj.attachment;
			request.open( obj.method, obj.url, obj.async );
			request.onreadystatechange = xhronreadystatechange;
			request.send( obj.data );

			if ( !xhrpending.length ) {
				clearInterval( xhrPollInt );
				xhrPollInt = 0;
			}

			request = xhr();
		} while ( request );
	}
}

// convenient method to get submit a new xhr request - cross browser and handles xhr limitations as well... well one of them
function newXhr( method, url, async, data, callback, attachment ) {
	var request = xhr();
	
	if ( !request ) {
		xhrpending[ xhrpending.length ] = { "method": method, "url": url, "data": data, "async": async, "callback": callback, "attachment": attachment };

		if ( !xhrPollInt ) {
			xhrPollInt = setInterval( xhrPoll, xhrPollTick );
		}
	} else {
		request.callback = callback;
		request.attachment = attachment;
		request.open( method, url, async );
		if (method.toLowerCase() == "post") {
			request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		}
		request.onreadystatechange = xhronreadystatechange;
		request.send( data );
	}
	return request;
}

// xhr "readystatechange" function
function xhronreadystatechange() {
	if ( this.readyState === 4 ) {
		this.callback( this );
	}
}

// browser stuff
function isIE() {
	// note: most regex stuff is sluggish
	if ( isUndefined( window.isIEBrowser ) ) {
		window.isIEBrowser = /MSIE/.test( navigator.userAgent );
	}
	return window.isIEBrowser;
}

function isFirefox() {
	// note: most regex stuff is sluggish
	if ( isUndefined( window.isFirefoxBrowser ) ) {
		window.isFirefoxBrowser = /Firefox/.test( navigator.userAgent );
	}
	return window.isFirefoxBrowser;
}

function isChrome() {
	// note: most regex stuff is sluggish
	if ( isUndefined( window.isChromeBrowser ) ) {
		window.isChromeBrowser = /Chrome/.test( navigator.userAgent );
	}

	return window.isChromeBrowser;
}

function isOpera() {
	// note: most regex stuff is sluggish
	if ( isUndefined( window.isOperaBrowser ) ) {
		window.isOperaBrowser = /Opera/.test( navigator.userAgent );
	}

	return window.isOperaBrowser;
}

function getBrowser() {
			if ( isOpera() ) {
				return "Opera";
			} else if ( isFirefox() ) {
				return "Firefox";
			} else if ( isIE() ) {
				return "IE";
			} else if ( isChrome() ) {
				return "Chrome";
			}
			return "unknown";
}

// The following I copied from Quirksmode instead of having to read the browser specific
// docs myself.
function getDocHeight() {
    var D = document;
	
    return Math.max(
        Math.max( D.body.scrollHeight, D.documentElement.scrollHeight ),
        Math.max( D.body.offsetHeight, D.documentElement.offsetHeight ),
        Math.max( D.body.clientHeight, D.documentElement.clientHeight )
    );
}

function getDocWidth() {
    var D = document;

    return Math.max(
        Math.max( D.body.scrollWidth, D.documentElement.scrollWidth ),
        Math.max( D.body.offsetWidth, D.documentElement.offsetWidth ),
        Math.max( D.body.clientWidth, D.documentElement.clientWidth )
    );
}

window.size = function() {
	var w = 0;
	var h = 0;

	if(!window.innerWidth) {
		if(!(document.documentElement.clientWidth == 0)) {
			w = document.documentElement.clientWidth;
			h = document.documentElement.clientHeight;
		} else {
			w = document.body.clientWidth;
			h = document.body.clientHeight;
		}
	} else {
		w = window.innerWidth;
		h = window.innerHeight;
	}
	
	return [ w, h ];
}

function getDocDim() {
	return [ getDocWidth(), getDocHeight() ];
}

// dom stuff
function isElNode( el ) {
	return ( el && el.nodeType === 1 ) ? 1 : 0;
}

function isDocumentNode( el ) {
	return ( el && el.nodeType === 9 ) ? 1 : 0;
}

function appendChild( par, child ) {
	if ( isElNode( par ) && child.nodeType ) {
		return par.appendChild( child );
	}
	return null;
}

function removeChild( par, child ) {
	if ( isElNode( par ) && child.nodeType ) {
		return par.removeChild( child );
	}

	return null;
}

function createElement( tag ) {
	return document.createElement( tag );
}

function createTextNode( text ) {
	return document.createTextNode( text );
}

function setAttribute( el, attr, value ) {
	if ( isElNode( el ) ) {
		el.setAttribute( attr, value );
	}
}

function getAttribute( el, attr ) {
	if ( isElNode( el ) ) {
		return el.getAttribute( attr );
	}

	return null;
}

function attribute( el, attr, value ) {
	if ( isUndefined( value ) ) {
		return getAttribute( el, attr );
	} else {
		setAttribute( el, attr, value );
	}
}

function parentNode( el ) {
	return isElNode( el ) ? el.parentNode : null;
}

function parentWithClass( el, cname ) {
	var par = null,
		classn = "";
	
	if ( isElNode( el ) ) {
		par = parentNode( el );
		
		while ( par && par.className.indexOf( cname ) < 0 ) {
			par = parentNode( par );
		}
	}
	return par;
}

// setClass, unsetClass and classFn only handle singular classes
function setClass( el, className ) {
	if ( isElNode( el ) ) {
		el.className = className;
	}
}

function unsetClass( el, className ) {
	if ( isElNode( el ) ) {
		el.className = '';
	}
}

function classFn( el, className ) {
	if ( isElNode( el ) ) {
		if ( isUndefined( className ) ) {
			return el.className;
		} else {
			setClass( el, className );
		}
	}
}

function setCss( el, style, value ) {
	if ( isElNode( el ) ) {
		el.style[ style ] = value;
	}
}

function getCss( el, style ) {
	if ( isElNode( el ) ) {
		if ( el.currentStyle ) {
			return el.currentStyle[ style ];
		} else if (window.getComputedStyle) {
			return document.defaultView.getComputedStyle( el, null ).getPropertyValue( style );
		}
	}
	
	return null;
}

function css( el, style, value ) {
	if ( style ) {
		if ( value ) {
			setCss( el, style, value );
		} else {
			return getCss( el, style );
		}
	}
}

// will modify later
function html( el, html ) {
	if ( isElNode( el ) ) {
		el.innerHTML = html;
	}
}

// get's the node name 

function nodeName( el ) {
	return ( isElNode( el ) ) ? el.nodeName : '';
}

// gets all child element nodes
function childNodes( el ) {
	var cNodes,
	clen,
	i,
	children = [],
	node;

	if ( isElNode( el ) || isDocumentNode( el ) ) {
		cNodes = el.childNodes;
		clen = cNodes.length;

		for ( i = 0; i < clen; ++i ) {
			node = cNodes[ i ];
			
			if ( isElNode( node ) ) {
				children[ children.length ] = node;
			}
		}
	}

	return children;
}

function removeAllChildren( el ) {
	if ( isElNode( el ) ) {
		while ( el.childNodes[ 0 ] ) {
			el.removeChild( el.childNodes[ 0 ] );
		}
	}
}

// event stuff
// cross-browser - get even obj
function getEventObj( e ) {
	return ( e || window.event );
}

// cross-browser - get the current event target
function getEventTar( e ) {
	var ev = getEventObj( e );
	return ( ev.target || ev.srcElement );
}

// cancels an event
function cancelEvent( e ) {
	var ev = getEventObj( e );

	// let's just use stopPropagation only :)
	if ( ev.stopPropagation ) {
		ev.stopPropagation();
	}

	ev.cancelBubble = true;
	ev.returnValue = false;
}

// Hooks a function to an element's events
Function.prototype.hook = function( type, el, capture, level ) {
	if ( isElNode( el ) ) {
		if ( level === 0 ) {
			el[ "on" + type ] = this;
		} else {
			if ( el.addEventListener ) {
				el.addEventListener( type, this, capture );
			} else if ( el.attachEvent ) {
				el.attachEvent( "on" + type, this );
			} else {
				// synthetic events not implemented
			}
		}
	}
};

// Unhooks a function to an element's events
Function.prototype.unhook = function( type, el, capture, level ) {
	if ( isElNode( el ) )  {
		if ( level === 0 ) {
			delete el[ "on" + type ];
		} else {
			if ( el.removeEventListener ) {
				el.removeEventListener( type, this, capture );
			} else if ( el.detachEvent ) {
				el.detachEvent( "on" + type, this );
			} else {
				// synthetic events not implemented
			}
		}
	}
};

// String utilities - cross browser
// trim left function - does not use regx
String.prototype.triml = function() {
	var ret = this;

	while ( ret.charAt( 0 ) == ' ' ) {
		ret = ret.substring( 1 );

	}
	
	return ret;

};

// trim right function - does not use regx
String.prototype.trimr = function() {
	var ret = this;

	while ( ret.charAt( ret.length ) == ' ' ) {
		ret = ret.substring( 0, ret.length - 1 );
	}

	return ret;

};

// trim function - does not use regx
String.prototype.trim = function() {
	return this.triml().trimr();
};

// checks a regex against all in an array
String.prototype.has = function( arr ) {
	var matches = [],
		alen;

	if ( isArray( arr ) ) {
		alen = arr.length;
		while ( alen-- ) {
			if ( this.indexOf( arr[ alen ] ) >= 0 ) {
				matches[ matches.length ] = arr[ alen ];
			}
		}
	}

	return matches;
};

// Array utilities - cross browser
Array.prototype.pushit = function( pitem ) {
	this[ this.length ] = pitem;
};

// pushes the item at the post, as an alternative to splice
Array.prototype.pushr = function( pitem, pos ) {
	var arr = this,
	tlen = arr.length;

	if ( isNumber( pos ) && tlen >= pos ) {
		while ( tlen > pos ) {
			this[ tlen ] = arr[ --tlen ];
		}
		
		this[ tlen ] = pitem;
	}
};

// eventuall want to make shift variable
Array.prototype.shift = function() {
	return this.splice( 0, 1 )[ 0 ];
};

// Pop's an item
Array.prototype.pop = function() {
	return this.splice( 0, 1 )[ 0 ];
};

// get the zero based length (i.e starting from zero instead of 1) of the array
Array.prototype.zeroLength = function() {
	return ( this.length === 0 ) ? 0 : this.length - 1;
};

// method to get the index of an item or -1 if it is not found
Array.prototype.index = function( fitem ) {
	var arr = this,
	alen = arr.length;
	
	while ( alen-- ) {
		if ( arr[ alen ] == fitem ) {
			return alen;
		}
	}

	return -1;
};

Array.prototype.each = function( func ) {
	var arr = this,
		alen = arr.length;
		
	while ( alen-- ) {
		func( arr[ alen ] );
	}
};

// utility functions
function isUndefined( obj ) {
	return typeof obj == "undefined" || typeof obj === undefined;
}

function isNumber( obj ) {
	return ( typeof obj === "number" );
}

function isFunction( obj ) {
	return typeof obj === "function";
}

function isObject( obj ) {
	return typeof obj === "object";
}

function isArray( obj ) {
	return !isUndefined( obj.length );
}

function returnFalse() {
	return false;
}

