/*
Javascript validation based on quirksmode.com
example:	http://www.quirksmode.org/dom/error.html
*/

var W3CDOM = (document.getElementsByTagName && document.createElement);//to know if the browser is W3CDOM compatible

//for tabs validations
var joobiErrorTabs=new Array();//store all the tabs that have been declared as containing errors
var joobiErrorFields=new Array();//store all the required fields within tabs for each tabs
var joobiTabs=false;//tells us if we have tabs on that page
var errorMessage='';

/*
function to manage the validation of an html form
@formName:string the form on which the validation is proceeded
@author:John
*/
function validateForm(formId,tab) {
	//elements contained in the form we are validating
	//var formElements = document.getElementById(formId).elements;

	//Start public var(window) defined here
		formHasError = false;
		fullErrorString = '';//used if the browser is not W3CDOM compatible
		firstError = null;	//variable which store the first html object on which there is a validation error
	//End public var(window)

	//for each elements of tab we validate
	for (var i=0;i<tab.length;i++) {
		index = tab[i].indexOf('-',0);
		long = tab[i].length - index - 1;
		name = tab[i].substr(0,index);
		type = tab[i].substr(index+1,long);

		if( validateType(tab[i],type) ){
			formHasError = true;
			errorName = 'error-' + formId;
			document.getElementById(errorName).innerHTML = errorMessage;

			//the browser is not W3C DOM compatible so we return the error as an alert
			if (!W3CDOM)	alert(fullErrorString);

			//we have an error so we focus the mouse on the first field showing it
			if (firstError)	firstError.focus();

			//we just return false if we have a form error
			if(formHasError)	return false;
		}
	}//endfor

	return true;
}//endfct

/*
function to switch the different validation types cases
@formElement:object the current formElement being validated
@type:string the type of validation we want to make there
@author:ben
*/
function validateType(name, type){
	formElement = document.getElementById(name);
	//some predefined types to validate
	var numericSep = "0123456789.,-+";
	var numeric = /[0-9]+/g;
	var alphabetic = /[a-z]+/gi;
	var alphanumeric = /[a-z0-9]+/gi;
	var jFlagError = false;

	switch (type){
		case "req":
			if(formElement.value == ''){jFlagError = true; errorMessage = "Le champ suivant est requis";}
			break;
		case "num":
			//we test the value to be numeric including the separators sucha as ".,-+"
			if(!isLike(formElement.value, numericSep))	jFlagError = true;
			break;
		case "numeric":
			//we test the value to be trully numeric
			if(!isLike(formElement.value, numeric))	jFlagError = true;
			break;
		case "alpha":
			//we test the value to be alphabetic
			var jsmatches=formElement.value.match(alphabetic);
			if(!jsmatches)	jFlagError = true;
			break;
		case "alphanum":
			//we test the value to be alphanumeric
			var jsmatches=formElement.value.match(alphanumeric);
			if(!jsmatches)	jFlagError = true;
			break;
		case "ws":
			var jsmatches=formElement.value.match(/(\s)/);
			if(jsmatches)	jFlagError = true;
			break;
		case "email":
			var pattern = /^[a-zA-Z0-9](([.]?[a-zA-Z0-9_-]+)*)?@([a-zA-Z0-9\-_]+\.)+[a-zA-Z]{2,7}$/;
			if(!verifyPattern(pattern,formElement.value)){jFlagError = true; errorMessage = "Format d'email incorrect";}
			break;
		case "minlgt":
			var Args = strArgs.match(/[a-zA-Z0-9]+/g);
			var minlgt= Args[0];
			if(formElement.value.length < minlgt)	jFlagError = true;
			break;
		case "inf":
			var Args = strArgs.match(/[a-zA-Z0-9]+/g);
			var minlgt= Args[0];
			if(formElement.value < minlgt)	jFlagError = true;
			break;
		case "sup":
			var Args = strArgs.match(/[a-zA-Z0-9]+/g);
			var minlgt= Args[0];
			if(formElement.value > minlgt)	jFlagError = true;
			break;
		case "maxlgt":
			var Args = strArgs.match(/[a-zA-Z0-9]+/g);
			var minlgt= Args[0];
			if(formElement.value.length > minlgt)	jFlagError = true;
			break;
		case "sameas":
			var Args = strArgs.match(/[a-zA-Z0-9_]+/g);
			var comparedElm=document.getElementById(Args[0]);
			if(comparedElm.value!=formElement.value)	{
				jFlagError = true;
				writeError(comparedElm,jCore.msg[type]);
			}
			break;
		case "date":
			break;
		case "ccontain":
			var Args = strArgs.match(/[\W]*(?=(\)))/g);
			var ArgsFinal = new String(Args);
			ArgsFinal=ArgsFinal.substring(1,ArgsFinal.length);
			if(notContains(formElement.value, ArgsFinal))	jFlagError = true;
			break;
		case "cncontain":
			var Args = strArgs.match(/[\W]*(?=(\)))/g);
			var ArgsFinal = new String(Args);
			ArgsFinal=ArgsFinal.substring(1,ArgsFinal.length);

			var message = new String(jCore.msg[type]);
			var msg=message.replace(/\[ILLEGAL_CHAR\]/, ArgsFinal);

			if(!notContains(formElement.value, ArgsFinal))	writeError(formElement,msg);
			break;
		default : break;
	}//endswitch

	if (jFlagError) firstError = formElement;
	return jFlagError;
}//endfct


/**
 * Verifies if the string obey the rules of the patern
@params:pattern a regex pattern eg:/[0-9]/gi
@params:text the text which is being tested
@author:ben
*/
function verifyPattern( pattern , text )
{
	var regex = new RegExp( pattern );
	return regex.test( text );
}



/*test if a field doesn't contains invalidChars.
@params:field the field which is being studied
@params:invalidChars a chain of characters to validate
@author:ben
*/
function notContains(field, invalidChars){
   var isMatching=true;
   var char2;
   for (i = 0; i < field.length && isMatching == true; i++) {
      char2 = field.charAt(i);
      if (invalidChars.indexOf(char2) != -1) isMatching = false;
      }
   return isMatching;
}

/*test if a field is of a certain type.
The type depends on validChars string sent.
@params:field the field which is being studied
@author:ben
*/
function isLike(field, validChars){
   var isMatching=true;
   var char2;
   for (i = 0; i < field.length && isMatching == true; i++) {
      char2 = field.charAt(i);
      if (validChars.indexOf(char2) == -1) isMatching = false;
      }
   return isMatching;
}

/*test if a field is NOT of a certain type.
The type depends on validChars string sent.
@params:field the field which is being studied
@params:validChars a chain of characters to validate
@author:ben
*/
function isNotLike(field, validChars){
   var isNotMatching=false;
   var char2;
   for (i = 0; i < field.length && isNotMatching == false; i++) {
      char2 = field.charAt(i);
      if (validChars.indexOf(char2) == -1) isNotMatching = true;
      }
   return isNotMatching;
}



/*
To write a message next to a conflictive field
@params:obj the html object which triggered the validation error(e.g.:inputbox, select)
@params:message the html object which triggered the validation error(e.g.:message)
@params:objects optional store all the html objects which may remove the message onchange(e.g.:radio)
@author:ben
*/
function writeError(obj,message,objects) {


	//if function WebFXTabPane exists then write into tab
	if(joobiTabs){
		writeErrorTab(obj);
	}

	//we set this object as the first error so that we can focus on it afterwards
	if (!firstError){
		//we come here only once and that means we have a form error for the following
		formHasError=true;
		firstError = obj;
	}

	//if we already have an error on the object we dont addup some more messages
	if (obj.hasError) return;

	if (W3CDOM) {
		obj.className += ' jberror';
		obj.onchange = function(){
			removeError(this,joobiTabs);
		};

		//foreach concerned object we trigger the onchange function so that the error message will be removed onchange of the state
		if(objects){
			for(objectheu in objects){
				objects[objectheu].onchange = function(){
					removeError(obj,joobiTabs);
				};
			}//endfor
		}//endif

		//we write the error message now
		writeMess(obj,message);

	}else {
		fullErrorString += obj.name + ': ' + message + '\n';
		obj.hasError = true;
	}//endif


}//endfct


/*
When a field which is required is nested in a tab we highlight the title of the tab
@params:obj the html object which triggered the validation error(e.g.:inputbox, select)
@author:ben
*/
function writeErrorTab(obj){
	//get the first dom NODE parent of obj
	var parentObj=obj.parentNode;

	//as long as we do not go into a recognised parent tab we continue
	var runaway=false;
	while(!runaway){
		//get the next parent dom NODE for the next round
		parentObj=parentObj.parentNode;

		//if we reach the body tag that means there is no tab there, let's return false
		if(parentObj.nodeName=='BODY')	return false;

		//as long as the tag is not a div or the className of that div is not tab-page we just skip
		//TODO maybe we can remove this hardcoded thing at some point (tab-page)
		if(parentObj.nodeName!='DIV' || (parentObj.nodeName=='DIV' && parentObj.className!='tab-page')){
			continue;
		}else{
			//get the id of that tab
			parentid=parentObj.getAttribute('id');
			//get the name of the Tab
			TabdivHeadName=parentObj.getAttribute('name');

			//if this name is the name we have a match
			//TODO maybe we can remove this hardcoded thing at some point(tabjb)
			if(TabdivHeadName=='tabjb'){

				//we make sure this is an array
				if(!eval(joobiErrorFields[parentid]))	joobiErrorFields[parentid]= new Array();
				//we record the field which is inside that tab
				joobiErrorFields[parentid].push(obj.getAttribute('id'));

				//we make sure that it hasne't already been modified
				for (var i=0;i<joobiErrorTabs.length;i++) {
					//if it was already modified we just return
					if(joobiErrorTabs[i]==TabdivHeadName){
						return true;
					}else	continue;
				}//endfor

				//get the span which corresponds to that tab
				//this is the one with the text and change its class
				TabspanHead=document.getElementById('jtspan'+parentid);
				TabspanHead.className +=' jberror';

				//we add an entry into the colored tabs for that tab
				joobiErrorTabs.push(parentid);

				//we runaway from the loop
				runaway=true;
			}else{
				continue;
			}//endif
		}//endif
	}//endwhile

}//endfct

/*
To write a message next to a conflictive field
@params:obj the html object which triggered the validation error(e.g.:inputbox, select)
@params:message the html object which triggered the validation error(e.g.:message)
@author:ben
*/
function writeMess(obj,message) {
		//we create a span node with a text node inside it
		var sp = document.createElement('span');
		sp.className = 'text jberror';
		sp.appendChild(document.createTextNode(message));

		//and we append it to the object showing the error
		obj.parentNode.appendChild(sp);

		//we record the span object in this attribute to remove it easily later
		obj.hasError = sp;
}//endfct

/*
To remove an error message
@params:obj the html object which triggered the validation error(e.g.:inputbox, select)
@params:joobiTabs to know if we have tabs in the layout
@author:ben
*/
function removeError(obj,joobiTabs)
{
	//if we have tabs we remove the color
	if(joobiTabs)	removeErrorTabs(obj);

	//change the classes and remove the error span
	obj.className = obj.className.substring(0,obj.className.lastIndexOf(' '));
	obj.parentNode.removeChild(obj.hasError);
	obj.hasError = null;
	obj.onchange = null;
}//endfct


/*
To remove an error message from a tab
@params:obj the html object which triggered the validation error(e.g.:inputbox, select)
@author:ben
*/
function removeErrorTabs(obj)
{
	//we try to remove the tab
	//we loop in the array of error fields per tab
	for (tabs in joobiErrorFields) {
		var prev=false;
		for(i=0;i<joobiErrorFields[tabs].length;i++){
			//if it is flagged as true we just skip it
			if(joobiErrorFields[tabs][i]===true)	continue;

			//if we spot the field we try to deactivate then we just flag it as true
			if(joobiErrorFields[tabs][i]==obj.getAttribute('id')){
				joobiErrorFields[tabs][i]=true;
			}//endif

			//we set the previous if it is = true
			if((prev===false) || (prev===true))	prev=joobiErrorFields[tabs][i];
		}//endfor

		//now we can remove the tab error message
		if(prev===true)	{
			tabObj=document.getElementById('jtspan'+tabs);
			//change the classes and remove the error span
			tabObj.className = tabObj.className.substring(0,tabObj.className.lastIndexOf(' '));
			tabObj.onchange = null;
		}//endif

	}//endfor
}//endfct

