/*
	name			: ClassBehaviours, the javascript framework based on class-name parsing
	update			: 20081124
	author			: Maurice van Creij
	dependencies	: jquery.classbehaviours.js
	info			: http://www.classbehaviours.com/

    This file is part of jQuery.classBehaviours.
    
    ClassBehaviours is a javascript framework based on class-name parsing.
    Copyright (C) 2008  Maurice van Creij

    ClassBehaviours is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    ClassBehaviours is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with ClassBehaviours. If not, see http://www.gnu.org/licenses/gpl.html.
*/

	// create the jQuery object if it doesn't already exist
	if(typeof(jQuery)=='undefined') jQuery = function(){};
	
	// create the root classbehaviours object if it doesn't already exist
	if(typeof(jQuery.classBehaviours)=='undefined') jQuery.classBehaviours = function(){};
	
	// create the handlers child object if it doesn't already exist
	if(typeof(jQuery.classBehaviours.handlers)=='undefined') jQuery.classBehaviours.handlers = function(){}
	
	// AJAX interface
	jQuery.classBehaviours.ajax = {
		// properties
		queue: new Array(),
		// utilities
		getNodeValue: function(objNode){
			strValue = (objNode.childNodes.length>0) ? objNode.firstChild.nodeValue : null ;
			return (isNaN(strValue) || strValue==null) ? strValue : parseInt(strValue);
		},
		setNodeValue: function(objNode,strValue){
			if(objNode.childNodes.length>0){
				objNode.firstChild.nodeValue = strValue;
			}else{
				var objNewNode = ajax.createTextNode(strValue);
				objNode.appendChild(objNewNode);
			}
		},
		getChildNumber: function(objNode){
			var objNodes = objNode.parentNode.childNodes;
			var intTextNodes = 0;
			for(var intA=0; intA<objNodes.length; intA++){
				if(objNodes[intA].nodeName == '#text') intTextNodes += 1;
				if(objNode==objNodes[intA]) return intA - intTextNodes;
			}
			return null;
		},
		serialize: function serialize(ajax){
			ser = new XMLSerializer();
			str = ser.serializeToString(ajax);
			return(str);
		},
		// methods
		addRequest: function(url, loadHandler, progressHandler, post, referingObject){
			// get the first free slot in the que
			index = this.queue.length;
			// add new request to the end of the que
			this.queue[index] = new this.HttpRequest();
			// set request constants
			this.queue[index].idx			=	index;
			this.queue[index].url			=	url;
			this.queue[index].post			=	post;
			this.queue[index].method		=	(post) ? 'POST' : 'GET' ;
			// request events
			this.queue[index].doOnLoad		=	loadHandler;
			this.queue[index].doOnProgress	=	progressHandler;
			this.queue[index].referObject	=	referingObject;
			// ask the queue handler to handle the next queued item
			this.handleQueue();
		},
		makeRequest: function(queued){
			// branch for native XMLHttpRequest object
			if(window.XMLHttpRequest){
				queued.request = new XMLHttpRequest();
				queued.request.onreadystatechange = this.progress;
				queued.request.open(queued.method, queued.url, true);
				queued.request.send(queued.post);
			// branch for IE/Windows ActiveX version
			}else if(window.ActiveXObject){
				queued.request = new ActiveXObject("Microsoft.XMLHTTP");
				queued.request.onreadystatechange = this.progress;
				queued.request.open(queued.method, queued.url, true);
				queued.request.send(queued.post);
			// if all else fails: load the document in an iFrame
			}else if(window.frames){
				// create an iframe to read the document in
					objIframe = document.createElement("IFRAME");
					objIframe.src = queued.url;
					objIframe.id = "feedimport0";
					objIframe.name = "feedimport0";
				objIframe.style = "visibility : invisible;position : absolute;left : -1600px; top : -1600px;";
					//objIframe.onload = ajax_load; // Doesn't work in Opera
				// append the iframe to the document
					document.body.appendChild(objIframe);
				// wait for the iframe to load
				this.wait();
			}
		},
		handleQueue: function(){
			queue = jQuery.classBehaviours.ajax.queue;
			// if the first item in the queue is a completed request
			if(queue.length>0){
				if(queue[0].ready==4 /*&& ajax.queue[0].status==200*/){
					// remove the completed request
					queue.reverse();
					queue.length = queue.length - 1;
					queue.reverse();
				}
			}
			// if the first item in the queue isn't allready in progress
			if(queue.length>0){
				if(!(queue[0].ready<4 && queue[0].ready!=null)){
					this.makeRequest(queue[0]);
				}
			}
		},
		// events
		progress: function(){
			queued = jQuery.classBehaviours.ajax.queue[0];
			// remember the readyState
			queued.ready = queued.request.readyState;
			// only if req shows "complete"
			if(queued.request.readyState == 4){
				// remember the status
				queued.status = queued.request.status;
				// only if "OK"
				if(queued.request.status == 200 || queued.request.status == 304){
					// update optional progress indicator code
					if(queued.doOnProgress) queued.doOnProgress(1, queued.referObject);
					// prepare the document
					queued.document = queued.request.responseXML;
					queued.text = queued.request.responseText;
					// trigger the load event
					if(queued.doOnLoad) queued.doOnLoad(queued.document, queued.referObject, queued.text);
					// request the next item in the queue to be handled
					jQuery.classBehaviours.ajax.handleQueue();
				}else{
					// update optional progress indicator code
					if(queued.doOnProgress) queued.doOnProgress(-1, queued.referObject, queued.request.status);
				}
			}else{
				// update optional progress indicator code
				if(queued.doOnProgress) queued.doOnProgress(queued.request.readyState/4, queued.referObject, 200);
			}
			// return the status if desired
			return queued.request.readyState;
		},
		wait: function(){
			queued = jQuery.classBehaviours.ajax.queue[0];
			// if the xml document has loaded in the iframe
			if(window.frames["feedimport0"]){
				// define the xml document object
				queued.document = window.frames["feedimport0"].document;
				queued.text = window.frames["feedimport0"].document.body.innerHTML;
				// what to do after the xml document loads
				queued.doOnLoad(queued.document, queued.referObject, queued.text);
			// else try again in a while
			}else{
				setTimeout("ajax.wait()",256);
			}
		}
	}
		// prototype http request object
		jQuery.classBehaviours.ajax.HttpRequest = function(){
			// request constants
			this.idx			=	null;
			this.url			=	null;
			this.post			=	null;
			this.method			=	'GET';
			// request events
			this.doOnLoad		=	null;
			this.doOnProgress	=	null;
			this.referObject	=	null;
			// request properties
			this.request		=	null;
			this.document		=	null;
			this.text			=	null;
			this.ready			=	null;
			this.status			=	null;
		}

	// debug console
	jQuery.classBehaviours.console = {
		// porperties
		id: 'debugConsole0',
		limit: 32,
		// methods
		debug: function(){
			// create the debug console if it doesn't exist yet
			debugConsole = document.getElementById(jQuery.classBehaviours.console.id);
			if(debugConsole==null){
				// create a new console node
				newConsole = document.createElement('div');
				newConsole.id = jQuery.classBehaviours.console.id;
				newText = document.createTextNode('-- newest at top --');
				newConsole.appendChild(newText);
				document.body.appendChild(newConsole);
				debugConsole = document.getElementById(jQuery.classBehaviours.console.id);
			}
			// set the console's properties
			if(debugConsole.style.background=='') 	debugConsole.style.background = '#ffffff url(../images/button_passive.png) no-repeat 0px 0px';
			if(debugConsole.style.border=='') 		debugConsole.style.border = 'solid 1px #000000';
			if(debugConsole.style.bottom=='') 		debugConsole.style.bottom = 'auto';
			if(debugConsole.style.height=='') 		debugConsole.style.height = (navigator.userAgent.indexOf('MSIE 6')>-1) ? '580px' : '98%' ;
			if(debugConsole.style.left=='') 		debugConsole.style.left = 'auto';
			if(debugConsole.style.overflow=='') 	debugConsole.style.overflow = 'auto';
			if(debugConsole.style.padding=='') 		debugConsole.style.padding = '1% 1% 1% 1%';
			if(debugConsole.style.position=='') 	debugConsole.style.position = (navigator.userAgent.indexOf('MSIE 6')>-1) ? 'absolute' : 'fixed' ;
			if(debugConsole.style.right=='') 		debugConsole.style.right = '-1px';
			if(debugConsole.style.top=='') 			debugConsole.style.top = '-1px';
			if(debugConsole.style.width=='') 		debugConsole.style.width = '128px';
			debugConsole.onclick = jQuery.classBehaviours.console.move;
			jQuery.classBehaviours.fader.setFade(debugConsole, 75);
			// send all the incoming arguments to the debug console
			newList = document.createElement('ul');
			for(var a=0; a<arguments.length; a++){
				// create a list item for each argument
				newListItem = document.createElement('li');
				newListText = document.createTextNode(arguments[a]);
				newListItem.appendChild(newListText);
				newList.appendChild(newListItem);
			}
			debugConsole.insertBefore(newList, debugConsole.firstChild);
			// if there are too many enties, remove a few
			allLists = debugConsole.getElementsByTagName('ul');
			if(allLists.length>jQuery.classBehaviours.console.limit) 
				for(var a=allLists.length-1; a>jQuery.classBehaviours.console.limit; a--)
					removedChild = debugConsole.removeChild(allLists[allLists.length-1]);
		},
		clear: function(){
			// clear the entries
			debugConsole = document.getElementById(jQuery.classBehaviours.console.id);
			if(debugConsole!=null){
				allLists = debugConsole.getElementsByTagName('ul');
				for(var a=allLists.length-1; a>=0; a--)
					removedChild = debugConsole.removeChild(allLists[allLists.length-1]);
			}
		},
		html: function(string){
			string = '<xmp>' + string + '</xmp>'
			this.debug(string)
		},
		// events
		move: function(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// get the console
			debugConsole = document.getElementById(jQuery.classBehaviours.console.id);
			// toggle through several console positions
			if(debugConsole.style.right == '-1px' && debugConsole.style.width == '128px'){
				debugConsole.style.bottom = 'auto';
				debugConsole.style.height = (navigator.userAgent.indexOf('MSIE 6')>-1) ? '580px' : '98%' ;
				debugConsole.style.left = '-1px';
				debugConsole.style.right = 'auto';
				debugConsole.style.top = '-1px';
				debugConsole.style.width = '128px';
			}else if(debugConsole.style.left == '-1px' && debugConsole.style.width == '128px'){
				debugConsole.style.bottom = '-1px';
				debugConsole.style.height = '128px';
				debugConsole.style.left = '-1px';
				debugConsole.style.right = 'auto';
				debugConsole.style.top = 'auto';
				debugConsole.style.width = '98%';
			}else if(debugConsole.style.bottom == '-1px' && debugConsole.style.width == '98%'){
				debugConsole.style.bottom = 'auto';
				debugConsole.style.height = (navigator.userAgent.indexOf('MSIE 6')>-1) ? '580px' : '98%' ;
				debugConsole.style.left = 'auto';
				debugConsole.style.right = '-1px';
				debugConsole.style.top = '-1px';
				debugConsole.style.width = '128px';
			}
		}
	}
		
	// short-cut wrapper functions
	debug = jQuery.classBehaviours.console.debug;
	
	// cookies Library
	jQuery.classBehaviours.cookies = {
		// methods
		getDaysFromNow: function(intDays){
			var dateCurrent = new Date();
			var intCurrent = Date.parse(dateCurrent);
			var intPeriod = intDays*24*60*60*1000;
			var datePeriodInFuture = new Date(intCurrent+intPeriod);
			return datePeriodInFuture;
		},
		setCookie: function(name, value, expires, path, domain, secure) {
			var curCookie = name + "=" + escape(value) +
				((expires) ? "; expires=" + expires.toGMTString() : "") +
				((path) ? "; path=" + path : "") +
				((domain) ? "; domain=" + domain : "") +
				((secure) ? "; secure" : "");
			document.cookie = curCookie;
		},
		getCookie: function(name) {
			var dc = document.cookie;
			var prefix = name + "=";
			var begin = dc.indexOf("; " + prefix);
			if (begin == -1) {
				begin = dc.indexOf(prefix);
				if (begin != 0) return null;
			}else{
				begin += 2;
			}
			var end = document.cookie.indexOf(";", begin);
			if (end == -1)
				end = dc.length;
			return unescape(dc.substring(begin + prefix.length, end));
		},
		deleteCookie: function(name, path, domain) {
			if (getCookie(name)) {
				document.cookie = name + "=" + 
				((path) ? "; path=" + path : "") +
				((domain) ? "; domain=" + domain : "") +
				"; expires=Thu, 01-Jan-70 00:00:01 GMT";
			}
		},
		fixDate: function(date) {
			var base = new Date(0);
			var skew = base.getTime();
			if (skew > 0)
				date.setTime(date.getTime() - skew);
		},
		makeBoolean: function(strIn){
			if(strIn=='true'){
				booOut = true;
			}else{
				booOut = false;
			}
			return booOut;
		},
		csv2array: function(csvIn){
			return csvIn.split(',');
		},
		array2csv: function(arrIn){
			return ''+arrIn;
		}
	}
		
	// decorative fader animations
	jQuery.classBehaviours.fader = {
		// properties
		getFade: function(node){
			var fadeValue = null;
			if(node!=null){
				// get the fade value using the proper method
				if(typeof(node.style.MozOpacity)!='undefined')	fadeValue = Math.round(parseFloat(node.style.MozOpacity)*100);
				if(typeof(node.style.filter)!='undefined')		fadeValue = parseInt(node.filters.alpha.opacity);
				if(typeof(node.style.opacity)!='undefined')		fadeValue = Math.round(parseFloat(node.style.opacity)*100);
			}
			// return the value
			return fadeValue;
		},
		setFade: function(node, amount){
			if(node!=null){
				// set the fade value using the proper method
				if(typeof(node.style.MozOpacity)!='undefined')	node.style.MozOpacity = amount/100;
				if(typeof(node.style.filter)!='undefined')		node.style.filter = "alpha(opacity=" + amount + ")";
				if(typeof(node.style.opacity)!='undefined')		node.style.opacity = amount/100;
			}
			/*
			filter:alpha(opacity=50);	imageobject.filters.alpha.opacity=opacity
			-moz-opacity: 0.5;			imageobject.style.MozOpacity=opacity/100
			opacity: 0.5;
			-khtml-opacity: 0.5;
			*/
		},
		getSize: function(node){
			// measure the height of the container
			var nodeWidth = node.offsetWidth;
			var nodeHeight = node.offsetHeight;
			// measure the height of all the childnodes of the container
			var totalWidth = 0;
			var totalHeight = 0;
			var contents = node.childNodes;
			for(var a=0; a<contents.length; a++){
				totalWidth += (contents[a].offsetWidth) ? contents[a].offsetWidth : 0 ;
				totalHeight += (contents[a].offsetHeight) ? contents[a].offsetHeight : 0 ;
			}
			// pass back the largest number
			return new Array(nodeWidth, nodeHeight, totalWidth, totalHeight);
		},
		setSize: function(node, xAmount, yAmount){
			if(xAmount!=null) node.style.width = xAmount + 'px';
			if(yAmount!=null) node.style.height = yAmount + 'px';
		},
		// methods
		fade: function(id, start, end, step, delay, acceleration, evalOnEnd){
			var cf = jQuery.classBehaviours.fader;
			// get the target node
			target = document.getElementById(id);
			// get the start value if missing
			if(start==null) 		start = cf.getFade(target);
			if(end==null) 			end = 100;
			if(step==null) 			step = 1;
			if(delay==null) 		delay = 10;
			if(acceleration==null) 	acceleration = 1;
			if(evalOnEnd==null) 	evalOnEnd = '';
			// calculate the new value
			if(start<end)		{value = (start+step>end) ? end : start+step ;}
			else if(start>end)	{value = (start-step<end) ? end : start-step ;}
			// set the fade
			cf.setFade(target, value);
			// order the next step
			if(value!=end) 		{setTimeout("jQuery.classBehaviours.fader.fade('"+id+"',"+value+","+end+","+(step+acceleration)+","+delay+","+acceleration+",'"+evalOnEnd+"')", delay);}
			else 				{eval(evalOnEnd);}
		},
		size: function(id, start, end, step, delay, acceleration, evalOnEnd){
			var cf = jQuery.classBehaviours.fader;
			// get the target node
			target = document.getElementById(id);
			// get the start value if missing
			if(start==null) 		start = cf.getSize(target)[1];
			if(end==null) 			end = cf.getSize(target)[3];
			if(step==null) 			step = 10;
			if(delay==null) 		delay = 10;
			if(acceleration==null) 	acceleration = 10;
			if(evalOnEnd==null) 	evalOnEnd = '';
			// calculate the new value
			if(start<end)		{value = (start+step>end) ? end : start+step ;}
			else if(start>end)	{value = (start-step<end) ? end : start-step ;}
			// set the fade
			cf.setSize(target, null, value);
			// order the next step
			if(value!=end) 		{setTimeout("jQuery.classBehaviours.fader.size('"+id+"',"+value+","+end+","+(step+acceleration)+","+delay+","+acceleration+",'"+evalOnEnd+"')", delay);}
			else 				{eval(evalOnEnd);}
		},
		/* START: legacy functions */
		fadeIn: function(id, step, delay, evalOnEnd, acceleration){
			jQuery.classBehaviours.fader.fade(id, 0, 100, step, delay, acceleration, evalOnEnd);
		},
		fadeOut: function(id, step, delay, evalOnEnd, acceleration){
			jQuery.classBehaviours.fader.fade(id, 100, 0, step, delay, acceleration, evalOnEnd);
		},
		crossFade: function(idIn, idOut, amount, step, delay, evalOnEnd, acceleration){
			jQuery.classBehaviours.fader.fade(idIn, 0, 100, step, delay, acceleration, evalOnEnd);
			jQuery.classBehaviours.fader.fade(idOut, 100, 0, step, delay, acceleration, '');
		},
		grow: function(id, step, delay, evalOnEnd, acceleration){
			jQuery.classBehaviours.fader.size(id, 1, null, step, delay, acceleration, evalOnEnd);
		},
		shrink: function(id, step, delay, evalOnEnd, acceleration){
			jQuery.classBehaviours.fader.size(id, null, 1, step, delay, acceleration, evalOnEnd);
		}
		/* END: legacy functions */
	}

	// general purpose functions
	jQuery.classBehaviours.utilities = {
		// returns all nodes of the same class
		getElementsByClassName: function(className, node){
			// use the whole body if no target was provided
			target = (node!=null) ? node : document ;
			// make an empty array for the results
			var foundNodes = new Array();
			// for all elements in the parent node
			var allNodes = (target.all) ? target.all : target.getElementsByTagName("*");
			for(var a=0; a<allNodes.length; a++){
				// if the item has a className
				if(allNodes[a].className){
					// process the classname
					nodeClass = allNodes[a].className + ' ';
					// add it to the results if the classname was found
					if(nodeClass.indexOf(className+' ')>-1) foundNodes[foundNodes.length] = allNodes[a];
				}
			}
			// return the list
			return foundNodes;
		},
		// detaries the available room on the screen
		screenHeight: function(){
			return (window.innerHeight) ? window.innerHeight : (document.documentElement.clientHeight) ? document.documentElement.clientHeight : document.body.clientHeight ;
		},
		// return a parameter from the url's query strings
		getQueryParameter: function(paramName, defaultValue){
			// split the query string at the parameter name
			var queryParameters = document.location.search.split(paramName+"=");
			// split the parameter value from the rest of the string
			var queryParameter = (queryParameters.length>1) ? queryParameters[1].split("&")[0] : null ;
			// return the value
			return (queryParameter!=null) ? queryParameter : defaultValue ;
		},
		// gets the value of a parameter from a className
		getClassParameter: function(targetNode, paramName, defaultValue){
			// get the class parameter from the classname
			var classParameter = targetNode.className;
			// split the classname between the parameter name
			classParameter = (classParameter!=null) ? classParameter.split(paramName + '_') : new Array();
			// split the second piece between spaces and take the first part,  if there are two pieces
			classParameter = (classParameter.length>1) ? classParameter[1].split(' ')[0] : null ;
			// return the value
			return (classParameter!=null) ? classParameter : defaultValue ;
		},
		// sets the value of a parameter from a className
		setClassParameter: function(targetNode, paramName, newValue){
			if(typeof(targetNode.className)!='undefined'){
				// create a default value, if there isn't one
				if(targetNode.className.indexOf(' ' + paramName + '_')<0) targetNode.className += ' ' + paramName + '_0';
				// get the old value
				oldValue = this.getClassParameter(targetNode, paramName, null);
				// replace the old value
				if(oldValue!=null) targetNode.className = targetNode.className.replace(paramName+'_'+oldValue, paramName+'_'+newValue);	
			}
		},
		// get the next node without worrying about text nodes
		nextNode: function(node, count){
			testNode = node;
			if(count==null) count = 1;
			// look for the next html node
			for(var a=0; a<count; a++){
				do {
					testNode = testNode.nextSibling;
					if(testNode==null) testNode = node;
				}while(testNode.nodeName.indexOf('#text')>-1);
			}
			// return it
			return testNode;
		},
		// get the previous node without worrying about text nodes
		previousNode: function(node, count){
			testNode = node;
			if(count==null) count = 1;
			// look for the previous html node
			for(var a=0; a<count; a++){
				do {
					testNode = testNode.previousSibling;
					if(testNode==null) testNode = node;
				}while(testNode.nodeName.indexOf('#text')>-1);
			}
			// return it
			return testNode;
		},
		// get the first real child node without worrying about text nodes
		firstNode: function(node, count){
			return this.nextNode(node.firstChild, count);
		},
		// find the parent node with the given classname
		rootNode: function(node, rootTag, rootId, rootClass){
			// try parent nodes until you find the one which meets the conditions
			rootFound = false;
			while(!rootFound && node.nodeName!='BODY'){
				rootFound = (rootTag && node.nodeName) ? (node.nodeName.indexOf(rootTag)>-1) : rootFound ;
				rootFound = (rootId && node.id) ? (node.id.indexOf(rootId)>-1) : rootFound ;
				rootFound = (rootClass && node.className) ? (node.className.indexOf(rootClass)>-1) : rootFound ;
				node = (!rootFound) ? node.parentNode : node;
			}
			// pass it back
			return node;
		},
		// returns the visible display state needed for this element
		getVisibleState: function(node){
			// what kind of node is this
			switch(node.nodeName.toLowerCase()){
				case 'table' : visibleState='table' ; break;
				case 'thead' : visibleState='table-header-group' ; break;
				case 'tfoot' : visibleState='table-footer-group' ; break;
				case 'tbody' : visibleState='table-row-group' ; break;
				case 'tr' : visibleState='table-row' ; break;
				case 'td' : visibleState='table-cell' ; break;
				case 'th' : visibleState='table-cell' ; break;
				default : visibleState='block';
			}
			// apply the state
			return (document.all && navigator.userAgent.indexOf('Opera')<0) ? 'block' : visibleState;
		},
		// hide select form elements for graphic glitches in certain browsers
		hideSelects: function(node){
			if(
				navigator.userAgent.indexOf('MSIE 6')>-1 || 
				(navigator.userAgent.indexOf('Firefox/2')>-1 && navigator.userAgent.indexOf('Mac')>-1)
			){
				allSelects = (node) ? node.getElementsByTagName('SELECT') : document.getElementsByTagName('SELECT') ;
				for(var a=0; a<allSelects.length; a++){
					allSelects[a].style.visibility = 'hidden';
				}
			}
		},
		showSelects: function(node){
			if(
				navigator.userAgent.indexOf('MSIE 6')>-1 || 
				(navigator.userAgent.indexOf('Firefox/2')>-1 && navigator.userAgent.indexOf('Mac')>-1)
			){
				allSelects = (node) ? node.getElementsByTagName('SELECT') : document.getElementsByTagName('SELECT') ;
				for(var a=0; a<allSelects.length; a++){
					allSelects[a].style.visibility = 'visible';
				}
			}
		},
		// adds an event-handler the proper way
		addEvent: function(node, eventName, eventHandler){
			if(node.addEventListener) 	node.addEventListener(eventName, eventHandler, false)
			else if(node.attachEvent) 	node.attachEvent("on"+eventName, eventHandler)
			else 						node["on"+eventName] = eventHandler;
			return true;
		}
	}
		
	// Parser functions
	jQuery.classBehaviours.parser = {
		// status of the parser
		waiting: false,
		// verify the state of the object
		start: function(){
			// if the document is complete enough start the behaviours, else wait until everything is loaded
			var handlersCount = 0;
			for (b in jQuery.classBehaviours.handlers) handlersCount++;
			this.waiting = (handlersCount>0 && document.body) ? this.parseDocument() : jQuery.classBehaviours.utilities.addEvent(window, 'load', this.parseDocument) ;
		},
		// scan the whole document
		parseDocument: function(){
			// pass the document object to the parser
			jQuery.classBehaviours.parser.parseNode(document);
			// return the status
			return false;
		},
		// scan the document object model for target classNames
		parseNode: function(node){
			// for all childnodes of the given node
			var allNodes = node.getElementsByTagName("*");
			for(var a=0; a<allNodes.length; a++){
				// get its className
				nodeClass = ' ' + allNodes[a].className + ' ';
				// if this node has a className
				if(nodeClass!=null)
					// for all class behaviours
					for(b in jQuery.classBehaviours.handlers)
						// if the behaviour name is in the className tested node
						if(nodeClass.indexOf(' ' + jQuery.classBehaviours.handlers[b].name + ' ')>-1)
							// apply its respective behaviour
							jQuery.classBehaviours.handlers[b].start(allNodes[a]);
			}
		}
	}

	// add this addon to the jQuery object
	if(typeof(jQuery.fn)!='undefined'){
		// set the event handler for this jQuery method
		$(document).ready(
			function(){
// TODO: at the moment this is handled by the individual classbehaviours modules, until this proves to slow
//				$.classBehaviours.parser.parseDocument()
			}
		);
	}else{
		// start the (backup) parsing of classes if the main jQuery library is not available
		jQuery.classBehaviours.parser.start()
	}

