function jpxLib() {}
jpxLib.addEvent = function(in_object, in_event, in_function) {
	if (in_object.addEventListener){ 
		in_object.addEventListener(in_event, in_function, false); 
		return true; 
	}
	else if (in_object.attachEvent){ 
		return in_object.attachEvent("on"+in_event, in_function); 
	}
	else {
		return false; 
	}
}

/*
 * (c)2006 Jesse Skinner/Dean Edwards/Matthias Miller/John Resig
 * Special thanks to Dan Webb's domready.js Prototype extension
 * and Simon Willison's addLoadEvent
 *
 * For more info, see:
 * http://www.thefutureoftheweb.com/blog/adddomloadevent
 * http://dean.edwards.name/weblog/2006/06/again/
 * http://www.vivabit.com/bollocks/2006/06/21/a-dom-ready-extension-for-prototype
 * http://simon.incutio.com/archive/2004/05/26/addLoadEvent
 * 
 *
 * To use: call jpxLib.addDOMLoadEvent one or more times with functions, ie:
 *
 *    function something() {
 *       // do something
 *    }
 *    jpxLib.addDOMLoadEvent(something);
 *
 */
jpxLib.addDOMLoadEvent = (function(){
	/* create event function stack */
	var load_events = [];
	var load_timer;
	var script;
	var done;
	var exec;
	var old_onload;
	var init = function() {
		/**
		 * When the init has already been performed --> don't do it again
		 */
		if(done) {
			return;
		}
		
		/**
		 * Check whether the dom is really loaded
		 */
		try {
			var test = document.getElementsByTagName('body')[0].appendChild(document.createElement('span'));
			test.parentNode.removeChild(test);
		}
		catch(e) {
			setTimeout(arguments.callee, 50);
			return;
		}
		
		/**
		 * Dom is really loaded so:
		 *  - set the done var
		 *  - kill the timer
		 *  - execute each function in the stack in the order they were added
		 */
		done = true;
		clearInterval(load_timer);
		while(exec = load_events.shift()) {
			exec();
		}
		if(script) {
			script.onreadystatechange = null;
		}
	};
	
	return function (func) {
		/* if the init function was already ran, just run this function now and stop */
		if(done) {
			return func();
		}
	
		if(!load_events[0]) {
			/* for Mozilla/Opera9 */
			if(document.addEventListener) {
				document.addEventListener("DOMContentLoaded", init, false);
			}
		
			/* for Internet Explorer */
			if(document.attachEvent) {
				document.write("<script id=\"__ie_onload\" defer src=\"javascript:void(0);\"><\/scr"+"ipt>");
				script = document.getElementById("__ie_onload");
				script.onreadystatechange = function() {
					if(this.readyState == "complete") {
						init();
					}
				};
			}
			
			/* for Safari */
			if(/WebKit/i.test(navigator.userAgent)) {
				load_timer = setInterval(function() {
					if(/loaded|complete/.test(document.readyState)) {
						init();
					}	
				}, 10);
			}
			
			/* for other browsers set the window.onload, but also execute the old window.onload */
			old_onload = window.onload;
			window.onload = function() {
				init();
				if(old_onload) {
					old_onload();
				}
			};
		}
		load_events.push(func);
	}
})();

jpxLib.addClassName = function(in_object, in_class) {
	jpxLib.removeClassName (in_object, in_class);
	in_object.className = jpxLib.trim(in_object.className = (in_object.className + " " + in_class));
}

jpxLib.removeClassName = function(in_object, in_class) {
	in_object.className = jpxLib.trim(in_object.className.replace(in_class, ""));
}

jpxLib.hasClassName = function(in_object, in_class) {
	return jpxLib.inArray(in_class, in_object.className.split(" "));
}

jpxLib.trim = function(in_str){
	return String(in_str).replace(/^\s+|\s+$/g, '');
}

jpxLib.inArray = function(in_search, in_array) {
	for(var i = 0; i < in_array.length; i++) {
		if(in_array[i] == in_search) {
			return true;
		}
	}
	return false;
}

jpxLib.arrayKeyExists = function(in_key, in_array) {
	return in_key in in_array;
}

jpxLib.getViewportSize = function() {
	size = new Object;
	if(typeof window.innerWidth != 'undefined') {
		size.width = window.innerWidth;
		size.height = window.innerHeight;
	}
	else if(typeof document.documentElement != 'undefined' && typeof document.documentElement.clientWidth != 'undefined' && document.documentElement.clientWidth != 0) {
		size.width = document.documentElement.clientWidth;
		size.height = document.documentElement.clientHeight;
	}
	else {
		size.width = document.getElementsByTagName('body')[0].clientWidth;
		size.height = document.getElementsByTagName('body')[0].clientHeight;
	}
	if(navigator.userAgent.toLowerCase().indexOf('msie') == -1) {
		size.width -= 15;
	}
	return size;

}

jpxLib.getObjectPosition = function(obj) {
	position = new Object;
	position.left = 0;
	position.top = 0;
	if (obj.offsetParent) {
		position.left = obj.offsetLeft;
		position.top = obj.offsetTop;
		while (obj = obj.offsetParent) {
			position.left += obj.offsetLeft;
			position.top += obj.offsetTop;
		}
	}
	return position;
}

jpxLib.getMousePosition = function(e) {
	if(!e) e = window.event;
	mX = (e.pageX) ? e.pageX : e.clientX;
	mY = (e.pageY) ? e.pageY : e.clientY;
	if(document.body && document.all) {
		if(document.documentElement && document.documentElement.scrollTop) {
			mX += document.documentElement.scrollLeft;
			mY += document.documentElement.scrollTop;
		}
		else {
			mX += document.body.scrollLeft;
			mY += document.body.scrollTop;
		}
	}
	return {left: mX, top: mY};
}

jpxLib.getScrollPosition = function() {
	pos_left = 0;
	pos_top = 0;
	
	if (self.pageXOffset) { // all except Explorer
		pos_left = self.pageXOffset;
		pos_top = self.pageYOffset;
	}
	else if (document.documentElement && document.documentElement.scrollLeft) { // Explorer 6 Strict
		pos_left = document.documentElement.scrollLeft;
		pos_top = document.documentElement.scrollTop;
	}
	else if (document.body) { // all other Explorers
		pos_left = document.body.scrollLeft;
		pos_top = document.body.scrollTop;
	}
	else {
		return false;
	}
	
	return {left: pos_left, top: pos_top};
}

jpxLib.getUrlParam = function(name) {
	name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
	var regexS = "[\\?&]"+name+"=([^&#]*)";
	var regex = new RegExp( regexS );
	var results = regex.exec( window.location.href );
	return (results === null) ? false : results[1];
}

jpxLib.addStyleSheet = function(in_url, in_title) {
	var cssNode = document.createElement('link');
	cssNode.type = 'text/css';
	cssNode.rel = 'stylesheet';
	cssNode.href = in_url;
	cssNode.media = 'screen';
	if(in_title) {
		cssNode.title = in_title;
	}
	document.getElementsByTagName("head")[0].appendChild(cssNode);
}

jpxLib.addCssRule = function(in_selector, in_declaration, in_index, in_csstitle) {
	var els = document.styleSheets;
	var stylesheet_index = els.length - 1;
	
	if(in_csstitle) {
		for(var i = 0; i < els.length; i++) {
			if(els.title == in_csstitle) {
				stylesheet_index = i;
			}
		}
	}
	
	/**
	 * When the index is not set:
	 * Create a style element in the head and add the css to it.
	 */
	if(typeof in_index == "undefined") {
		jpxLib.addCssRuleToStyleElement(in_selector, in_declaration);
		return true;
	}
	
	if(els[stylesheet_index].addRule) {
		if(in_index == -1) {
			in_index = null;
		}
		els[stylesheet_index].addRule(in_selector, in_declaration, in_index);
		return true;
	}
	else if(els[stylesheet_index].insertRule) {
		try {
			if(in_index == -1) {
				in_index = els[stylesheet_index].cssRules.length;
			}
			els[stylesheet_index].insertRule(in_selector + "{" + in_declaration + "}", in_index);
			return true;
		}
		catch(e) {
			/**
			 * FF needs a setTimeout, beause the stylesheet is probably not loaded yet.
			 */
			if(e.name == "NS_ERROR_DOM_INVALID_ACCESS_ERR") {
				setTimeout("jpxLib.addCssRule('"+in_selector+"', '"+in_declaration+"', "+in_index+ ((in_csstitle) ? ", '"+in_csstitle+"'" : "null") + ")", 100);
			}
			
			/**
			 * The method jpxLib.addCssRule is not allowed since the CSS file is on a different domain than the HTML file.
			 * So try it another way.
			 */
			else if(e.name == "NS_ERROR_DOM_SECURITY_ERR") {
				jpxLib.addCssRuleToStyleElement(in_selector, in_declaration);
			
				return true;
			}
		}
	}
	
	return false;
}

jpxLib.addCssRuleToStyleElement = function(in_selector, in_declaration) {
	var style_el = document.getElementById('jpxCssAutomaticInsert');
	if(!style_el) {
		style_el = document.createElement('style');
		style_el.type = 'text/css';
		style_el.id = 'jpxCssAutomaticInsert';
		document.getElementsByTagName("head")[0].appendChild(style_el);
	}
	
	if(style_el.styleSheet) { //IE doesn't allow to append textnode childs and needs special treatment.
		style_el.styleSheet.cssText += in_selector + "{" + in_declaration + "} ";
	}
	else {
		style_el.appendChild(document.createTextNode(in_selector + "{" + in_declaration + "} "));
	}
}


/**
 * A few basic extensions of javascript
 */
jpxLib.objectInherit = function(targetClass, superClass) {
	var tmpClass = function() {};
	tmpClass.prototype = superClass.prototype;
	targetClass.prototype = new tmpClass;
	var className = jpxLib.getObjectClassName(superClass);
	targetClass.prototype[className] = superClass;
	return targetClass;
}

jpxLib.getObjectClassName = function(baseClass) {
	var matches = baseClass.toString().match(/function\s*(\w+)/);
	return (matches == null) ? '' : matches[1];
}

/**
 * Add a default stylesheet which prevents the interface from text becoming selected.
 */
jpxLib.addCssRule('.jpxNoSelect', '-moz-user-select: none; -khtml-user-select: none; user-select: none;');