/*
name			: Class Behaviour
update			: 20041004
author			: Frank van Rooijen, Maurice van Creij
dependencies	: lib_classbehaviour.js
info			: /~wmittensblg/content/details.asp?id=20040805133501

1. Replace "link" in class
   class="classMouseHover link"
2. Replace "link" in src
   class="srcMouseHover"
3. Add display:none; on parse
   class="hideThisNode"
4. Add or remove display:none; onclick
   class="toggleNextNode"
5. Add display:none; to parent node
   class="closeParentNode"
6. Replace image with transparent version, invoke directX background loader
   class="pngAlpha"
7. Handle ondrag events
   class="dragAndDrop"
8. Open links in a popup
   class="openAsPopUp[_WI400][_HE300][_TByes][_SCyes][_RSyes][_STyes][_LOyes][_MEyes][_NMmyname]"
   (Everything between [brackets] is optional. Leave out the [brackets] in the classname)
   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)
9. Shows the contents of a container as raw code
   class="showAsCode"
10. Chooses a random increment of an image source
   class="setRandomSrc[_MN0][_MX1]"
   (Everything between [brackets] is optional. Leave out the [brackets] in the classname)
   MN = minimum (default: 0)
   MX = maximum (default: 1)
11. Class a link matching the document's url
   class="matchActiveUrl[_PR0]"
   PR = Apply class to parent (default: 0)
12 Add a className to a tag using the query parameter "class"
   class="addQueryToClassName"
13 Add a suffix to an image source using the query parameter "src"
   class="addQueryToSrc"
14 Validate the value of a for element to a predefined regular expression
   class="validateInput[_TY]"
   (Everything between [brackets] is optional. Leave out the [brackets] in the classname)
   TY = validator type (email,phone,dutchzipcode,date,memberid,money,bankaccount,alphanumeric,notempty,(isradiochecked))
   AE = allow empty (default: 0)
15 Triggers all validateInput class behaviours within a node after the onsubmit event.
   class="validateAllInput"
*/

/* 
TODO: javascript stylesheet parsing for min-height and max-height
var myStyle = document.styleSheets[0].cssRules[0].style;
*/


	// 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].indexOf(strClassNameHint)>-1) ? arrClassNames[intClass] : null;
				intClass += 1;
			}
			// 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" :
								var strClassName = objAll[intA].className;
								objAll[intA].className += (strClassName.indexOf('link')<0 && strClassName.indexOf('active')<0) ? ' link' : '' ;
								objAll[intA].onmouseover = addClassHover;
								objAll[intA].onmouseout = remClassHover;
								//objAll[intA].onclick = addClassActive;
								break;
							// replace in src sub-string
							case "srcmousehover" : 
								objAll[intA].onmouseover = addSrcHover;
								objAll[intA].onmouseout = remSrcHover;
								break;
							// add display='none'; on parse
							case "hidethisnode" : 
								/*event*/;
								objAll[intA].style.display = 'none';
								break;
							// add or remove display='none'; onclick
							case "togglenextnode" : 
								/*event*/;
								objAll[intA].onclick = toggleNextNode;
								break;
							// add display='none'; to parent node
							case "closeparentnode" : 
								/*event*/;
								objAll[intA].onclick = closeParentNode;
								break;
							// replace image with transparent version, invoke activeX background loader
							case "pngalpha" : 
								/*event*/;
								pngAlpha(objAll[intA]);
								objAll[intA].onload = pngAlpha;
								break;
							// handle ondrag events
							case "draganddrop" : 
								/*event*/;
								objAll[intA].onmousedown = dragPickUp;
								objAll[intA].onmouseup = dragDrop;
								objAll[intA].onmousemove = dragMove
								break;
							// show contents as code
							case "showascode" : 
								/* event */
								showAsCode(objAll[intA]);
								break;
							// Add a className to a tag using the query parameter "class"',
							case "addquerytoclassname" :
								addQueryToClassName(objAll[intA]);
								break;
							// Add a suffix to an image source using the query parameter "src"',
							case "addquerytosrc" :
								addQueryToSrc(objAll[intA]);
								break;
							// Triggers all validateInput class behaviours within a node after the onsubmit event.',
							case "validateallinput" :
								objAll[intA].onsubmit = validateAllInput
								break;
							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("matchactiveurl")>-1) matchActiveUrl(objAll[intA]);
						if(arrClass[intB].toLowerCase().indexOf("validateinput")>-1) objAll[intA].onblur = validateInput;
					}
				}
			}
		}
	// ternary function - event handlers
		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,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
			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' : 
					booRegExpValidator = (objNode.value.match(/^(?!\u00a2)(?!0,?\d)(\d{1,3}(\.\d{3})*|(\d+))(\,\d{2})?$/)!=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 addClassHover(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// replace link by 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 = 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');
		}
		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');
		}
		var objLastOpened;
		function toggleThisNode(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// restore previous node
			if(objLastOpened!=null && objLastOpened!=objNode) objLastOpened.style.display = 'none';
			// toggle node's visibility
			objNode.style.display = (objNode.style.display=='none') ? 'block' : 'none' ;
			objLastOpened = objNode;	
		}
		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 ;
			// toggle it's visibility
			toggleThisNode(objNextNode);
		}
		function closeParentNode(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// hide the parent node
			objNode.parentNode.style.display = 'none';
		}
		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;
				}
			}
		}
		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;
			// promote z position
			objNode.style.zIndex = 1024;
			// cancel browser mouse handler
			return false;
		}
		var intGridX=intDragAndDropGridWidth; var intGridY=intDragAndDropGridHeight;
		function dragDrop(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;
			// cancel browser mouse handler
			return false;
		}
		function dragMove(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 />");
		}
		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
			strUrl = document.location.href;
			// get the href
			strHref = objNode.getAttribute('href').replace('../','').split(/[?#]/i)[0];
			// was the bad data
			if(strHref!=null){
				// if the url contains the href is high enough
				if(strUrl.indexOf(strHref)>-1){
					// get the original node
					objNode.className += ' active';
					// get the parent node
					for(var intA=0; intA<intToParent; intA++) objNode = objNode.parentNode;
					// add the active class to the item
					objNode.className += ' active';
					objNode.style.display = 'block';
				}
			}
		}
	// events
		//onload = parseForClasses;
		parseForClasses();
