/*
	Developed by Robert Nyman
	Code/licensing: http://code.google.com/p/dlite/
	Documentation: http://www.robertnyman.com/dlite
	Version 1.0
*/	
var dLite = function () {
	var isIE = /*@cc_on!@*/false;
	var uniqueHandlerId = 0;
	var DOMLoaded = false;
	var DOMLoadTimer = null;
	var functionsToCall = [];
	var addedStrings = {};
	var execFunctions = function () {
		for (var i=0, il=functionsToCall.length; i<il; i++) {
			try {
				functionsToCall[i]();
			}
			catch (e) {
				// Prevent possible reference errors
			}
		}
		functionsToCall = [];
	};
	var DOMHasLoaded = function () {
		if (DOMLoaded) {
			return;
		}
		DOMLoaded = true;
		execFunctions();
	};
	return {
		init : function () {
			window.elm = window.elm || this.elm;
			window.elmsByClass = window.elmsByClass || this.elmsByClass;
			window.addClass = window.addClass || this.addClass;
			window.removeClass = window.removeClass || this.removeClass;
			window.addEvent = window.addEvent || this.addEvent;
			window.removeEvent = window.removeEvent || this.removeEvent;
			window.stopDefault = window.stopDefault || this.stopDefault;
			window.cancelBubbling = window.cancelBubbling || this.cancelBubbling;
			window.DOMReady = window.DOMReady || this.DOMReady;
			
			if (document.addEventListener) {
				document.addEventListener("DOMContentLoaded", DOMHasLoaded, false);
			}
			if (isIE) {
				if (document.getElementById) {
					document.write("<script id=\"ieScriptLoad\" defer src=\"//:\"><\/script>");
					document.getElementById("ieScriptLoad").onreadystatechange = function() {
						if (this.readyState === "complete") {
							DOMHasLoaded.call(this);
						}
					};
				}
			}
			if (/KHTML|WebKit|iCab/i.test(navigator.userAgent)) {
				DOMLoadTimer = setInterval(function () {
					if (/loaded|complete/i.test(document.readyState)) {
						DOMHasLoaded.call(this);
						clearInterval(DOMLoadTimer);
					}
				}, 10);
			}
			window.onload = DOMHasLoaded;
		},
		
		elm : function (id) {
			return document.getElementById(id);
		},
		
		elmsByClass : function (className, tag, elm){
			if (document.getElementsByClassName) {
				this.elmsByClass = function (className, tag, elm) {
					elm = elm || document;
					var elements = elm.getElementsByClassName(className),
						nodeName = (tag)? new RegExp("\\b" + tag + "\\b", "i") : null,
						returnElements = [],
						current;
					for(var i=0, il=elements.length; i<il; i+=1){
						current = elements[i];
						if(!nodeName || nodeName.test(current.nodeName)) {
							returnElements.push(current);
						}
					}
					return returnElements;
				};
			}
			else if (document.evaluate) {
				this.elmsByClass = function (className, tag, elm) {
					tag = tag || "*";
					elm = elm || document;
					var classes = className.split(" "),
						classesToCheck = "",
						xhtmlNamespace = "../../../../../www.w3.org/1999/xhtml",
						namespaceResolver = (document.documentElement.namespaceURI === xhtmlNamespace)? xhtmlNamespace : null,
						returnElements = [],
						elements,
						node;
					for(var j=0, jl=classes.length; j<jl; j+=1){
						classesToCheck += "[contains(concat(' ', @class, ' '), ' " + classes[j] + " ')]";
					}
					try	{
						elements = document.evaluate(".//" + tag + classesToCheck, elm, namespaceResolver, 0, null);
					}
					catch (e) {
						elements = document.evaluate(".//" + tag + classesToCheck, elm, null, 0, null);
					}
					while ((node = elements.iterateNext())) {
						returnElements.push(node);
					}
					return returnElements;
				};
			}
			else {
				this.elmsByClass = function (className, tag, elm) {
					tag = tag || "*";
					elm = elm || document;
					var classes = className.split(" "),
						classesToCheck = [],
						elements = (tag === "*" && elm.all)? elm.all : elm.getElementsByTagName(tag),
						current,
						returnElements = [],
						match;
					for(var k=0, kl=classes.length; k<kl; k+=1){
						classesToCheck.push(new RegExp("(^|\\s)" + classes[k] + "(\\s|$)"));
					}
					for(var l=0, ll=elements.length; l<ll; l+=1){
						current = elements[l];
						match = false;
						for(var m=0, ml=classesToCheck.length; m<ml; m+=1){
							match = classesToCheck[m].test(current.className);
							if (!match) {
								break;
							}
						}
						if (match) {
							returnElements.push(current);
						}
					}
					return returnElements;
				};
			}
			return this.elmsByClass(className, tag, elm);
		},
		
		addClass : function (elm, className) {
			var currentClass = elm.className;
			if (!new RegExp(("(^|\\s)" + className + "(\\s|$)"), "i").test(currentClass)) {
				elm.className = currentClass + (currentClass.length? " " : "") + className;
			}
		},

		removeClass : function (elm, className) {
			var classToRemove = new RegExp(("(^|\\s)" + className + "(\\s|$)"), "i");
			elm.className = elm.className.replace(classToRemove, function (match) {
				var retVal = "";
				if (new RegExp("^\\s+.*\\s+$").test(match)) {
					retVal = match.replace(/(\s+).+/, "$1");
				}
				return retVal;
			}).replace(/^\s+|\s+$/g, "");
		},
		
		addEvent : function (elm, evt, func) {
			if (document.addEventListener) {
				this.addEvent = function (elm, evt, func) {
					elm.addEventListener(evt, func, false);
				};
			}
			else {
				this.addEvent = function (elm, evt, func) {
					if (!elm.uniqueHandlerId) {
						elm.uniqueHandlerId = uniqueHandlerId++;
					}
					var alreadyExists = false;
					if (func.attachedElements && func.attachedElements[evt + elm.uniqueHandlerId]) {
						alreadyExists = true;
					}
					if (!alreadyExists) {
						if (!elm.events) {
							elm.events = {};
						}
						if (!elm.events[evt]) {
							elm.events[evt] = [];
							var existingEvent = elm["on" + evt];
							if (existingEvent) {
								elm.events[evt].push(existingEvent);
							}
						}
						elm.events[evt].push(func);
						elm["on" + evt] = dLite.handleEvent;
						
						if (!func.attachedElements) {
							func.attachedElements = {};
						}
						func.attachedElements[evt + elm.uniqueHandlerId] = true;
					}
				};
			}
			return this.addEvent(elm, evt, func);
		},
		
		handleEvent : function (evt) {
			var currentEvt = evt || event;
			var currentTarget = currentEvt.target || currentEvt.srcElement || document;
			while (currentTarget.nodeType !== 1 && currentTarget.parentNode) {
				currentTarget = currentTarget.parentNode;
			}			
			currentEvt.eventTarget = currentTarget;
			var eventColl = this.events[currentEvt.type].slice(0);
			var eventCollLength = eventColl.length - 1;
			if (eventCollLength !== -1) {
				for (var i=0; i<eventCollLength; i++) {
					eventColl[i].call(this, currentEvt);
				}
				return eventColl[i].call(this, currentEvt);
			}
		},
		
		removeEvent : function (elm, evt, func) {
			if (document.addEventListener) {
				this.removeEvent = function (elm, evt, func) {
					elm.removeEventListener(evt, func, false);
				};
			}
			else {
				this.removeEvent = function (elm, evt, func) {
					if (elm.events) {
						var eventColl = elm.events[evt];
						if (eventColl) {
							for (var i=0; i<eventColl.length; i++) {
								if (eventColl[i] === func) {
									delete eventColl[i];
									eventColl.splice(i, 1);
								}
							}
						}
						func.attachedElements[evt + elm.uniqueHandlerId] = null;
					}
				};
			}
			return this.removeEvent(elm, evt, func);
		},
		
		stopDefault : function (evt) {
			evt.returnValue = false;
			if (evt.preventDefault) {
				evt.preventDefault();
			}
		},
		
		cancelBubbling : function (evt) {
			evt.cancelBubble = true;
			if (evt.stopPropagation) {
				evt.stopPropagation();
			}
		},
		
		DOMReady : function () {
			for (var i=0, il=arguments.length, funcRef; i<il; i++) {
				funcRef = arguments[i];
				if (!funcRef.DOMReady && !addedStrings[funcRef]) {
					if (typeof funcRef === "string") {
						addedStrings[funcRef] = true;
						funcRef = new Function(funcRef);
					}
					funcRef.DOMReady = true;
					functionsToCall.push(funcRef);
				}
			}
			if (DOMLoaded) {
				execFunctions();
			}
		}
	};
}();
dLite.init();
