/*
name			: Class Behaviour
update			: 20051129
author			: Xander Bindt, Frank van Rooijen, Maurice van Creij
dependencies		: lib_classbehaviour.js
info				: http://www.woollymittens.nl/
*/

	// MAIN
	// main class-behaviour object
	function ClassBehaviour(){
		/* properties */
			this.handlers			=	new Array();
		/* methods */
			// return a parameter from the url's query strings
			this.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 ;
										}
			// returns a string of parameters found in the classname which can be [eval]uated
			this.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.split(paramName + '_');
											// 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 ;
										}
			// returns the visible display state needed for this element
			this.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;
										}
			// (cross)fader and pseudo event handler
			this.fader				=	new Fader;
			// get the previous node without worrying about text nodes
			this.nextNode			=	function(node){
											// look for the next html node
											do {
												node = node.nextSibling;
											} while(node.nodeName.indexOf('#text')>-1);
											// return it
											return node;
										}
			// get the next node without worrying about text nodes
			this.previousNode		=	function(node){
											// look for the previous html node
											do {
												node = node.previousSibling;
											} while(node.nodeName.indexOf('#text')>-1);
											// return it
											return node;
										}
			// parse the document for classnames
			this.parseDocument		=	function(){
											// get all document nodes
											var allNodes = (document.all) ? document.all : document.getElementsByTagName("*");
											// for all tags
											for(var a=0; a<allNodes.length; a++){
												// if the item has a className
												if(allNodes[a].className){
													// get the classname
													nodeClass = allNodes[a].className;
													// for all behaviours
													for(var b=0; b<this.handlers.length; b++){
														// if the behaviour's name exists in the class name, apply it's events
														if(nodeClass.indexOf(this.handlers[b].name)>-1) this.handlers[b].start(allNodes[a]);
													}
												}
											}
										}
	}
	// create the main class-behaviour object
	var classBehaviour = new ClassBehaviour;
	
	// UTILITIES
		function Fader(){
			/* properties */
			/* methods */
			this.getFade	=	function(node){
									var fadeValue = 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;
								}
			this.setFade	=	function(node, amount){
									// 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;
										*/
								}
			this.fadeIn		=	function(idIn, step, delay, evalEvent){
									var cf = classBehaviour.fader;
									// get the fading object
									node = document.getElementById(idIn);
									// get the current fade
									fade = cf.getFade(node) + step;
									// if not 100%
									if((fade)<100){
										// set the new fade
										cf.setFade(node, fade);
										// next step
										cf.timeOut = setTimeout("classBehaviour.fader.fadeIn('"+idIn+"',"+step+","+delay+",'"+evalEvent+"')", delay);
									// else
									}else{
										// set the fade to 100%
										cf.setFade(node, 100);
										// trigger the end event
										eval(evalEvent);
									}
								}
			this.fadeOut	=	function(idOut, step, delay, evalEvent){
									var cf = classBehaviour.fader;
									// get the fading object
									node = document.getElementById(idOut);
									// get the current fade
									fade = cf.getFade(node) - step;
									// if not 100%
									if(fade>0){
										// set the new fade
										cf.setFade(node, fade);
										// next step
										cf.timeOut = setTimeout("classBehaviour.fader.fadeOut('"+idOut+"',"+step+","+delay+",'"+evalEvent+"')", delay);
									// else
									}else{
										// set the fade to 100%
										cf.setFade(node, 0);
										// trigger the end event
										eval(evalEvent);
									}
								}
			this.crossFade	=	function(idIn, idOut, amount, step, delay, evalEvent){
									var cf = classBehaviour.fader;
									// if the amount is not the end value yet
									if(amount<=100){
										// set the fade amounts
										cf.setFade(document.getElementById(idIn), amount);
										cf.setFade(document.getElementById(idOut), 100-amount);
										// unhide the new page
										document.getElementById(idIn).style.display = 'block';
										// construct the fade function
										var evalLoop = "classBehaviour.fader.crossFade('"+idIn+"', '"+idOut+"', "+(amount+step)+", "+step+", "+delay+", '"+evalEvent+"')";
										// repeat the fade
										setTimeout(evalLoop, delay);
									}else{
									// else
										// cancel the opacity style
										var node = document.getElementById(idIn);
										if(typeof(node.style.MozOpacity)!='undefined')	node.style.MozOpacity = 'auto';
										if(typeof(node.style.filter)!='undefined')		node.style.filter = 'none';
										if(typeof(node.style.opacity)!='undefined')		node.style.opacity = 'auto';
										// hide the old page
										document.getElementById(idOut).style.display = 'none';
										// trigger the end event
										cf.onEnd(evalEvent);
									}
								}
			/* events */
			this.onEnd		=	function(evalEvent){
									eval(evalEvent);
								}
		}
	
	// BEHAVIOURS
	// replace in class
		// define this class behaviour
		function ClassMouseHover(){
			/* properties */
			this.name 		= 	'classMouseHover';
			/* methods */
			this.start		=	function(node){
									node.onmouseover = this.addHover;
									node.onmouseout = this.remHover;
								}
			this.hasNoStateClass 	= 	function(objNode){
											return (objNode.className.indexOf('link')<0 && objNode.className.indexOf('hover')<0 && objNode.className.indexOf('active')<0);
										}
			/* events */
			this.addHover 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var cmh = classBehaviour.classMouseHover;
									// replace link by hover
									objNode.className = (cmh.hasNoStateClass(objNode)) ? 'hover ' + objNode.className : objNode.className.replace('link','hover') ;
								}
			this.remHover 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var cmh = classBehaviour.classMouseHover;
									// replace hover by link
									objNode.className = (cmh.hasNoStateClass(objNode)) ? 'link ' + objNode.className : objNode.className.replace('hover','link') ;
								}
			this.addActive 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var cmh = classBehaviour.classMouseHover;
									// replace link by active
									objNode.className = objNode.className.replace('link','active') ;
									// replace hover by active
									objNode.className = objNode.className.replace('hover','active') ;
									// if there's still no active class
									if(cmh.hasNoStateClass(objNode)) objNode.className = 'active ' + objNode.className;
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.classMouseHover = new ClassMouseHover;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.classMouseHover;

	// make all sub elements fake the :hover attribute with .hover
		// define this class behaviour
		function PseudoHover(){
			/* properties */
			this.name 		= 	'pseudoHover';
			/* methods */
			this.start		=	function(node){
									// get all elements
									allNodes = node.getElementsByTagName('LI');
									// for all elements
									for(var a=0; a<allNodes.length; a++){
										// add the hover event
										classBehaviour.classMouseHover.start(allNodes[a]);
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.pseudoHover = new PseudoHover;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.pseudoHover;
		
	// replace in src sub-string
		// define this class behaviour
		function SrcMouseHover(){
			/* properties */
			this.name 			= 	'srcMouseHover';
			this.cache 			= new Array();
			/* methods */
			this.start			=	function(node){
										this.cacheImages(node);
										node.onmouseover = this.addHover;
										node.onmouseout = this.remHover;
									}
			this.cacheImages	 = 	function(that) {
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										// if this is not the image, it must be the parent
										if(!objNode.src) objNode = objNode.getElementsByTagName('IMG')[0];
										// replace link by hover
										var cacheIdx = this.cache.length;
										// hover version
										this.cache[cacheIdx] = new Image();
										this.cache[cacheIdx].src = objNode.src.replace('_link','_hover');
										// active version
										this.cache[cacheIdx+1] = new Image();
										this.cache[cacheIdx+1].src = objNode.src.replace('_link','_active');
									}
			/* events */
			this.addActive 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// if this is not the image, it must be the parent
									if(objNode.nodeName!='IMG') objNode = objNode.getElementsByTagName('IMG')[0];
									// replace link by active
									objNode.src = objNode.src.replace('_link','_active');
									// replace hover by active
									objNode.src = objNode.src.replace('_hover','_active');
								}
			this.addHover 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// if this is not the image, it must be the parent
									if(!objNode.src) objNode = objNode.getElementsByTagName('IMG')[0];
									// replace link by hover
									objNode.src = objNode.src.replace('_link','_hover');
								}
			this.remHover 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// if this is not the image, it must be the parent
									if(!objNode.src) objNode = objNode.getElementsByTagName('IMG')[0];
									// replace link by hover
									objNode.src = objNode.src.replace('_hover','_link');
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.srcMouseHover = new SrcMouseHover;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.srcMouseHover;

	// replace in src sub-string
		// define this class behaviour
		function FadeMouseHover(){
			/* properties */
			this.name 			= 'fadeMouseHover';
			this.cache 			= new Array();
			this.count			= 0;
			this.timeOut		= null;
			/* methods */
			this.start			=	function(node){
										this.cacheImages(node);
										// node.onload = this.setUpFader;
										this.setUpFader(node);
									}
			this.setUpFader		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var fmh = classBehaviour.fadeMouseHover;
										// give this image an id, if it doesn't have one
										if(!objNode.id) objNode.id = 'fadingImage' + fmh.count;
										fmh.count += 1;
										// set the active version of the image source as a background-image of the container
										objNode.parentNode.style.backgroundImage = 'url(' + objNode.src.replace('_link','_hover') + ')';
										// set the image as a block element
										objNode.parentNode.style.display = 'block';
										objNode.parentNode.style.width = objNode.width + 'px';
										objNode.parentNode.style.height = objNode.height + 'px';
										// set the default fade
										classBehaviour.fader.setFade(objNode, 100);
										// set up the events
										objNode.onmouseover = fmh.addHover;
										objNode.onmouseout = fmh.remHover;
									}
			this.cacheImages	 = 	function(that) {
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										// if this is not the image, it must be the parent
										if(!objNode.src) objNode = objNode.getElementsByTagName('IMG')[0];
										// replace link by hover
										var cacheIdx = this.cache.length;
										// hover version
										this.cache[cacheIdx] = new Image();
										this.cache[cacheIdx].src = objNode.src.replace('_link','_hover');
									}
			/* events */
			this.addHover 	= 	function(that, id){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var fmh = classBehaviour.fadeMouseHover;
									// if an id is passed. It overrides the event node
									if(id) objNode = document.getElementById(id);
									// if there's no fade active at the moment // fade out the image
									if(classBehaviour.fader.getFade(objNode)%100==0){
										classBehaviour.fader.fadeOut(objNode.id, 20, 50, '');
									// else try again in a bit
									}else{
										// fmh.timeOut = setTimeout("classBehaviour.fadeMouseHover.addHover(null, '" + objNode.id + "')",50);
									}
								}
			this.remHover 	= 	function(that, id){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var fmh = classBehaviour.fadeMouseHover;
									// if an id is passed. It overrides the event node
									if(id) objNode = document.getElementById(id);
									// if there's no fade active at the moment // fade in the image
									if(classBehaviour.fader.getFade(objNode)%100==0){
										classBehaviour.fader.fadeIn(objNode.id, 20, 50, '');
									// else try again in a bit
									}else{
										fmh.timeOut = setTimeout("classBehaviour.fadeMouseHover.remHover(null, '" + objNode.id + "')",50);
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.fadeMouseHover = new FadeMouseHover;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.fadeMouseHover;
		
	// Add or remove display:none; onclick
		// define this class behaviour
		function ToggleNextNode(){
			/* properties */
			this.name 		= 	'toggleNextNode';
			this.nextNode	=	null;
			this.lastNode	=	null;
			this.lastLink	=	null;
			this.titleNode	= 	null;
			this.locked	=	false;
			/* methods */
			this.start		=	function(node){
									node.onclick = this.toggleNext;
								}
			this.animate	=	function(){
									var tnn = classBehaviour.toggleNextNode;
									// set the loop status
									tnn.locked = true;
									openingComplete = true;
									closingComplete = true;
									// FOR THE CLOSING NODE
									if(tnn.lastNode){
										// what is the content's height of this object
										closingCurrentHeight = parseInt(tnn.lastNode.offsetHeight);
										closingContentHeight = parseInt(classBehaviour.getClassParameter(tnn.lastNode, 'height', '0'));
										// calculate the step-size
										closingStep = Math.round(closingContentHeight / 10);
										// if the current height isn't big enough
										if(closingCurrentHeight > closingStep){
											closingComplete = false;
											// set the container to hide any overflow
											tnn.lastNode.style.overflow = 'hidden';
											// set the container to the current height + a step
											tnn.lastNode.style.height = (closingCurrentHeight - closingStep) + 'px';
										// else
										}else{
											closingComplete = true;
											// hide the node
											tnn.lastNode.style.display = 'none';
											// remove the overflow parameter
											tnn.lastNode.style.overflow = 'visible';
											// set the height to automatic
											tnn.lastNode.style.height = 'auto';
											// RESET THE PARENT NODE (since the animation loop prevents this to be done in it's regular function "toggleNext"
											titleNode = tnn.titleNode;
											if(titleNode.className) titleNode.className = titleNode.className.replace('active','link');
											if(titleNode.src!=null) titleNode.src = titleNode.src.replace('active','link');
											tnn.titleNode = null;
										}
									}
									// FOR THE OPENING NODE
									if(tnn.nextNode){
										// what is the content's height of this object
										openingCurrentHeight = parseInt(tnn.nextNode.offsetHeight);
										openingContentHeight = parseInt(classBehaviour.getClassParameter(tnn.nextNode, 'height', '0'));
										// calculate the step-size
										openingStep = Math.round(openingContentHeight / 10);
										// if the current height isn't big enough
										if(openingCurrentHeight <= openingContentHeight - openingStep){
											openingComplete = false;
											// set the container to hide any overflow
											tnn.nextNode.style.overflow = 'hidden';
											// set the container to the current height + a step
											tnn.nextNode.style.height = (openingCurrentHeight + openingStep) + 'px';
											// make the node visible
											tnn.nextNode.style.display = classBehaviour.getVisibleState(tnn.nextNode);
										// else
										}else{
											openingComplete = true;
											// remove the overflow parameter
											tnn.nextNode.style.overflow = 'visible';
											// set the height to automatic
											tnn.nextNode.style.height = 'auto';
										}
									}
									// REPEAT OR END
									// if both limits are reached
									if(openingComplete && closingComplete){
										// remember the new last node
										tnn.lastNode = tnn.nextNode;
										// restore the click lock
										tnn.locked = false;
									// else
									}else{
										// call this function again
										setTimeout("classBehaviour.toggleNextNode.animate();", 10);
									}
tickle();
								}
			/* events */
			this.toggleThis = 	function(that, strClosePrevious){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var tnn = classBehaviour.toggleNextNode;
									// restore previous node
									if(tnn.lastNode!=null && tnn.lastNode!=objNode && strClosePrevious=='yes') tnn.lastNode.style.display = 'none';
									// toggle node's visibility
									objNode.style.display = (objNode.style.display=='none') ? classBehaviour.getVisibleState(objNode) : 'none' ;
									// remember last node
									tnn.lastNode = objNode;	
								}
			this.toggleAnim =	function(that, strClosePrevious, objTitleNode){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var tnn = classBehaviour.toggleNextNode;
									// set the title node
									tnn.titleNode = objTitleNode;
									// store the animating nodes
									if(strClosePrevious=='no'){
										tnn.nextNode = (objNode.style.display=='none') ? objNode : null ;
										tnn.lastNode = (objNode.style.display=='none') ? null : objNode ;
									}else{
										tnn.nextNode = (objNode.style.display=='none') ? objNode : null ;
										tnn.lastNode = (objNode.style.display=='none') ? tnn.lastNode : objNode ;
									}
									// measure the height of the content in the opening node
									tnn.animate();
								}
			this.toggleNext = 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var tnn = classBehaviour.toggleNextNode;
									// if there is not a running animation
									if(!tnn.locked){
										// get parent recursion
										var intParentRecursion = parseInt(classBehaviour.getClassParameter(objNode,'useParent','0'));
										var objParentNode = objNode;
										for(var a=0; a<intParentRecursion; a++) objParentNode = objParentNode.parentNode;
										// check if a previousnode needs closing
										var strClosePrevious = classBehaviour.getClassParameter(objNode,'closePrevious','no');
										// get optional id
										var strCloseId = classBehaviour.getClassParameter(objNode, 'id', null);
										// determine the next node
										var objNextNode;
										if(strCloseId!=null){
											objNextNode = document.getElementById(strCloseId);
										}else if(objParentNode.nextSibling){
											objNextNode = (objParentNode.nextSibling.nodeName.indexOf("text")<0) ? objParentNode.nextSibling : objParentNode.nextSibling.nextSibling ;
										}
										// animated folding
										var strAnimated = (navigator.appVersion.indexOf('Safari')<0) ? classBehaviour.getClassParameter(objNode,'animated','yes') : 'no' ;
										// if there is a next node
										if(objNextNode!=null){
											// toggle it's visibility
											if(strAnimated=='yes'){
												tnn.toggleAnim(objNextNode, strClosePrevious, objParentNode);
											}else{
												tnn.toggleThis(objNextNode, strClosePrevious);
											}
											// If the next node has been hidden
											if(objNextNode.style.display=='none'){
												// restore current node's click state
												objNode.className = objNode.className.replace('active','link');
												if(objNode.src!=null) objNode.src = objNode.src.replace('active','link');
											}else{
												// mark current node as active
												objNode.className = objNode.className.replace('link','active');
												objNode.className = objNode.className.replace('hover','active');
												if(objNode.src!=null) objNode.src = objNode.src.replace('link','active');
												if(objNode.src!=null) objNode.src = objNode.src.replace('hover','active');
												// restore previous node's click state
												if(tnn.lastLink!=null && tnn.lastLink!=objNode && strClosePrevious=='yes'){
													tnn.lastLink.className = tnn.lastLink.className.replace('active','link');
													if(objNode.src!=null) tnn.lastLink.src = tnn.lastLink.src.replace('active','link');
												}
											}
											// remember last node
											tnn.lastLink = objNode;
										}
									}
									// cancel onclick event
									return false;
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.toggleNextNode = new ToggleNextNode;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.toggleNextNode;

	// add display='none'; on parse
		// define this class behaviour
		function HideThisNode(){
			/* properties */
			this.name 		= 	'hideThisNode';
			/* methods */
			this.start		=	function(node){
									// store the node's height in it's className
									node.className += ' height_' + node.offsetHeight;
									// hide the node
									if(!node.className.match("dontHide")){
									    node.style.display = 'none';
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.hideThisNode = new HideThisNode;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.hideThisNode;
		
	// affirms the visibility status in regard to toggles
		// define this class behaviour
		function ShowThisNode(){
			/* properties */
			this.name 		= 	'showThisNode';
			/* methods */
			this.start		=	function(node){
									// store the node's height in it's className
									node.className += ' height_' + node.offsetHeight;
									// apply the visible state
									node.style.display = classBehaviour.getVisibleState(node);
									// fill the "previous node" parameters of a related object
									classBehaviour.toggleNextNode.lastNode = node;
									classBehaviour.toggleNextNode.lastNode = node;
									// if this isn't the first node
									if(node.parentNode.childNodes[0] != node){
										// pick the previousnode
										objPreviousNode = (node.previousSibling.nodeName.indexOf("text")<0) ? node.previousSibling : node.previousSibling.previousSibling ;
										// store it as the 'previous' toggle
										if(objPreviousNode!=null) classBehaviour.toggleNextNode.lastNext = objPreviousNode;
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.showThisNode = new ShowThisNode;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.showThisNode;
		
	// clear a form element filled with a help text
		// define this class behaviour
		function EmptyOnFocus(){
			/* properties */
			this.name 		= 	'emptyOnFocus';
			/* methods */
			this.start		=	function(node){
									node.onfocus = this.clear;
								}
			/* events */
			this.clear		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// clear the contents if this is the first time
									if(objNode.className.indexOf('wasEmptied')<0){
										// clear this field
										objNode.value = '';
										// mark this input as cleared
										objNode.className += ' wasEmptied';
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.emptyOnFocus = new EmptyOnFocus;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.emptyOnFocus;
		
	// tabbed content
		// define this class behaviour
		function TabbedContent(){
			/* properties */
			this.name 		= 	'tabbedContent';
			/* methods */
			this.start		=	function(node){
									// get all tabs
									allTabs = node.getElementsByTagName('a');
									// store the most likely opened tab
									openedTab = allTabs[0];
									// for all tabs
									for(var a=0; a<allTabs.length; a++){
										// get the id this tab refers to
										tabId = allTabs[a].href.split('#')[1];
										// apply onclick events to the referred tab
										allTabs[a].onclick = this.open;
										// apply the starting state of the tab if needed
										if(allTabs[a].className.indexOf('closedTab')<0) allTabs[a].className += ' closedTab';
										// apply the starting state of the referred content if needed
										document.getElementById(tabId).style.display = 'none';
										// if this tab is referred to in the page url, remember it as active
										if(document.location.href.indexOf(allTabs[a].href)>-1) openedTab = allTabs[a];
										// if this tab was manualy set
										if(allTabs[a].className.indexOf('openedTab')>-1) openedTab = allTabs[a];
									}
									// if there is a pager
									pager = document.getElementById(classBehaviour.getClassParameter(node, 'pagerId', 'none'));
									if(pager){
										// assign the events for the buttons
										pager.getElementsByTagName('a')[0].onclick = this.previous;
										pager.getElementsByTagName('a')[1].onclick = this.next;
									}
									// open the most likely first tab
									this.open(openedTab, true);
								}
			/* events */
			this.next		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var tbd = classBehaviour.tabbedContent;
									// get the pager information
									pagerInfo = objNode.parentNode.parentNode.getElementsByTagName('span')[0].firstChild.nodeValue;
									// what is the current pagenumber
									currentPage = parseInt(pagerInfo.split('/')[0]);
									// how many pages are there
									totalPages = parseInt(pagerInfo.split('/')[1]);
									// what is the next page
									nextPage = (currentPage<totalPages) ? currentPage + 1 : 1 ;
									// what is the tabs strip
									tabStrip = document.getElementById(classBehaviour.getClassParameter(objNode.parentNode.parentNode, 'tabsId', 'none'));
									if(tabStrip){
										// get the relevant page from the tab strip
										targetTab = tabStrip.getElementsByTagName('a')[nextPage-1];
										// activate it's click
										tbd.open(targetTab);
									}
								}
			this.previous	=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var tbd = classBehaviour.tabbedContent;
									// get the pager information
									pagerInfo = objNode.parentNode.parentNode.getElementsByTagName('span')[0].firstChild.nodeValue;
									// what is the current pagenumber
									currentPage = parseInt(pagerInfo.split('/')[0]);
									// how many pages are there
									totalPages = parseInt(pagerInfo.split('/')[1]);
									// what is the next page
									previousPage = (currentPage>1) ? currentPage - 1 : totalPages ;
									// what is the tabs strip
									tabStrip = document.getElementById(classBehaviour.getClassParameter(objNode.parentNode.parentNode, 'tabsId', 'none'));
									if(tabStrip){
										// get the relevant page from the tab strip
										targetTab = tabStrip.getElementsByTagName('a')[previousPage-1];
										// activate it's click
										tbd.open(targetTab);
									}
								}
			this.open		=	function(that, noAnimation){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var tbd = classBehaviour.tabbedContent;								
									
									// INDEX THE TAB STATES
									// get all tabs
									var allTabs = objNode.parentNode.parentNode.getElementsByTagName('a');
									var prevTab = null;
									var pageNumber = 0;
									// find the current tab
									for(var a=0; a<allTabs.length; a++){
										// rememeber the previous tab
										if(allTabs[a].className.indexOf('openedTab')>-1) prevTab = allTabs[a];
										// count the new pagenumber
										if(allTabs[a]==objNode) pageNumber = a;
									}
									
									// if this is the current tab again
									if(prevTab!=objNode){
									
										// PREVIOUS TAB
										if(prevTab){
											// mark the previous tab as passive
											prevTab.className = prevTab.className.replace('openedTab', 'closedTab');
											prevTab.getElementsByTagName('img')[0].src = prevTab.getElementsByTagName('img')[0].src.replace('_active', '_link');
											// id the previous tabbed content
											prevContentId = prevTab.href.split('#')[1];
										}
										
										// NEXT TAB
										// mark the next tab as active
										objNode.className = objNode.className.replace('closedTab', 'openedTab');
										objNode.getElementsByTagName('img')[0].src = objNode.getElementsByTagName('img')[0].src.replace('_link', '_active').replace('_hover', '_active');
										// id the next tabbed content
										nextContentId = objNode.href.split('#')[1];
										
										// FADE ANIMATION
										isAnimated = (noAnimation) ? 'no' : classBehaviour.getClassParameter(objNode, 'animated', 'yes') ;
										if(isAnimated=='yes'){
											// make the previous tab float
											document.getElementById(prevContentId).style.position = 'absolute';
											document.getElementById(prevContentId).style.top = '0px';
											document.getElementById(prevContentId).style.left = '0px';
											// make the next tab no float
											document.getElementById(nextContentId).style.position = 'relative';
											// order the animation
											classBehaviour.fader.crossFade(nextContentId, prevContentId, 0, 10, 50, null);
										}else{
											if(prevTab) document.getElementById(prevContentId).style.display = 'none';
											document.getElementById(nextContentId).style.display = 'block';
										}
										
										// PAGE NUMBER
										// update page-numbering
										pager = document.getElementById(classBehaviour.getClassParameter(objNode.parentNode.parentNode, 'pagerId', 'none'));
										if(pager){
											pager.getElementsByTagName('span')[0].firstChild.nodeValue = (pageNumber+1) + '/' + allTabs.length ;
										}
										
									}
									// cancel the jump to the anchor
									return false;
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.tabbedContent = new TabbedContent;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.tabbedContent;
		
	// Use SwfObject to replace a title with a flash version
		// define this class behaviour
		function FlashTitle(){
			/* properties */
			this.name 		= 	'flashTitle';
			/* methods */
			this.start		=	function(node){
									// get the text to replace
									titleText  = escape(node.firstChild.nodeValue);
									// get the dimensions
									titleWidth = node.offsetWidth;
									titleHeight = node.offsetHeight;
									// get the flash parameters
									swfPath = classBehaviour.getClassParameter(node, 'swf', 'title');
									titleWidth = classBehaviour.getClassParameter(node, 'width', titleWidth);
									titleHeight = classBehaviour.getClassParameter(node, 'height', titleHeight);
									// load the flash plugin
									var so = new SWFObject("/bezorger_huis_aan_huis/flash/" + swfPath + ".swf", node.id + "swf", titleWidth, titleHeight, "7", "#000000");
									so.addParam("wmode", "transparent");
									so.addVariable("inputText", titleText);
									so.write(node.id);
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.flashTitle = new FlashTitle;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.flashTitle;
		
	// Scrolls the shedule table horizontaly
		// define this class behaviour
		function SheduleScroller(){
			/* properties */
			this.name 		= 	'sheduleScroller';
			this.timer		=	null;
			this.table		=	null;
			/* methods */
			this.start		=	function(node){
									// store the scrolling table
									this.table = node.getElementsByTagName('table')[0];
									// construct the non-scrolling table header
									this.labels(node);
									// get all scroll arrows
									allButtons = node.getElementsByTagName('img');
									// set the event handlers for the scroll arrows
									allButtons[allButtons.length-1].onmousedown = this.right;
									allButtons[allButtons.length-1].onmouseup = this.stop;
									allButtons[allButtons.length-1].onmouseout = this.stop;
									allButtons[allButtons.length-2].onmousedown = this.left;
									allButtons[allButtons.length-2].onmouseup = this.stop;
									allButtons[allButtons.length-2].onmouseout = this.stop;
								}
			this.labels	=	function(node){
									// get the containers of the tables
									containers = node.getElementsByTagName('div');
									// put a copy of the table in the div
									containers[0].innerHTML = containers[1].innerHTML;
								}
			this.scroll	=	function(delta){
									var shs = classBehaviour.sheduleScroller;
									// shift the margin of the table in the direction of the scroll
									if(shs.table.style.left){
										// get scroll constants
										step = Math.abs(delta);
										distance = Math.abs(parseInt(shs.table.style.left));
										scrollWidth = shs.table.offsetWidth;
										windowWidth = shs.table.parentNode.offsetWidth
										limit = scrollWidth - windowWidth;
										// calculate step
										distance += delta;
										if(distance>limit) distance = limit;
										if(distance<0) distance = 0;
										// set the style
										shs.table.style.left = '-' + (distance) + 'px';
									}else{
										shs.table.style.left = '0px';
									}
									shs.timer = setTimeout("classBehaviour.sheduleScroller.scroll(" + delta + ")",10);
								}
			/* events */
			this.left		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var shs = classBehaviour.sheduleScroller;
									// set the image
									objNode.src = objNode.src.replace('_link','_hover');
									// set the scroll function
									clearTimeout(shs.timer);
									shs.scroll(-2);
									// cancel the click
									return false;
								}
			this.right		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var shs = classBehaviour.sheduleScroller;
									// set the image
									objNode.src = objNode.src.replace('_link','_hover');
									// set the scroll function
									clearTimeout(shs.timer);
									shs.scroll(2);
									// cancel the click
									return false;
								}
			this.stop		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var shs = classBehaviour.sheduleScroller;
									// set the image
									objNode.src = objNode.src.replace('_hover','_link');
									// set the scroll function
									clearTimeout(shs.timer);
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.sheduleScroller = new SheduleScroller;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.sheduleScroller;
		
	// open all "hideThisNode" items in a list
		// define this class behaviour
		function OpenAllNodes(){
			/* properties */
			this.name 		= 	'openAllNodes';
			/* methods */
			this.start		=	function(node){
									// set the event handlers for this node
									node.onclick = this.open;
								}
			/* events */
			this.open		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// get all nodes
									allNodes = objNode.parentNode.getElementsByTagName('*');
									// for all nodes
									for(var a=0; a<allNodes.length; a++){
										// if the node has "toggleNextNode" and is not "active"
										if(allNodes[a].className){
											if(allNodes[a].className.indexOf('toggleNextNode')>-1 && allNodes[a].className.indexOf(' active')<0){
												// replace the animated version with static version
												allNodes[a].className = allNodes[a].className.replace('animated_yes','animated_no');
												// toggle the node
												classBehaviour.toggleNextNode.toggleNext(allNodes[a]);
												// put the animated version back
												allNodes[a].className = allNodes[a].className.replace('animated_no','animated_yes');
											}
										}
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.openAllNodes = new OpenAllNodes;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.openAllNodes;	
		
	// vary a classname
		// define this class behaviour
		function SetStyle(){
			/* properties */
			this.name 		= 	'setStyle';
			this.locked	=	false;
			/* methods */
			this.start		=	function(node){
									node.onmousemove = this.style;
									/* set the event handlers for this node
									if(navigator.userAgent.indexOf('MSIE 6')){
										node.onmouseover = this.style;
									}else{
										node.onmousemove = this.style;
									}
									*/
								}
			/* events */
			this.style		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var sst = classBehaviour.setStyle;
									if(!sst.locked){
										sst.locked = true;
										// get the classes
										targetId = classBehaviour.getClassParameter(objNode, 'id', null);
										targetClass = classBehaviour.getClassParameter(objNode, 'class', null);
										// set the classes
										document.getElementById(targetId).className = targetClass;
										setTimeout('classBehaviour.setStyle.delay()',32);
									}
									objNode.style.cursor = 'pointer';
								}
			this.delay		=	function(){
									var sst = classBehaviour.setStyle;
									sst.locked = false;
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.setStyle = new SetStyle;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.setStyle;
		
	// Enrich a calendar control
		// define this class behaviour
		function DatePicker(){
			/* properties */
			this.name 			= 	'datePicker';
			/* methods */
			this.start		=	function(node){
									// set the event handlers for this node
									node.onclick = this.open;
								}
			this.set		=	function(calendarNode, date){
									dpr = classBehaviour.datePicker;
									// get the next and previous buttons
									calendarNode.getElementsByTagName('img')[0].onclick = dpr.previous;
									calendarNode.getElementsByTagName('img')[1].onclick = dpr.next;
									// set the month dropdown
									monthNode = calendarNode.getElementsByTagName('select')[0];
									monthNode.selectedIndex = date.getMonth();
									monthNode.onchange = dpr.update;
									// set the year dropdown
									yearSelect = calendarNode.getElementsByTagName('select')[1];
									yearOptions = yearSelect.getElementsByTagName('option');
									currentYear = date.getFullYear();
									if(yearOptions.length==1){
										yearOption = yearOptions[0].cloneNode(true);
										for(var a=currentYear-100; a<currentYear+2; a++ ){
											yearOption = yearSelect.getElementsByTagName('option')[0].cloneNode(true);
											yearOption.value = a;
											yearOption.selected = (a==currentYear) ? 'selected' : '' ;
											yearOption.text = a;
											yearSelect.appendChild(yearOption);
										}
										yearSelect.removeChild(yearSelect.getElementsByTagName('option')[0]);
										yearSelect.onchange = dpr.update;
									}else{
										for(var a=0; a<yearOptions.length; a++) yearOptions[a].selected = (yearOptions[a].value==currentYear) ? 'selected' : '' ;
									}
									// clear out the previous month
									daySlots = calendarNode.getElementsByTagName('td');
									for(var a=0; a<daySlots.length; a++){
										daySlots[a].className = "empty";
										daySlots[a].innerHTML = "";
										daySlots[a].onclick = null;
									}
									// fill the new month
									currentDay = new Date(date.getFullYear(), date.getMonth(), 1);
									nextDay = new Date(date.getFullYear(), date.getMonth(), 2);
									startWeekDay = currentDay.getDay()-1;
									while(currentDay.getDate() < nextDay.getDate()){
										// put the date on the weekday cell
										daySlots[currentDay.getDate()+startWeekDay].innerHTML = currentDay.getDate();
										daySlots[currentDay.getDate()+startWeekDay].className = "";
										daySlots[currentDay.getDate()+startWeekDay].onclick = dpr.pick;
										// next date
										currentDay = new Date(currentDay.getFullYear(), currentDay.getMonth(), currentDay.getDate()+1);
										nextDay = new Date(nextDay.getFullYear(), nextDay.getMonth(), nextDay.getDate()+1);
									}
									
                    daySlots[currentDay.getDate()+startWeekDay].innerHTML = currentDay.getDate();
										daySlots[currentDay.getDate()+startWeekDay].className = "";
										daySlots[currentDay.getDate()+startWeekDay].onclick = dpr.pick;
								}
			this.setSelects =	function(open){
									allSelects = document.getElementById('content').getElementsByTagName('select');
									for(var a=0; a<allSelects.length; a++){
										if(allSelects[a].parentNode.parentNode.className.indexOf('date')<0) allSelects[a].style.visibility = (open) ? 'visible' : 'hidden';
									}
								}
			/* events */
			this.open		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var dpr = classBehaviour.datePicker;
									// OBJECTS
									calendar = classBehaviour.nextNode(objNode);
									// STARTING DATE
									// get the input from the field
									// turn it into a date
									// if the result is a date
										// use it as a start date
									// else
										// take the current date
										date = new Date();
									// CONSTRUCT THE CALENDAR AT THE GIVEN DATE
									dpr.set(calendar, date);
									// hide nearby dropdowns
									if(navigator.userAgent.indexOf('MSIE 6')) classBehaviour.datePicker.setSelects(false);
									// SHOW THE CALENDAR
									classBehaviour.toggleNextNode.toggleNext(objNode);
								}
			this.update	=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var dpr = classBehaviour.datePicker;
									// get both selectors from the parent node
									selectors = objNode.parentNode.getElementsByTagName('select');
									// get the month
									month = parseInt(selectors[0].value);
									// get the year
									year = parseInt(selectors[1].value);
									// make a date out of it
									date = new Date(year, month, 1);
									// update the calendar
									dpr.set(objNode.parentNode.parentNode.parentNode.parentNode,date);
								}
			this.next		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var dpr = classBehaviour.datePicker;
									// get the calendar
									calendar = objNode.parentNode.parentNode.parentNode.parentNode;
									// get the displayed date
									month = parseInt(objNode.parentNode.parentNode.parentNode.getElementsByTagName('select')[0].value);
									year = parseInt(objNode.parentNode.parentNode.parentNode.getElementsByTagName('select')[1].value);
									// add a month
									date = new Date(year,month+1,1);
									// build the calendar
									dpr.set(calendar,date);
								}
			this.previous	=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var dpr = classBehaviour.datePicker;
									// get the calendar
									calendar = objNode.parentNode.parentNode.parentNode.parentNode;
									// get the displayed date
									month = parseInt(objNode.parentNode.parentNode.parentNode.getElementsByTagName('select')[0].value);
									year = parseInt(objNode.parentNode.parentNode.parentNode.getElementsByTagName('select')[1].value);
									// subsctract a month
									date = new Date(year,month-1,1);
									// build the calendar
									dpr.set(calendar,date);
								}
			this.pick		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// get the selected day
									dayValue = objNode.innerHTML;
									// get the selected month
									calendarTitle = objNode.parentNode.parentNode.parentNode.getElementsByTagName('caption')[0];
									month = calendarTitle.getElementsByTagName('select')[0];
									monthValue = month[month.selectedIndex].value;
									// get the selected year
									year = calendarTitle.getElementsByTagName('select')[1];
									yearValue = year[year.selectedIndex].innerHTML;
									// put it in the input field
									targetField = objNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.getElementsByTagName('input')[0];
									targetField.value = dayValue + "-" + (parseInt(monthValue)+1) + "-"+ yearValue;
									// close the calendar
									calendarButton = objNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.getElementsByTagName('img')[0];
									classBehaviour.toggleNextNode.toggleNext(calendarButton);
									// show nearby dropdowns
									if(navigator.userAgent.indexOf('MSIE 6')) classBehaviour.datePicker.setSelects(true);
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.datePicker = new DatePicker;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.datePicker;

	// STARTUP-SEQUENCE
	// start the parsing of classes
	classBehaviour.parseDocument();
