// Chase Mathewson Javascript Library
// version 0.1
// http://chasemathewson.com

//FUNCTION AND ARGUMENT LIST
var get = {
	x : getElementX, //ELEMENT
	y : getElementY, //ELEMENT
	width : getElementWidth, //ELEMENT
	height : getElementHeight, //ELEMENT
	attribute : getElementAttribute, //ELEMENT, ATTRIBUTE
	opacity : getElementOpacity, //ELEMENT
	cookie : getCookie //NAME
}
var set = {
	x : setElementX, //ELEMENT, Y POSITION
	y : setElementY, //ELEMENT, X POSITION
	attribute : setElementAttribute, //ELEMENT, ATTRIBUTE, VALUE
	opacity : setElementOpacity, //ELEMENT, DECIMAL OPACITY VALUE
	listener : addListener, //ELEMENT, EVENT TYPE, FUNCTION TO EXECUTE, TRUE ON CAPTUREPHASE(OPTIONAL)
	cookie : setCookie //NAME, VALUE, DAYS TO LIVE
}
var remove = {
	element : removeElementFromDOM, //ELEMENT
	attribute : removeElementAttribute, //ELEMENT, REMOVING ATTRIBUTE
	listener : removeListener, //ELEMENT, EVENT TYPE, EXECUTING FUNCTION, TRUE ON CAPTUREPHASE(OPTIONAL)
	cookie : removeCookie //NAME
}
var mouse = {
	x : getMouseX,
	y : getMouseY,
	rightclick : getRightClick
}
var key = {
	code : getKey,
	character : getChar
}
var browser = {
	x : getPageScrollX,
	y : getPageScrollY,
	width : getBrowserWidth,
	height : getBrowserHeight,
	preload : imagePreload //IMAGE SOURCE
}
var client = {
	selected : getSelectedText,
	event : getEvent,
	target : getTarget,
	caller : getCaller,
	ajax : sendRequest, //REQUESTED URL
	deny : denyInput, //ELEMENT, STRING-ARRAY OF EVENTS TO DENY(OPTIONAL)
	allow : allowInput //ELEMENT, STRING-ARRAY OF EVENTS TO RELEASE(OPTIONAL)
}

//HTML OBJECT
var html = document.documentElement ? document.documentElement : document;

//FREEZE USER INPUT

//stops user from interacting with an element
function denyInput(element){
	if(!element) return false;
	var events = ['click','mousemove','mousedown','mouseup','keypress','keydown','keyup'];
	for(var i=0; i<events.length; i++){
		eval("element.on" + events[i] + " = lock");
	}
}
//releases a lockout on a selected element
function allowInput(element){
	if(!element) return false;
	var events = ['click','mousemove','mousedown','mouseup','keypress','keydown','keyup'];
	for(var i=0; i<events.length; i++){
		eval("element.on" + events[i] + " = null");
	}
}

function lock(){
	if(!e) var e = getEvent();
	var t = getTarget();
	e.cancelBubble = true;
	if(e.stopPropagation) e.stopPropagation();
	return false;
}

//GET FUNCTIONS
	//return an element's left position
	function getElementX(element){
		if(!element) return false;
		var elementX = 0;
		if(element.offsetParent){
			do{
				if(typeof(element.offsetLeft) == 'number') elementX += element.offsetLeft;
			}
			while(element = element.offsetParent)
		}
		return elementX;
	}
	//return an element's top position
	function getElementY(element){
		if(!element) return false;
		var elementY = 0;
		if(element.offsetParent){
			do{
				if(typeof(element.offsetTop) == 'number') elementY += element.offsetTop;
			}
			while (element = element.offsetParent)
		}
		return elementY;
	}
	//return an element's spatial width
	function getElementWidth(element){
		if(!element) return false;
		if(element.currentStyle) return element.offsetWidth;
		else if(window.getComputedStyle){
			var width = element.offsetWidth;
			var extraWidth = new Array('padding-left','padding-right','border-left-width','border-right-width');
			for(var i=0; i<extraWidth.length; i++){
				var css = document.defaultView.getComputedStyle(element,null).getPropertyValue(extraWidth.length[i]);
				if(typeof(css) == 'number') width += Math.round(parseFloat(css));
			}
			return width;
		}
		else return false;
	}
	//return an element's spatial height
	function getElementHeight(element){
		if(!element) return false;
		if(element.currentStyle) return element.offsetHeight;
		else if(window.getComputedStyle){
			var height = element.offsetHeight;
			var extraHeight = new Array('padding-top','padding-bottom','border-top-width','border-bottom-width');
			for(var i=0; i<extraHeight.length; i++){
				var css = document.defaultView.getComputedStyle(element,null).getPropertyValue(extraHeight.length[i]);
				if(typeof(css) == 'number') height += Math.round(parseFloat(css));
			}
			return height;
		}
		else return false;
	}
	//return an element's attribute value
	function getElementAttribute(element,attribute){
		if(element.attributes[attribute] == "") return false;
		else if(element.attributes[attribute]) return element.attributes[attribute].nodeValue;
		else return element.getAttribute(attribute);
	}
	//return an element's visual opacity (0.0 through 1.0)
	function getElementOpacity(element){
			var opacity = 1;
			if(element.style.opacity) opacity = element.style.opacity;
			else if(element.style.filter){
				opacity = opacity.style.filter;
				if(opacity.indexOf("opacity") >= 0) opacity = parseFloat(opacity) * 0.01;
			}
			return opacity;
	}

//SET AND REMOVE FUNCTIONS
	//remove an element from the DOM
	function removeElementFromDOM(element){
		if(!element) return false;
		element.parentNode.removeChild(element);
		return true;
	}
	
	//assign an element's attribute value
	function setElementAttribute(element,attribute,value){
		if (!element.attributes[attribute]){
			element.setAttribute(attribute,'');
			element.attributes[attribute] = '';
		}
		element.attributes[attribute].nodeValue = value;
	}
	//remove an element's attribute value
	function removeElementAttribute(element,attribute){
		if(element.attributes[attribute]) element.attributes[attribute].nodeValue = null;
		else element.removeAttribute(attribute);
	}
	//assign an element's left position
	function setElementX(element,x,flipflag){
		if(!element) return false;
		if(flipflag) element.style.right = x+ "px";
		else element.style.left = x+ "px";
	}
	//assign an element's top position
	function setElementY(element,y,flipflag){
		if(!element) return false;
		if(flipflag) element.style.bottom = y + "px";
		else element.style.top = y + "px";
	}
	//assign an element's visual opacity (0.0 through 1.0)
	function setElementOpacity(element,opacityLevel){
			element.style.opacity = opacityLevel;
			element.style.filter = "alpha(opacity=\"" + (opacityLevel*100) + "\")";
	}
	//adds an event listener to an element
	function addListener(element,type,functionCall,phase){
		if(!phase) phase = false;
		else phase = true;
		if(element.attachEvent){
			element['e'+type+functionCall] = functionCall;
			element[type+functionCall] = function(){element['e'+type+functionCall](window.event);}
			element.attachEvent('on'+type,element[type+functionCall]);
		}
		else element.addEventListener(type,functionCall,phase);
	}
	//removes an existing event listener from an element
	function removeListener(element,type,functionCall,phase){
		if(!phase) phase = false;
		else phase = true;
		if(element.detachEvent){
			element.detachEvent('on'+type,element[type+functionCall]);
			element[type+functionCall] = null;
		}
		else element.removeEventListener(type,functionCall,phase);
	}

//BROWSER AND CLIENT DATA
	//return position scrolled to from the left
	function getPageScrollX(){
		return (document.documentElement.scrollLeft ?
				document.documentElement.scrollLeft :
				document.body.scrollLeft)	
	}
	//return position scrolled to from the top
	function getPageScrollY(){
		return (document.documentElement.scrollTop ?
				document.documentElement.scrollTop :
				document.body.scrollTop)	
	}
	//return browser's viewable width
	function getBrowserWidth(){
		//if (window.innerWidth) return window.innerWidth; (This doesn't always account for the scrollbar.)
		if(document.documentElement.clientWidth) return document.documentElement.clientWidth;
		else if(document.body.clientWidth) return document.body.clientWidth;
		else if(document.body.offsetWidth) return document.body.offsetWidth;
		else return false;
	}
	//return browser's viewable height
	function getBrowserHeight(){
		if (window.innerHeight) return window.innerHeight;
		else if(document.documentElement.clientHeight) return document.documentElement.clientHeight;
		else if(document.body.clientHeight) return document.body.clientHeight;
		else if(document.body.offsetHeight) return document.body.offsetHeight;
		else return false;
	}
	//returns event object
	function getEvent(){
		if(window.event) return window.event;
		else if (arguments.callee) {
			var callerFunc = arguments.callee;
			while(callerFunc){
				for(var i=0; i<callerFunc.arguments.length; i++){
					if (callerFunc.arguments[i] instanceof Event) return callerFunc.arguments[i];
				}
				callerFunc = (callerFunc.caller ? callerFunc.caller : false)
			}
		}
		else return false;
	}
	//returns element that triggered the event
	function getTarget(){
		if(!e) var e = getEvent();
		return (e.target ?
				e.target :
				e.srcElement)
	}
	//returns element that is assigned the event 
	function getCaller(){
		if(!e) var e = getEvent();
		if(e.currentTarget) return e.currentTarget;
		var target = getTarget();
		var trigger = "on" + e.type;
		var caller = false;
		if (arguments.callee) {
			var callerFunc = arguments.callee;
			while(callerFunc){
				if(callerFunc.caller) callerFunc = callerFunc.caller;
				else {
					caller = callerFunc;
					callerFunc = false;
				}
			}
		}
		while(target){
			var evalTarget = eval("target." + trigger.toString());
			if (evalTarget){
				if(evalTarget == caller) return target;
			}
			target = (target.parentNode ? target.parentNode : false);
		}
		return false;
	}
	//returns selected text
	function getSelectedText(){
		var selection = false;
		if(window.getSelection){
			selection = window.getSelection();
		}
		else if (document.selection) selection = document.selection.createRange();
		if(selection.text) selection = selection.text;
		return selection;
	}
	//creates or sets a cookie
	function setCookie(name,value,days) {
		if(!days) var expiration = "";
		else {
			var date = new Date();
			date.setTime(date.getTime()+(days*24*60*60*1000));
			var expiration = "; expires="+date.toGMTString();
		}
		var cookie = name + "=" + value + expiration + "; path=/";
		document.cookie = cookie;
	}
	//get a cookie
	function getCookie(name){
		var varibaleName = name + "=";
		var cookieCrumbs = document.cookie.split(';');
		for(var i=0;i < cookieCrumbs.length;i++){
			var crumb = cookieCrumbs[i];
			while (crumb.charAt(0)==' ') crumb = crumb.substring(1,crumb.length);
			if (crumb.indexOf(varibaleName) == 0) return crumb.substring(varibaleName.length,crumb.length);
		}
		return false;
	}
	//removes a cookie
	function removeCookie(name) {
		setCookie(name,"",-1);
	}
	//PPK's Ajax Handler
	function sendRequest(url,callback,postData) {
		var XMLHttpFactories = [
			function(){ return new XMLHttpRequest() },
			function(){ return new ActiveXObject("Msxml2.XMLHTTP") },
			function(){ return new ActiveXObject("Msxml3.XMLHTTP") },
			function(){ return new ActiveXObject("Microsoft.XMLHTTP") }
		];
		function createXMLHTTPObject(){
			var xmlhttp = false;
			for (var i=0; i<XMLHttpFactories.length; i++){
				try {
					xmlhttp = XMLHttpFactories[i]();
				}
				catch (e) {
					continue;
				}
				break;
			}
			return xmlhttp;
		}
		var req = createXMLHTTPObject();
		if (!req) return;
		var method = (postData) ? "POST" : "GET";
		req.open(method,url,true);
		req.setRequestHeader('User-Agent','XMLHTTP/1.0');
		if (postData)
			req.setRequestHeader('Content-type','application/x-www-form-urlencoded');
		req.onreadystatechange = function () {
			if (req.readyState != 4) return;
			if (req.status != 200 && req.status != 304) {
				//alert('HTTP error ' + req.status);
				return;
			}
			callback(req);
		}
		if (req.readyState == 4) return;
		req.send(postData);
	}
	//preloads an image
	function imagePreload(source){
		if(!preloadArray) preloadArray = new Array();
		if(!preloadCounter) preloadCounter = 0;
		preloadArray[preloadCounter] = new Image();
		preloadArray[preloadCounter].src = source;
		preloadCounter =+ 1;
	}

//MOUSE DATA
	//returns mouse's left position
	function getMouseX(){
		if (!e) var e = getEvent();
		if (e.pageX){
			if(e.pageX != getPageScrollX()) return e.pageX;
			else return false;
		}
		else if(e.clientX) return e.clientX + getPageScrollX();
		else return false;
	}
	//returns mouse's top position
	function getMouseY(){
		if (!e) var e = getEvent();
		if (e.pageY){
			if(e.pageY != getPageScrollY()) return e.pageY;
			else return false;
		}
		else if(e.clientY) return e.clientY + getPageScrollY();
		else return false;
	}
	//returns if right mouse button was clicked
	function getRightClick(){
		if (!e) var e = getEvent();
		if(e.button){
			if(e.button == 2) return true;
			else return false;
		}
		else if(e.which){
			if (e.which == 3) return true;
			else return false;
		}
		else return false;
	}

//KEYSTROKE DATA
	//returns keycode for pressed key
	function getKey(){
		if(!e) var e = getEvent();
		if (e.keyCode || e.which) return (e.keyCode ? e.keyCode : e.which);
		else return false;
	}
	//returns key character from pressed key
	function getChar(){
		if(!e) var e = getEvent();
		charCode = getKey();
		return String.fromCharCode(charCode);
	}

//JAVASCRIPTS ADDITIONS
	//check for a variables existance
	function isset(variable){
		if(typeof( window[variable] ) != "undefined") return true;
		else return false;
	}
	
//PROTOTYPE ADDITIONS
	//format to decimals
	Number.prototype.toDecimals=function(n){
		n=(isNaN(n))?
			2:
			n;
		var
			nT=Math.pow(10,n);
		function pad(s){
				s=s||'.';
				return (s.length>n)?
					s:
					pad(s+'0');
		}
		return (isNaN(this))?
			this:
			(new String(
				Math.round(this*nT)/nT
			)).replace(/(\.\d*)?$/,pad);
	}
	//adds values to the end of an array, then returns the new length
	function Array_push(){
		var A_p = 0
		for (A_p = 0; A_p < arguments.length; A_p++) {
			this[this.length] = arguments[A_p]
		}
		return this.length
	}
	if (typeof Array.prototype.push == "undefined") {
		Array.prototype.push = Array_push
	}
	//returns the first value of an array and then removes that value from the array
	function Array_shift() {
		var A_s = 0
		var response = this[0]
		for (A_s = 0; A_s < this.length-1; A_s++) {
			this[A_s] = this[A_s + 1]
		}
		this.length--
		return response
	}
	if (typeof Array.prototype.shift == "undefined") {
		Array.prototype.shift = Array_shift
	}
