/*
name: Class Behaviour for popup windows

notes:
 Open links in a popup
   class="openAsPopUp[_WI400][_HE300][_TByes][_SCyes][_RSyes][_STyes][_LOyes][_MEyes][_NMmyname]"
   WI = width (default: automatic)
   HE = height (default: automatic)
   TB = toolbars (default: no)
   SC = Scrollbars (default: no)
   RS = Resizable (default: no)
   ST = Status bar (default: no)
   LO = Location bar (default: no)
   ME = Menus (default: no)
   NM = Window name (default: popup)

*/


	// constants/configuration
		if(typeof(intDragAndDropGridWidth)=='undefined')	var intDragAndDropGridWidth = 16;
		if(typeof(intDragAndDropGridHeight)=='undefined')	var intDragAndDropGridHeight = 16;
		if(typeof(strTransparentImg)=='undefined')			var strTransparentImg = '_alpha.png';
	// primary functions - functionality
		// returns a string of parameters found in the classname which can be [eval]uated
		function getClassParameter(objNode,strClassNameHint){
			// get the className
			var arrClassNames = objNode.className.split(' '); var strClass; var intClass = 0;
			while(strClass==null && intClass<arrClassNames.length){
				strClass = (arrClassNames[intClass].toLowerCase().indexOf(strClassNameHint.toLowerCase())>-1) ? arrClassNames[intClass] : null;
				intClass += 1;
			}
			// if the classname is valid
			if(strClass!=null){
				// get class parameters
				var arrClassParams = strClass.split('_'); var evalParams = '';
				for(var intParam=1; intParam<arrClassParams.length; intParam++){
					evalParams += "var " + arrClassParams[intParam].substr(0,2) + "= '" + arrClassParams[intParam].substr(2) + "';";
				}
			}
			return evalParams;
		}
		// return a parameter from the url's query strings
		function getQueryParameter(strParamName){
			// split the query string at the parameter name
			var arrQueryParameter = document.location.search.split(strParamName+"=");
			// split the parameter value from the rest of the string
			var strQueryParameter = (arrQueryParameter.length>1) ? arrQueryParameter[1].split("&")[0] : null ;
			// return the value
			return strQueryParameter;
		}
	// secondary function - constructors
		function parseForClasses(){
			var strClass, arrClass
			// get all elements
			var objAll = (document.all) ? document.all : document.getElementsByTagName("*");
			// for all elements
			for(var intA=0; intA<objAll.length; intA++){
				// get the element's class attribute
				strClass = objAll[intA].className;
				// if there is a class
				if(strClass!=null){	
					// split the class attribute into classes
					arrClass = strClass.split(' ');
					// for all sub-classes
					for(var intB=0; intB<arrClass.length; intB++){
						// choose known classes
						switch(arrClass[intB].toLowerCase()){
							// replace in class
							case "classmousehover" :
								objAll[intA].onmouseover = addClassHover;
								objAll[intA].onmouseout = remClassHover;
								//objAll[intA].onclick = addClassActive;
								break;
							// replace in src sub-string
							case "srcmousehover" :
								cacheSrcHover(objAll[intA]);
								objAll[intA].onmouseover = addSrcHover;
								objAll[intA].onmouseout = remSrcHover;
								break;
							// add display='none'; on parse
							case "hidethisnode" : 
								/*event*/;
								objAll[intA].style.display = 'none';
								break;
							// affirms the visibility status in regard to toggles
							case "showthisnode" : 
								/*event*/;
								objAll[intA].style.display = 'block';
								objLastOpened = objAll[intA];
								break;
							// add display='none'; to parent node
							case "closeparentnode" : 
								/*event*/;
								objAll[intA].onclick = closeParentNode;
								break;

							// Add a className to a tag using the query parameter "class"',
							case "addquerytoclassname" :
								addQueryToClassName(objAll[intA]);
								break;


							// Resizes the window to avoid a scrollbar
							case "resizetofit" :
								objAll[intA].onload = resizeToFit;
								resizeToFit();
								break;
							// Alternates the classes of a table's rows and columns
							case "zebratable" :
								zebraTable(objAll[intA]);
								break;
							// Makes the headers of a table click/sortable
							case "sorttable" :
								objAll[intA].onclick = sortTable;
								break;

							// Open print dialog
							case "openasprintable" :
								objAll[intA].onclick = openAsPrintable;
							// Make dropdown menu
							case "dropdownmenu" :
								dropDownMenu(objAll[intA]);
							// Make foldout menu
							case "foldoutmenu" :
								foldOutMenu(objAll[intA]);
							default :
								/*event*/;
						}
						// check for parsable classes
						if(arrClass[intB].toLowerCase().indexOf("openaspopup")>-1) objAll[intA].onclick = openAsPopup;
						if(arrClass[intB].toLowerCase().indexOf("setrandomsrc")>-1) setRandomSrc(objAll[intA]);
						if(arrClass[intB].toLowerCase().indexOf("togglenextnode")>-1) objAll[intA].onclick = toggleNextNode;
						if(arrClass[intB].toLowerCase().indexOf("matchactiveurl")>-1) matchActiveUrl(objAll[intA]);
						if(arrClass[intB].toLowerCase().indexOf("validateinput")>-1) objAll[intA].onblur = validateInput;
						if(arrClass[intB].toLowerCase().indexOf("minheight")>-1){
							// immediate event
							minHeight(objAll[intA]);
							// store object for acter resize
							arrHeightAdjusts[arrHeightAdjusts.length] = objAll[intA];
							window.onresize = setDimensions;
						}
						if(arrClass[intB].toLowerCase().indexOf("maxwidth")>-1){
							// immediate event
							maxWidth(objAll[intA]);
							// store object for acter resize
							arrWidthAdjusts[arrWidthAdjusts.length] = objAll[intA];
							window.onresize = setDimensions;
						}
						if(arrClass[intB].toLowerCase().indexOf("listscroller")>-1) listScroller(objAll[intA]);
					}
				}
			}
		}
	// ternary function - event handlers
		function openAsPrintable(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
// TODO: exchange stylesheet with print stylsheet
			// open the print dialog
			window.print();
		}

			// resize helpers
			arrHeightAdjusts = new Array();
			arrWidthAdjusts = new Array();
			function setDimensions(){
				for(var intA=0; intA<arrHeightAdjusts.length; intA++){
					arrHeightAdjusts[intA].style.height = 'auto';
					minHeight(arrHeightAdjusts[intA]);
				}
				for(var intA=0; intA<arrWidthAdjusts.length; intA++){
					arrWidthAdjusts[intA].style.width = 'auto';
					maxWidth(arrWidthAdjusts[intA]);
				}
			}
		function minHeight(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// get the height parameters
			var strValidatorName, strMinHeight, strOffSet;		
			eval(getClassParameter(objNode,'minHeight'));
			strMinHeight	= (typeof(HE)!='undefined') ? HE : null ;
			strOffSet		= (typeof(OF)!='undefined') ? OF : null ;

			// get the current document and window dimensions
			var intDocHeight, intCanvasHeight;
			intDocHeight	= document.body.scrollHeight;
			intCanvasHeight	= (typeof(window.innerHeight)!='undefined') ? window.innerHeight : document.body.offsetHeight ;
			// adjust target container to fill the difference in dimensions
			var intMinHeight	= (strMinHeight.indexOf('pct')>-1) ? Math.round(intCanvasHeight * parseInt(strMinHeight) / 100) : parseInt(strMinHeight) ;
			var intOffSet		= (strOffSet.indexOf('pct')>-1) ? Math.round(intCanvasHeight * parseInt(strOffSet) / 100) : parseInt(strOffSet) ;
				// MSIE compensation
				if(document.all) intOffSet += 4;
			if(intDocHeight<intCanvasHeight) objNode.style.height = (intMinHeight - intOffSet) + 'px';
		}
		function maxWidth(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// get the width parameters
			var strValidatorName, strMaxWidth, strOffSet;		
			eval(getClassParameter(objNode,'maxWidth'));
			strMaxWidth		= (typeof(WI)!='undefined') ? WI : null ;
			strOffSet		= (typeof(OF)!='undefined') ? OF : null ;
			// get the current document and window dimensions
			var intDocWidth, intCanvasWidth;
			intDocWidth		= document.body.scrollWidth;
			intCanvasWidth	= (typeof(window.innerWidth)!='undefined') ? window.innerWidth : document.body.offsetWidth ;
			// adjust target container to fill the difference in dimensions
			var intMaxWidth	= (strMaxWidth.indexOf('pct')>-1) ? Math.round(intCanvasWidth * parseInt(strMaxWidth) / 100) : parseInt(strMaxWidth) ;
			var intOffSet	= (strOffSet.indexOf('pct')>-1) ? Math.round(intCanvasWidth * parseInt(strOffSet) / 100) : parseInt(strOffSet) ;
			if(intDocWidth>intMaxWidth) objNode.style.width = (intMaxWidth - intOffSet) + 'px';
		}
			// sort helpers
			function sortNodesForward(objA,objB){
				var intCompare = 0;
				// get the string values from the nodes
				strA = (objA.getElementsByTagName(strSortColTag)[intSortCol].childNodes.length == 0) ? ' ' : objA.getElementsByTagName(strSortColTag)[intSortCol].innerHTML;
				strB = (objB.getElementsByTagName(strSortColTag)[intSortCol].childNodes.length == 0) ? ' ' : objB.getElementsByTagName(strSortColTag)[intSortCol].innerHTML;
				// get the numeric values from the nodes
				intA = parseInt(strA);
				intB = parseInt(strB);
				// compare the values for the sort funtion
				if(strA==strB || (navigator.appVersion.indexOf('MSIE 5.0')>-1)){
					// equal
					return 0;
				}else if(isNaN(intA) || isNaN(intB)){
					// remove any tags that might be in the way
					var regTags = new RegExp('<(.|\n)+?>','gi');
					strA = strA.replace(regTags,'');
					strB = strB.replace(regTags,'');
					// compare the textual values
					return (strA>strB) ? 1 : -1 ;
				}else{
					// compare the numeric values
					return intB - intA;
				}
			}
			function sortNodesReverse(objA,objB){
				var intCompare = 0;
				// get the string values from the nodes
				strA = (objA.getElementsByTagName(strSortColTag)[intSortCol].childNodes.length == 0) ? ' ' : objA.getElementsByTagName(strSortColTag)[intSortCol].innerHTML;
				strB = (objB.getElementsByTagName(strSortColTag)[intSortCol].childNodes.length == 0) ? ' ' : objB.getElementsByTagName(strSortColTag)[intSortCol].innerHTML;
				// get the numeric values from the nodes
				intA = parseInt(strA);
				intB = parseInt(strB);
				// compare the values for the sort funtion
				if(strA==strB || (navigator.appVersion.indexOf('MSIE 5.0')>-1)){
					// equal
					return 0;
				}else if(isNaN(intA) || isNaN(intB)){
					// remove any tags that might be in the way
					var regTags = new RegExp('<(.|\n)+?>','gi');
					strA = strA.replace(regTags,'');
					strB = strB.replace(regTags,'');
					// compare the textual values
					return (strA<strB) ? 1 : -1 ;
				}else{
					// compare the numeric values
					return intA - intB;
				}
			}
		var intSortCol, strSortRowTag, strSortColTag;
		function sortTable(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// defaults
			intSortCol		= 0;
			strSortRowTag	= 'TR';
			strSortColTag	= 'TD';
			strSortDir		= 'forwardSorted';
			// Find column number
			var objSiblings	= objNode.parentNode.getElementsByTagName(objNode.nodeName);
			for(var intA=0; intA<objSiblings.length; intA++){
				// test if this is the clicked node
				if(objSiblings[intA] == objNode){
					intSortCol = intA;
					strSortDir = (objSiblings[intA].className.indexOf('forwardSorted')>-1) ? 'reverseSorted' : 'forwardSorted' ;
				}
				// unmark any previously sorted column
				objSiblings[intA].className = objSiblings[intA].className.replace('forwardSorted','');
				objSiblings[intA].className = objSiblings[intA].className.replace('reverseSorted','');
			}
			// make a nodelist
			var objNodeTable	= (objNode.parentNode.parentNode.nodeName != 'TABLE') ? objNode.parentNode.parentNode.parentNode : objNode.parentNode.parentNode ;
			var objNodeRoot		= objNode.parentNode.parentNode ;
			var objNodeList		= objNodeRoot.getElementsByTagName(strSortRowTag);
			var arrNodeList		= new Array();
			// for all table rows (except the header)
			for(var intA=0; intA<objNodeList.length; intA++){
				if(objNodeList[intA].getElementsByTagName('TH').length<1){
					arrNodeList[arrNodeList.length] = objNodeList[intA];
				}
			}
			// sort the collection using a helper function
			arrNodeList = (strSortDir=='forwardSorted') ? arrNodeList.sort(sortNodesForward) : arrNodeList.sort(sortNodesReverse);
			// clear the unsorted nodelist
			for(var intA=0; intA<objNodeList.length; intA++){
				if(objNodeList[intA].getElementsByTagName('TH').length<1){
					objNodeRoot.removeChild(objNodeList[intA]);
				}
			}
			// append the sorted nodelist
			for(var intA=0; intA<arrNodeList.length; intA++){
				objNodeRoot.appendChild(arrNodeList[intA]);
			}
			// reapply the zebra effect
			if(objNodeTable.className.toLowerCase().indexOf('zebratable')>-1) zebraTable(objNodeTable);
			// mark the newly sorted column
			objNode.className += ' ' + strSortDir;
		}
		function zebraTable(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			var objRows, objCols, intCellNumber;
			// get all table rows
			objRows = objNode.getElementsByTagName('TR');
			// for all table rows
			for(var intRow=0; intRow<objRows.length; intRow++){
				// undo any previous classing
				objRows[intRow].className = objRows[intRow].className.replace('odd','');
				objRows[intRow].className = objRows[intRow].className.replace('even','');
				// add oddrow or evenrow class to the row
				objRows[intRow].className += (intRow%2==0) ? ' odd' : ' even' ;
				// and row and col counters if they're not allready present
				if(objRows[intRow].className.indexOf('row_')<0) objRows[intRow].className += ' row_' + intRow;
				// get all nodes in this row
				objCols = objRows[intRow].childNodes;
				// for every node in the row
				intCellNumber = 0;
				for(var intCol=0; intCol<objCols.length; intCol++){
					// is this a cell or a header
					if(objCols[intCol].nodeName.indexOf('text')<0){
						// undo any previous classing
						objCols[intCol].className = objCols[intCol].className.replace('odd','');
						objCols[intCol].className = objCols[intCol].className.replace('even','');
						// add oddcol or evencol class
						objCols[intCol].className += (intCellNumber%2==0) ? ' odd' : ' even' ;
						// and row and col counters if they're not allready present
						if( objCols[intCol].className.indexOf('col_')<0) objCols[intCol].className += ' col_' + intCellNumber;
						// keep cell numbers
						intCellNumber += 1;
					}
				}
			}
		}
		function resizeToFit(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			var intScrollX, intScrollY, intWinWidth, intWinHeight, intMaxWidth, intMaxHeight;
			// start dimensions
			intMaxWidth = screen.availWidth;
			intMaxHeight = screen.availHeight;
			// while the scroll position is not 0
			var intWhileCount = 0;
			do{
				// scroll the document by 1 pixel
				window.scrollTo(1,1);
				// measure the scroll position			
				intScrollX = (document.all) ?  document.body.scrollLeft : window.pageXOffset ;
				intScrollY = (document.all) ? document.body.scrollTop : window.pageYOffset ;
				// measure window size
				intWinWidth = (document.all) ? document.body.offsetWidth : window.innerWidth ;
				intWinHeight = (document.all) ? document.body.offsetHeight : window.innerHeight ;
				// if the scroll position is not 0
				if(intScrollX>0){
					// make the window larger
					window.resizeBy(32,0)
				}
				if(intScrollY>0){
					// make the window larger
					window.resizeBy(0,32)
				}
				// count the steps
				intWhileCount += 1;
			}while((intScrollX>0 || intScrollY>0) && intWinWidth<intMaxWidth && intWinHeight<intMaxHeight && intWhileCount<32);
		}
		function validateAllInput(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			var booPassed = true;
			// get all subnodes
			var objSubNodes = (objNode.all) ? objNode.all : objNode.getElementsByTagName("*") ;
			// for all nodes
			for(var intA=0; intA<objSubNodes.length; intA++){
				// Does this node have the validateInput put class? Invoke the validator function upon it.
				if(objSubNodes[intA].className.toLowerCase().indexOf('validateinput')>-1) booPassed = (validateInput(objSubNodes[intA]) && booPassed);
			}
			// is the form valid enough?
			return booPassed;
		}
			// custom validation functions
			function validate_bankaccount(objNode){
				var intDeel, intRest;
				var strInput = objNode.value;
				var intTot=0;
				if (strInput.length!=9){
					return false;
				}else{
					for (i=0; i<strInput.length; i++) intTot += strInput.substr(i,1) * (9 - i);
					intDeel = intTot/11;
					intRest = intTot%11;
					return (intRest==0);
				}
			}
		function validateInput(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// default validator values
			var booEmptyTest,booBooValidator,booRegExpValidator, regExpValidator,booFuncValidator;
			// get the warning message
			var objWarningNode = (objNode.nextSibling.nodeName.indexOf("text")<0) ? objNode.nextSibling : objNode.nextSibling.nextSibling ;
			// get the type of validation required			
			eval(getClassParameter(objNode,'validateInput'));
			strValidatorName	= (typeof(TY)!='undefined') ? TY : '' ;
			intAllowEmpty		= (typeof(AE)!='undefined') ? parseInt(AE) : 0 ;
			// empty test
			booEmptyTest = (intAllowEmpty==1 && objNode.value=='') ? true : false ;
			// boolean test
			switch(strValidatorName){
// TODO: need to check all radio buttons in one family
				case 'isradiochecked' : 
					booBooValidator = true;
				default :
					booBooValidator = true;
			}
			// regular expression test
			if(navigator.appVersion.indexOf('MSIE 5.0')>-1 && strValidatorName=='money') strValidatorName = null;
			switch(strValidatorName){
				case 'email' : 
					booRegExpValidator = (objNode.value.match(/^[\w\.\-\,\+]+@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$/)!=null);
					break;
				case 'phone' : 
					booRegExpValidator = (objNode.value.match(/(^\+[0-9]{2}|^\+[0-9]{2}\(0\)|^\(\+[0-9]{2}\)\(0\)|^00[0-9]{2}|^0)([0-9]{9}$|[0-9\-\s]{10}$)/)!=null); 
					break;
				case 'dutchzipcode' : 
					booRegExpValidator = (objNode.value.match(/^[0-9]{4}\s{0,1}[a-zA-Z]{2}$/)!=null); 
					break;
				case 'date' : 
					booRegExpValidator = (objNode.value.match(/^\d{4}\-\d{1,2}\-\d{1,2}$/)!=null);
					break;
				case 'memberid' : 
					booRegExpValidator = (objNode.value.match(/^[0-9]+$/)!=null); 
					break;
				case 'money' :
					regExpValidator = new RegExp('^(?!\u00a2)(?!0,?\d)(\d{1,3}(\.\d{3})*|(\d+))(\,\d{2})?$');
					booRegExpValidator = (objNode.value.match(regExpValidator)!=null);
					break;
				case 'alphanumeric' :
					booRegExpValidator = (objNode.value.match(/^[a-zA-Z0-9]/)!=null);
				default :
					booRegExpValidator = true;
			}
			// custom test
			switch(strValidatorName){
				case 'bankaccount' :
					booFuncValidator = validate_bankaccount(objNode);
					break;
				case 'notempty' :
					booFuncValidator = (objNode.value!="");
					break;
				default :
					booFuncValidator = true;
			}
			// close the error message by default
			objWarningNode.style.display = 'none';
			// show or hide the warning message based on the validator's match
			if(!booEmptyTest)objWarningNode.style.display = (booBooValidator && booRegExpValidator && booFuncValidator) ? 'none' : 'block' ;
			// return a pass of fail boolean to whoever may want to know the results of the test
			return !(objWarningNode.style.display=='block');
		}
		function addQueryToClassName(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// get the query parameter
			var strQueryParameter = getQueryParameter("class");
			// add to front of classNames
			if(strQueryParameter!=null) objNode.className = strQueryParameter + ' ' + objNode.className;
		}
		function addQueryToSrc(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// get the query parameter
			var strQueryParameter = getQueryParameter("src")
			// add to front of classNames
			if(strQueryParameter!=null) objNode.src = objNode.src.replace('.','_'+strQueryParameter+'.');
		}
		var objPopup;
		function openAsPopup(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// get the parameters from the classname
			eval(getClassParameter(objNode,'openAsPopUp'));
			// get width parameter
			var strWidth		= (typeof(WI)!='undefined') ? 'width='+WI : '' ;
			// get height parameter
			var strHeight		= (typeof(HE)!='undefined') ? ',height='+HE : '' ;
			// get toolbar string
			var strToolbars		= (typeof(TB)!='undefined') ? ',toolbar='+TB : ',toolbar=no' ;
			// get scrolling string
			var strScrolling	= (typeof(SC)!='undefined') ? ',scrollbars='+SC : ',scrollbars=no' ;
			// get status string
			var strStatus		= (typeof(ST)!='undefined') ? ',status='+ST : ',status=no' ;
			// get resizable string = 
			var strResize		= (typeof(RS)!='undefined') ? ',resizable='+RS : ',resizable=no' ;
			// get resizable string = 
			var strLocation		= (typeof(LO)!='undefined') ? ',location='+LO : ',location=no' ;
			// get resizable string = 
			var strMenu			= (typeof(ME)!='undefined') ? ',menu='+ME : ',menu=no' ;
			// window name
			var strName			= (typeof(NM)!='undefined') ? NM : 'popup' ;
			// open requested window
			objPopup = window.open(objNode.getAttribute('href'), strName, strWidth+strHeight+strScrolling+strToolbars+strStatus+strResize+strLocation+strMenu);
			objPopup.focus();
			// cancel click
			return false;
		}
		function setRandomSrc(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// get the parameters from the classname
			eval(getClassParameter(objNode,'setRandomSrc'));
			// get min parameter
			var intMin		= (typeof(MN)!='undefined') ? parseInt(MN) : 0 ;
			// get max parameter
			var intMax		= (typeof(MX)!='undefined') ? parseInt(MX) : 1 ;
			// generate random number
			var intRandom = Math.round(Math.random()*(intMax-intMin))+intMin;
			// replace default increment by random number
			objNode.src = objNode.src.replace('_0','_'+intRandom);
		}
			function hasNoStateClass(objNode){
				return (objNode.className.indexOf('link')<0 && objNode.className.indexOf('hover')<0 && objNode.className.indexOf('active')<0);
			}
		function addClassHover(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// replace link by hover
			objNode.className = (hasNoStateClass(objNode)) ? 'hover ' + objNode.className : objNode.className.replace('link','hover') ;
		}
		function remClassHover(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// replace hover by link
			objNode.className = (hasNoStateClass(objNode)) ? 'link ' + objNode.className : objNode.className.replace('hover','link') ;
		}
		function addClassActive(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// 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(hasNoStateClass(objNode)) objNode.className = 'active ' + objNode.className;
		}
			// helper functions for srcMouseHover
			var arrCachedImages = new Array();
			function cacheSrcHover(that) {
				var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
				// replace link by hover
				var intCachedImageIdx = arrCachedImages.length;
				// hover version
				arrCachedImages[intCachedImageIdx] = new Image();
				arrCachedImages[intCachedImageIdx].src = objNode.src.replace('link','hover');
				// active version
				arrCachedImages[intCachedImageIdx+1] = new Image();
				arrCachedImages[intCachedImageIdx+1].src = objNode.src.replace('link','active');
			}
		function addSrcHover(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// replace link by hover
			objNode.src = objNode.src.replace('link','hover');
		}
		function remSrcHover(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// replace link by hover
			objNode.src = objNode.src.replace('hover','link');
		}
			// helper function for 
			var objLastOpened;
			function toggleThisNode(that, strClosePrevious){
				var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
				// restore previous node
				if(objLastOpened!=null && objLastOpened!=objNode && strClosePrevious=='yes') objLastOpened.style.display = 'none';
				// toggle node's visibility
				objNode.style.display = (objNode.style.display=='none') ? 'block' : 'none' ;
				// remember last node
				objLastOpened = objNode;	
			}
		var objLastToggled;
		function toggleNextNode(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// determine the next node
			var objNextNode = (objNode.nextSibling.nodeName.indexOf("text")<0) ? objNode.nextSibling : objNode.nextSibling.nextSibling ;
			// if there is a next node
			if(objNextNode!=null){
				// get the parameters from the classname
				eval(getClassParameter(objNode,'toggleNextNode'));
				// get parent recursion
				var strClosePrevious = (typeof(CP)!='undefined') ? CP : 'no' ;
				// toggle it's visibility
				toggleThisNode(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(objLastToggled!=null && objLastToggled!=objNode && strClosePrevious=='yes'){
						objLastToggled.className = objLastToggled.className.replace('active','link');
						objLastToggled.src = objLastToggled.src.replace('active','link');
					}
				}
				// remember last node
				objLastToggled = objNode;
			}
			// cancel onclick event
			return false;
		}
		function closeParentNode(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// hide the parent node
			objNode.parentNode.style.display = 'none';
			// restore previous node's click state
			if(objLastToggled!=null && objLastToggled!=objNode) objLastToggled.className = objLastToggled.className.replace('active','link');
			// cancel onclick event
			return false;
		}
		function pngAlpha(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// if the image has been processed before
			if(objNode.src.indexOf('_alpha')<0){
				// alpha image url
				var strAlphaSrc = objNode.src.replace(/.png|.jpg|.gif/gi,"_alpha.png")
				// for the downloeve browser MSIE
				if(typeof(objNode.style.filter)!='undefined'){
					// change the image styles
					objNode.style.width		= objNode.width + 'px';
					objNode.style.height	= objNode.height + 'px';
					objNode.style.filter	= "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + strAlphaSrc + "')";
					// get the path to the image folder
					var strPathSrc = '';
					var arrPathSrc = objNode.src.split('/');
					for(var intA=0; intA<arrPathSrc.length-1; intA++){strPathSrc += arrPathSrc[intA] + '/'};
					// replace the original with the alpha variant
					objNode.src = strPathSrc + strTransparentImg;
				// for the rest of the world
				}else{
					// replace the image source with the alpha channel version
					objNode.src = strAlphaSrc;
				}
			}
		}
			// drag and drop helper functions
			function dragRestore(that){
				var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
				// is lib_cookies available
				if(typeof(setCookie)!='undefined'){
					var strStyles, arrStyles;
					// retrieve styles string
					strStyles = getCookie('dragposition');					
					// were any styles recovered
					if(strStyles!=null){
						arrStyles = strStyles.split(',');
						// does the stored positions match the object
						if(arrStyles[0]==objNode.id && arrStyles.length>2){
							objNode.style.left = arrStyles[1];
							objNode.style.top = arrStyles[2];
						}
					}
				}
			}
			function dragStore(that){
				var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
				// is lib_cookies available
				if(typeof(setCookie)!='undefined'){
					// store styles
					setCookie('dragposition', objNode.id + ',' + objNode.style.left + ',' + objNode.style.top, null, '/', null, null);
				}
			}
		var intPickupX, intPickupY, intPickupZ;
		function dragPickUp(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// store pickup location
			intPickupX = (document.all) ? event.x : that.layerX ;
			intPickupY = (document.all) ? event.y : that.layerY ;
			intPickupZ = objNode.style.zIndex;
			// default starting position if none was given
			if(objNode.style.position!='absolute') objNode.style.position = 'absolute';
			if(objNode.style.left=='') objNode.style.left = 0 + 'px'; 
			if(objNode.style.top=='') objNode.style.top = 0 + 'px';
			// promote z position
			objNode.style.zIndex = 1024;
			// cancel browser mouse handler
			return false;
		}
		var intGridX=intDragAndDropGridWidth; var intGridY=intDragAndDropGridHeight;
		function dragDropDown(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// snap coordinates to grid
			if(intGridX>0) objNode.style.left = Math.round(parseInt(objNode.style.left)/intGridX)*intGridX + "px";
			if(intGridY>0) objNode.style.top = Math.round(parseInt(objNode.style.top)/intGridY)*intGridY + "px";
			// restore z position
			objNode.style.zIndex = intPickupZ;
			// clear pickup location
			intPickupX = null;
			intPickupY = null;
			intPickupZ = null;
			// store the position in a cookie
			dragStore(objNode);
			// cancel browser mouse handler
			return false;
		}
		function dragMoveAway(that){
			if(intPickupZ!=null){
				var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
				// mouse position
				intEventX = (document.all) ? event.x : that.layerX ;
				intEventY = (document.all) ? event.y : that.layerY ;
				// current object position
				var intStyleX = (objNode.style.left.indexOf('px')<0) ? 0 : parseInt(objNode.style.left) ;
				var intStyleY = (objNode.style.top.indexOf('px')<0) ? 0 : parseInt(objNode.style.top) ;
				// new object position
				if(intPickupX!=null) objNode.style.left = (intStyleX+intEventX-intPickupX) + 'px';
				if(intPickupY!=null) objNode.style.top = (intStyleY+intEventY-intPickupY) + 'px';
				// update pickup location (for some browsers)
				if(document.all) intPickupX = intEventX;
				if(document.all) intPickupY = intEventY;
				// cancel browser mouse handler
				return false;
			}
		}
		function showAsCode(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// replace html tags
			objNode.innerHTML = objNode.innerHTML.replace(/</gi,"&lt;").replace(/>/gi,"&gt;\n").replace(/ /gi,"&nbsp;").replace(/\t/gi,"&nbsp;&nbsp;&nbsp;").replace(/\n/gi,"<br />");
		}
			// helper functions for matchActiveUrl()
			function convertAbsToRelUrls(strUrl){
				// is the url a relative path
				if(strUrl.indexOf('/')<0 || strUrl.substr(0,1)=='.' || strUrl.substr(0,1)=='/'){
					// the current absolute path
					strAbs = document.location.href;
					// remove the filename from the end
					strAbs = strAbs.substring(0, strAbs.lastIndexOf('/'));
					// while there are parent markers in the url
					while(strUrl.indexOf('../')==0){
						// remove one level from the absolute path
						strUrl = strUrl.replace('../','');
						// remove one parent marker from the relative path
						strAbs = strAbs.substring(0, strAbs.lastIndexOf('/'));
					}
					// remove all current dir markers from the relative url
					strUrl = strUrl.replace(/\.\//gi,'');
					// add the url to the absolute path
					strUrl = strAbs + '/' + strUrl;
				}
				return strUrl;
			}
			function compareUrls(strUrlA,strUrlB){
				var intCurScore = 0;
				var intPotScore = 0;
				var intMaxScore = 0;
				var intA,intB;
				// replace most common illegal characters
				strUrlA = strUrlA.replace(/ /gi,"%20");
				strUrlB = strUrlB.replace(/ /gi,"%20");
				// remove anchors
				strUrlA = strUrlA.split('#')[0];
				strUrlB = strUrlB.split('#')[0];
				// make sure both paths are absolute
				strUrlA = convertAbsToRelUrls(strUrlA);
				strUrlB = convertAbsToRelUrls(strUrlB);
				// split the urls into manageable strings
				var arrUrlA = strUrlA.split(/[?&#\/]/i);
				var arrUrlB = strUrlB.split(/[?&#\/]/i);
				// for every string of UrlA
				for(intA=0; intA<arrUrlA.length; intA++){
					// is the string in the substrings of UrlB
					intB = 0; while(intB<arrUrlB.length && arrUrlA[intA]!=arrUrlB[intB]) intB += 1;
					// if a match was found, add length of string A to current score
					if(intB<arrUrlB.length) intCurScore += arrUrlA[intA].length;
					// add length of string A to potential score
					intPotScore += arrUrlA[intA].length;
				}
				// calcultate maximum score possible
				intMaxScore = strUrlB.length - arrUrlB.length + 1;
				// return the compare-score
				return intCurScore/intPotScore;
			}
		function matchActiveUrl(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// get the parameters from the classname
			eval(getClassParameter(objNode,'matchActiveUrl'));
			// get parent recursion
			var intToParent	= (typeof(PR)!='undefined') ? parseInt(PR) : 0 ;
			// get the url and clean it up
			var strUrl = convertAbsToRelUrls(document.location.href);
			// get the href and clean it up
			var strHref = convertAbsToRelUrls(objNode.getAttribute('href'));
			// was the data bad
			if(strHref!=null){
				// compare score
				var ftlCompareScore = compareUrls(strUrl, strHref) * compareUrls(strHref, strUrl);
				// if the href matches the url 
				if(ftlCompareScore==1){
					// add the active class to the target item
					addClassActive(objNode);
					// if a parent node also needs to be marked
					if(intToParent>0){
						// get the relevant parent node
						for(var intA=0; intA<intToParent; intA++) objNode = objNode.parentNode;
						// if the href matches the url
						if(ftlCompareScore==1){
							// add the active class to the parent item
							addClassActive(objNode);
						}
					}
					// report a match
					return true;
				}
			}
			// report no match
			return false;
		}
			function recurseActiveNode(objParentNode){
				// emulate addActive
				if(objParentNode.getElementsByTagName('A').length>0) addClassActive(objParentNode.getElementsByTagName('A')[0]);
				// emulate toggleNextNode
				if(objParentNode.getElementsByTagName('IMG').length>0) toggleNextNode(objParentNode.getElementsByTagName('IMG')[0]);
				// next recursion to same node type
				if(objParentNode.nodeName == objParentNode.parentNode.parentNode.nodeName) recurseActiveNode(objParentNode.parentNode.parentNode);
			}
		function dropDownMenu(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			var objNodes, objMatch;
			// apply events to all ULs
			objNodes = objNode.getElementsByTagName('UL');
			for(var intNode=0; intNode<objNodes.length; intNode++){
				// hideThisNode
				objNodes[intNode].style.display = 'none';
			}
			// apply events to all IMGs
			objNodes = objNode.getElementsByTagName('IMG');
			for(var intNode=0; intNode<objNodes.length; intNode++){
				// if this node has children atempt to rename the images
				if(objNodes[intNode].parentNode.getElementsByTagName('UL').length>0) objNodes[intNode].src = objNodes[intNode].src.replace('_child', '_parent');
				// toggleNextNode
				objNodes[intNode].onclick = toggleNextNode;
			}
			// apply events to all As
			objNodes = objNode.getElementsByTagName('A');
			for(var intNode=0; intNode<objNodes.length; intNode++){
				// matchActiveUrl
				objMatch = matchActiveUrl(objNodes[intNode]) ? objNodes[intNode] : objMatch ;
			}
			// recurse back the last matching node
			if(objMatch!=null) recurseActiveNode(objMatch.parentNode);
		}
			function addClassHoverProxy(that){
				var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
				// emulate the parent node's mouseout event
				addClassHover(objNode);
			}
			function remClassHoverProxy(that){
				var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
				// emulate the parent node's mouseout event
				remClassHover(objNode);
			}
		function foldOutMenu(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			var objNodes, objMatch;
			// apply events to all LIs
			objNodes = objNode.getElementsByTagName('LI');
			for(var intNode=0; intNode<objNodes.length; intNode++){
				// mouseover events
				objNodes[intNode].onmouseover	= addClassHoverProxy;
				objNodes[intNode].onmouseout	= remClassHoverProxy;
			}
		}
			function Scroller(){
				// parameters
				this.object			=	null;
				this.dimensions 	=	new Coordinates();
				this.limits			=	new Coordinates();
				this.speed			=	new Coordinates();
				this.distance		=	new Coordinates();
				this.delay			=	null;
				this.interval		=	null;
				// functions
				this.step			=	function(){
											var scrollCanvas		=	this.object.getElementsByTagName('UL')[0];
											// update styles
											scrollCanvas.style.left	=	(Math.abs(this.distance.x)>=Math.abs(this.limits.x)) ? '0px' : (this.distance.x + this.speed.x) + 'px';
											scrollCanvas.style.top	=	(Math.abs(this.distance.y)>=Math.abs(this.limits.y)) ? '0px' : (this.distance.y + this.speed.y) + 'px';
											// update stored positions
											this.distance.x			=	parseInt(scrollCanvas.style.left);
											this.distance.y			=	parseInt(scrollCanvas.style.top);
											return 0;
										}
				this.start			=	function(){
											scroller.interval		= setInterval('scroller.step()',scroller.delay);
											return 0;
										}
				this.stop			=	function(){
											clearInterval(scroller.interval);
											return 0;
										}
			}
				function Coordinates(){
					this.x = 0;
					this.y = 0;
				}
		var scroller = new Scroller();
		function listScroller(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// get the parameters from the classname
			eval(getClassParameter(objNode,'listScroller'));
			// make a new instance of the scroller object
			scroller.object			= objNode;
			scroller.dimensions.x	= (typeof(DX)!='undefined') ? parseInt(DX) : 256 ;
			scroller.dimensions.y	= (typeof(DY)!='undefined') ? parseInt(DY) : 75 ;
			scroller.speed.x		= (typeof(SX)!='undefined') ? -1 * parseInt(SX) : -2 ;
			scroller.speed.y		= (typeof(SY)!='undefined') ? -1 * parseInt(SY) : 0 ;
			scroller.delay			= (typeof(DE)!='undefined') ? parseInt(DE) : 64 ;
			// clone the list items for double buffering
			var scrollList			= scroller.object.getElementsByTagName('UL')[0];
			var scrollItems			= scrollList.getElementsByTagName('LI');
			var itemsMax			= scrollItems.length;
			for(var a=0; a<itemsMax; a++){
				var new_node = scrollItems[a].cloneNode(true);
				scrollList.appendChild(new_node); 
			}
			// note the scrolling limits
			scroller.limits.x		= scroller.dimensions.x * itemsMax;
			scroller.limits.y		= scroller.dimensions.y * itemsMax;
			// set prerequisite styles
				//	UL settings
				scrollList.style.width		= (scroller.dimensions.x * 2 * itemsMax) + 'px';
				scrollList.style.height		= (scroller.dimensions.y * 2 * itemsMax) + 'px';
				// LI settings
				for(var a=0; a<scrollItems.length; a++){
					scrollItems[a].style.width	= scroller.dimensions.x + 'px';
					scrollItems[a].style.height	= scroller.dimensions.y + 'px';
				}
			// set the mouseover events
			scroller.object.onmouseover		= scroller.stop;
			scroller.object.onmouseout		= scroller.start;
			// initiate the scroll interval
			scroller.start();
		}
	// events
		//onload = parseForClasses;
		parseForClasses();

