// ADD CLASSES TO OBJECTS
function addClassName(element, className){
	if (hasClassName(element, className)) { return false; }
	if (!element.className) { element.className = className; }
	else { element.className += ' '+className; }
	return true;
}

// REMOVE CLASSES FROM OBJECTS
function removeClassName(element, className){
	if (!hasClassName(element, className)) { return false; }
	var classNames = element.className.split(' ');
	var newClassNames = [];
	for (var a=0; a<classNames.length; a++){
		if (classNames[a] != className) { newClassNames[newClassNames.length] = classNames[a]; }
	}
	element.className = newClassNames.join(' ');
	return true;
}

// TEST FOR CLASS NAME
function hasClassName(element, className){
	var exp = new RegExp("(^|\\s)"+className+"($|\\s)");
	return (element.className && exp.exec(element.className))?true:false;
}

// TEST FOR CLASS NAME BY PATTERN
function getClassNameLike(element, pattern){
	var classNames = element.className.split(' ');
	for (var a=0; a<classNames.length; a++){
		if (classNames[a].match(pattern)) { return classNames[a]; }
	}
	return '';
}

// TOGGLE CLASS NAME
function toggleClassName(element, className) {
	if (hasClassName(element, className)) { removeClassName(element, className); }
	else { addClassName(element, className); }
}

// FIND PREVIOUS ELEMENT
function prevElem(el) {
	var prev = el.previousSibling;
	for (var a=0; a<1000; a++) {
		if (!prev) { return null; }
		if (prev.nodeType==1) { return prev; }
		prev = prev.previousSibling;
	}
	throw "couldn't find previous sibling";
}

// FIND NEXT ELEMENT
function nextElem(el) {
	var next = el.nextSibling;
	for (var a=0; a<1000; a++) {
		if (!next) { return null; }
		if (next.nodeType==1) { return next; }
		next = next.nextSibling;
	}
	throw "couldn't find next sibling";
}

// IS OBJECT AN ARRAY?
function isArray(obj) {   
    return obj && typeof obj.unshift != 'undefined';
}

// SHORTCUT FOR BUILDING ELEMENTS
function elem(name, atts, content) {
	// name: a tag name, with optional class or id: 'div', 'div.foo', 'div#bar', 'div.foo#bar', 'div#bar.foo'
	// atts: optional. object where keys=attribute names, values=attribute values: {'href':'page.html','target':'_blank'}
	// content: optional. either a string, or an element, or an arry of strings or elements
	if (name.indexOf('.') + name.indexOf('#') > -2) {
		var className = (name.indexOf('.') > -1) ? name.replace(/^.*\.([^\.#]*).*$/,"$1") : "";
		var id = (name.indexOf('#') > -1) ? name.replace(/^.*#([^\.#]*).*$/,"$1") : "";
		name = name.replace(/^([^\.#]*).*$/,'$1');
	}
	var e = document.createElement(name);
	if (className) { e.className = className; }
	if (id) { e.id = id; }
	if (atts) {
		for (key in atts) {
			// setAttribute() has shaky support, try direct methods first
			if (key == 'class') { e.className = atts[key]; }
			else if (key == 'id') { e.id = atts[key]; }
			else if (key == 'href') { e.href = atts[key]; }
			else if (key == 'action') { e.action = atts[key]; }
			else if (key == 'method') { e.method = atts[key]; }
			else if (key == 'title') { e.title = atts[key]; }
			else if (key == 'alt') { e.alt = atts[key]; }
			else if (key == 'border') { e.border = atts[key]; }
			else if (key == 'caption') { e.caption = atts[key]; }
			else if (key == 'cellspacing') { e.cellspacing = atts[key]; }
			else if (key == 'for') { e.htmlFor = atts[key]; }
			else { e.setAttribute(key, atts[key]); }
		}
	}
	if (content) {
		if (!isArray(content)) { // it's not an array
			content = [content];
		}
		for (var a=0; a<content.length; a++) {
			if (typeof content[a] == 'string') {
				e.appendChild(document.createTextNode(content[a]));
			} else {
				e.appendChild(content[a]);
			}
		}
	}
	if (name.toLowerCase() == 'img' && !e.alt) { e.alt = ''; }
	return e;
}

// GRAB JUST THE TEXTUAL DATA OF AN ELEMENT
function elemText(el) {
	// <a id="foo" href="page.html">click <b>here</b></a>
	// elemText(document.getElementById('foo')) == "click here"
	// warning: recurses through *all* descendants of el!
	var chlds = el.childNodes;
	var result = '';
	for (var a=0; a<chlds.length; a++) {
		if (3 == chlds[a].nodeType) {
			result += chlds[a].data;
		} else if (1 == chlds[a].nodeType) {
			result += elemText(chlds[a]);
		}
	}
	return result;
}

// BUILD AN ELEMENT FROM AN HTML TEXT BLOB
function getElementFromString(textBlob, tagName, id) {
	var container = document.createElement('div');
	container.innerHTML = textBlob;
	var tags = container.getElementsByTagName(tagName);
	for (var a=0; a<tags.length; a++){
		if (tags[a].id == id) { return tags[a]; }
	}
	return null;
}

// GENERIC XML HTTP REQUEST
function xhr(url, successFunc, failFunc, obj, postData){
	var http_request = false;
	if (window.XMLHttpRequest) {
		http_request = new XMLHttpRequest();
	}else if (window.ActiveXObject) { // IE
		try { http_request = new ActiveXObject("Msxml2.XMLHTTP"); }
		catch(e){
			try{ http_request = new ActiveXObject("Msxml3.XMLHTTP"); }
			catch(e){
				try{ http_request = new ActiveXObject("Microsoft.XMLHTTP"); }
				catch(e){}
			}
		}
	}
	if (!http_request) { return false; }
	if (!postData) { postData = null; }
	var method = (postData) ? "POST" : "GET";
	http_request.open(method, url, true);
	http_request.setRequestHeader('User-Agent','XMLHTTP/1.0');
	if (postData) { http_request.setRequestHeader('Content-type','application/x-www-form-urlencoded'); }
	http_request.onreadystatechange = function() {
		if (http_request.readyState == 4) {
			if (http_request.status == 200) {
				successFunc(http_request.responseText, obj);
   			}else{
   				failFunc(http_request.status, obj);
  			}
		}
	};
	http_request.send(postData);
}

// GET DATA FROM A FORM FOR XHR
function getFormData(form) {
	var result = [];
	var allChildren = form.getElementsByTagName("*");
	for (var a=0; a<allChildren.length; a++) {
		var el = allChildren[a];
		var tagName = el.tagName.toLowerCase();
		var name = "";
		var val = "";
		if (tagName == 'input' || tagName == 'textarea') {
			name = encodeURIComponent(el.name);
			val = encodeURIComponent(el.value);
		} else if (tagName == 'select') {
			name = encodeURIComponent(el.name);
			val = encodeURIComponent(el.options[el.options.selectedIndex].value);
		}
		if (name || val) { result[result.length] = name+"="+val; }
	}
	return result.join("&");
}

/*	
	AddEvent()
	See <http://www.dustindiaz.com/rock-solid-addevent/> for more information.
	This software is licensed under the CC-GNU LGPL <http://creativecommons.org/licenses/LGPL/2.1/>
*/

//ADD EVENT
function addEvent( obj, type, fn ) {
	if (obj.addEventListener) {
		obj.addEventListener( type, fn, false );
		EventCache.add(obj, type, fn);
	}
	else if (obj.attachEvent) {
		obj["e"+type+fn] = fn;
		obj[type+fn] = function() { obj["e"+type+fn]( window.event ); }
		obj.attachEvent( "on"+type, obj[type+fn] );
		EventCache.add(obj, type, fn);
	}
	else {
		obj["on"+type] = obj["e"+type+fn];
	}
}

/*	
	EventCache Version 1.0
	Copyright 2005 Mark Wubben
	Provides a way for automagically removing events from nodes and thus preventing memory leakage.
	See <http://novemberborn.net/javascript/event-cache> for more information.
	This software is licensed under the CC-GNU LGPL <http://creativecommons.org/licenses/LGPL/2.1/>
*/

//EVENT CACHE
var EventCache = function(){
	var listEvents = [];
	return {
		listEvents : listEvents,
		add : function(node, sEventName, fHandler){
			listEvents.push(arguments);
		},
		flush : function(){
			var i, item;
			for(i = listEvents.length - 1; i >= 0; i = i - 1){
				item = listEvents[i];
				if(item[0].removeEventListener){
					item[0].removeEventListener(item[1], item[2], item[3]);
				};
				if(item[1].substring(0, 2) != "on"){
					item[1] = "on" + item[1];
				};
				if(item[0].detachEvent){
					item[0].detachEvent(item[1], item[2]);
				};
				item[0][item[1]] = null;
			};
		}
	};
}();

addEvent(window,'unload',EventCache.flush);

// CANCEL DEFAULT EVENT
function cancelDefault(e){
	if (lteie6 || lteie7) {
		e.returnValue=false;
	}else{
		e.preventDefault();
	}
}

/**
 registerSetupFunction(selector, function, onceOnly);
 @param selector: a string like 'p', 'div.entry', 'form#comment-form', or 'element[attribute=regexp]'
 @param function: a function that accepts a DOM object and performs arbitrary initialization on it 
 @param onceOnly: optional boolean that defaults to false. if true, the function only ever runs once

 examples:
 registerSetupFunction(".entry",function(el){...}); anything with class="entry"
 registerSetupFunction("div.entry",function(el){...}); divs with class="entry"
 registerSetupFunction("div#content",function(el){...}); the div with id="content"
 registerSetupFunction("h1",function(el){...},true); only the first h1 on the page
 registerSetupFunction("img[src=\\.png$]",function(el){...},true); all .png images

 usage:
 registerSetupFunction() should be called as many times as needed, but before the 
 onload event, since it builds up a queue of tasks to be run onload, at which time 
 runSetupFunctions() runs. if an XMLHttpRequest dumps new content onto the page, 
 runSetupFunctions(el) can be called again, passing it the element containing the 
 new content.
*/
(function(){

	var setupQueue={};

	window.registerSetupFunction=function(selector, setup, firstTimeOnly){
		firstTimeOnly=(firstTimeOnly)?true:false;
		var sq=setupQueue;
		var matches=selector.match(/^([a-z][a-z0-9_-]*)?(((#|\.)([a-z][a-z0-9_-]*))|(\[([a-z][a-z0-9_-]*)=(.+)\]))?$/i);
		if(!matches){throw 'invalid selector: "'+selector+'"';}
		var tagName=matches[1];
		if(!tagName){tagName='*';}
		var useId=(matches[4]=='#')?true:false;
		var classOrId=matches[5];
		var className=(useId)?'':classOrId;
		var id=(useId)?classOrId:'';
		var regObj={
			'className':className,
			'id':id,
			'setup':setup,
			'ran':false,
			'firstTimeOnly':(firstTimeOnly || useId),
			'attName':matches[7],
			'attPatt':new RegExp(matches[8])
		};
		if(!sq[tagName]){sq[tagName]=[regObj];}
		else{sq[tagName][sq[tagName].length]=regObj;}
	}

	function runIt(el, regObj){
		if(regObj.id){
			if(regObj.id == el.id){
				regObj.setup(el);
				regObj.ran=true;
			}
		}else if(regObj.attName){
			if(regObj.attName=='for'){regObj.attName='htmlFor';}
			var attVal=el[regObj.attName];
			if(!attVal){attVal=el.getAttribute(regObj.attName);}
			if(attVal && attVal.match(regObj.attPatt)){
				regObj.setup(el);
				regObj.ran=true;
			}
		}else{
			if((regObj.className && hasClassName(el,regObj.className)) || !regObj.className){
				regObj.setup(el);
				regObj.ran=true;
			}
		}
	}

	window.runSetupFunctions=function(el, cancelIfAlreadyRan){
		if (typeof el.setupFunctionsAlreadyRanHere != 'undefined' && el.setupFunctionsAlreadyRanHere && cancelIfAlreadyRan) { return; }
		var doc=(el)?el:document;
		var sq=setupQueue;
		var els=doc.getElementsByTagName('*');
		var len=els.length;
		for(var a=0;a<len;a++){
			var elmt=els[a];
			var lcNodeName=elmt.nodeName.toLowerCase();
			var regObjArrayAll=sq['*'];
			var regObjArrayTag=sq[lcNodeName];
			if(regObjArrayAll){
				for(var b=0;b<regObjArrayAll.length;b++){
					var regObj=regObjArrayAll[b];
					if(regObj.firstTimeOnly && regObj.ran){continue;}
					runIt(elmt, regObj);
				}
			}
			if(regObjArrayTag){
				for(var b=0;b<regObjArrayTag.length;b++){
					var regObj=regObjArrayTag[b];
					if(regObj.firstTimeOnly && regObj.ran){continue;}
					runIt(elmt, regObj);
				}
			}
		}
		el.setupFunctionsAlreadyRanHere = true;
	}

	addEvent(window, 'load', function(){window.runSetupFunctions(document.body, true);});

})();


