
/**
* represent a cfform 
*/
function RailoForms(form) {
	var pub=this;
	var prv={};
	
    pub.TYPE_SELECT=-1;
    pub.TYPE_TEXT=0;
    pub.TYPE_RADIO=1;
    pub.TYPE_CHECKBOX=2;
    pub.TYPE_PASSWORD=3;
	
    pub.VALIDATE_DATE=4;
    pub.VALIDATE_EURODATE=5;
    pub.VALIDATE_TIME=6;
    pub.VALIDATE_FLOAT=7;
    pub.VALIDATE_INTEGER=8;
    pub.VALIDATE_TELEPHONE=9;
    pub.VALIDATE_ZIPCODE=10;
    pub.VALIDATE_CREDITCARD=11;
    pub.VALIDATE_SOCIAL_SECURITY_NUMBER=12;
    pub.VALIDATE_REGULAR_EXPRESSION=13;
    pub.VALIDATE_NONE=14;

	prv.form=form;
	prv.elements={};
	prv.errors=[];
			
	/*
	* adds a input definition to the for Object
	*/
	pub.addInput=function(name,required,type,validate,pattern,message,onerror,onvalidate,rangeMin,rangeMax) {
		if((rangeMin || rangeMax) && validate!=pub.VALIDATE_FLOAT && validate!=pub.VALIDATE_INTEGER)validate=pub.VALIDATE_FLOAT;
		prv.elements[name]={'name':name,'required':required,'type':type,'validate':validate,'pattern':pattern,'message':message,'onerror':onerror,'onvalidate':onvalidate,'rangeMin':rangeMin,'rangeMax':rangeMax};
	}
	
	/*
	* check data from the form
	*/
	pub.check=function() {
		for(var key in prv.elements) {
			var el=prv.elements[key];
			if(pub.TYPE_TEXT==el.type) prv.checkText(el,true);
			else if(pub.TYPE_PASSWORD==el.type) prv.checkText(el,false);
			else if(pub.TYPE_RADIO==el.type) prv.checkRadio(el);
			else if(pub.TYPE_CHECKBOX==el.type) prv.checkRadio(el);
			else if(pub.TYPE_SELECT==el.type) prv.checkSelect(el);
		}
		if(prv.errors.length) {
			for(var i=0;i<prv.errors.length;i++) {
				var err=prv.errors[i];
				var el=err.element;
				
				if(el.onerror) {
					if(typeof(el.onerror) == "string" && typeof(eval(el.onerror)) == "function") {
						var func=eval(el.onerror);
						var f=document.forms[prv.form]
						var i=f[el.name];				
						var v=i.value;
						if(!v && err.value)v='';
						func(f,i,i.v);
					}
				}		
				else alert(err.error);
			}
			
			prv.errors=[];
			return false;
		}
		else return true;
	}
	
	/*
	* checks a select input field 
	* @param el Element with all data to the input field
	*/
	prv.checkSelect=function(el) {
		var select=document.forms[prv.form][el.name];
		var hasSelection=false;
		for(var i=0;i<select.options.length;i++) {
			if(select.options[i].selected) {
				hasSelection=true;
				break;
			}
		}
		if(!hasSelection) {
			if(el.message && el.message.length>0) prv.addError(el,el.message);
			else prv.addError(el,"drop-down field \""+el.name+"\" is required, but no selction is made");
		}
	}
	
	/*
	* checks a text/password input field 
	* @param el Element with all data to the input field
	*/
	prv.checkText=function(el,checkValidation) {
		var hasError=false;
		var input=document.forms[prv.form][el.name];
		var value=prv.trim(input.value);
		// missing value
		if(el.required && value.length==0) {
			if(el.message && el.message.length>0) prv.addError(el,el.message);
			else prv.addError(el,"missing value for text input field \""+el.name+"\"");
			hasError=true;
		}
		if(checkValidation && !hasError)prv.validate(el,value);
	}
	
	/*
	* checks a radio input field 
	* @param el Element with all data to the input field
	*/
	prv.checkRadio=function(el) {
		var hasError=false;
		var input=document.forms[prv.form][el.name];
		if(!input.length)	{
			if(!input.checked && el.required) {
				if(el.message && el.message.length>0) prv.addError(el,el.message);
				else prv.addError(el,'radio button or checkbox ['+el.name+'] is not checked but required');
				hasError=true;
			}
			if(input.checked && !hasError) {
				prv.validate(el,input.value);
			}
		}
		else {
			var isChecked=false;
			for(var i=0;i<input.length;i++) {
				var i=input[i];
				if(i.checked) {
					isChecked=true;
					prv.validate(el,i.value);
				}
			}
			if(!isChecked && el.required) {
				if(el.message && el.message.length>0) prv.addError(el,el.message);
				else prv.addError(el,'radio button or checkbox ['+el.name+'] is not checked but required');
				hasError=true;
			}
		}
	}
	
	/*
	* checks a checkbox input field 
	* @param el Element with all data to the input field
	*/
	prv.checkCheckbox=function(el) {
		
	}
	
	
	prv.validate=function(el,value) {
		var v=el.validate;
		if(v==pub.VALIDATE_NONE)return;
		else if(v==pub.VALIDATE_DATE) prv.validateDate(el,value);
		else if(v==pub.VALIDATE_EURODATE) prv.validateEuroDate(el,value);
		else if(v==pub.VALIDATE_TIME) prv.validateTime(el,value);
		else if(v==pub.VALIDATE_FLOAT) prv.validateFloat(el,value);
		else if(v==pub.VALIDATE_INTEGER) prv.validateInteger(el,value);
		else if(v==pub.VALIDATE_TELEPHONE) prv.validateTelephone(el,value);
		else if(v==pub.VALIDATE_ZIPCODE) prv.validateZipCode(el,value);
		else if(v==pub.VALIDATE_CREDITCARD) prv.validateCreditCard(el,value);
		else if(v==pub.VALIDATE_SOCIAL_SECURITY_NUMBER) prv.validateSocialSecurityNumber(el,value);
		else if(v==pub.VALIDATE_REGULAR_EXPRESSION) prv.validateRegularExpression(el,value);
		if(el.onvalidate && !prv.hasError()) {
			if(typeof(el.onvalidate) == "string" && typeof(eval(el.onvalidate)) == "function") {
  				var func=eval(el.onvalidate);
				var f=document.forms[prv.form]
				var i=[el.name];				
				if(func(f,i,value))return;
				else {
					if(el.message && el.message.length>0)prv.addError(el,el.message);
					else prv.addError(el,'value ('+value+') of field '+el.name+' has a invalid value');
					return;
				}
			}
			prv.addError(el,'invalid definition of the validation function in argument onValidation, you must only define the name of the function, not a function call, example: "myValidation" not "myValidation(\'argument\')"');
		}		
	}
	
	/*
	* check if value contains a time value or not (hh:mm:ss)
	* @param el Element with all data to the input field
	* @param value value from input field
	*/
	prv.validateTime=function(el,value) {
		var pattern=/^(\d{1,2}):(\d{1,2}):(\d{1,2})$/;
		var result=value.match(pattern);
		if(!result) {
  			if(el.message && el.message.length>0)prv.addError(el,el.message);
			else prv.addError(el,'value ('+value+') of field '+el.name+' doesnt contain a time value');
		}
	}
	
	/*
	* check if value contains a date value or not (dd/mm/yyyy)
	* @param el Element with all data to the input field
	* @param value value from input field
	*/
	prv.validateEuroDate=function(el,value)  { 
        var pattern=/^(\d{1,2})\/(\d{1,2})\/(\d{1,4})$/; 
        var result=value.match(pattern); 
        if(result && result.length==4) { 
			var month=result[2]; 
			var day=result[1]; 
			var year=result[3]; 
			var date=new Date(year,month-1,day); 
			if(day==date.getDate() && month==date.getMonth()+1 && (year==date.getYear() || year==date.getFullYear())) {
				return;
			} 
        } 
		if(el.message && el.message.length>0)prv.addError(el,el.message);
		else prv.addError(el,'value ('+value+') of field '+el.name+' doesnt contain a euro date value'); 
	}

	/*
	* check if value contains a date value or not (mm/dd/yyyy)
	* @param el Element with all data to the input field
	* @param value value from input field
	*/
	prv.validateDate=function(el,value)  { 
        var pattern=/^(\d{1,2})\/(\d{1,2})\/(\d{1,4})$/; 
        var result=value.match(pattern);
        if(result && result.length==4) { 
			var month=result[1]; 
			var day=result[2]; 
			var year=result[3]; 
			var date=new Date(year,month-1,day); 
			if(day==date.getDate() && month==date.getMonth()+1 && (year==date.getYear() || year==date.getFullYear())) {
				return;
			} 
        } 
		if(el.message && el.message.length>0)prv.addError(el,el.message);
		else prv.addError(el,'value ('+value+') of field '+el.name+' doesnt contain a date value'); 
	} 

	/*
	* check if value contains a float value or not
	* @param el Element with all data to the input field
	* @param value value from input field
	*/
	prv.validateFloat=function(el,value) {
		var nbr=Number(value);
		if(isNaN(nbr)) {
			if(el.message && el.message.length>0)prv.addError(el,el.message);
			else prv.addError(el,'value ('+value+') of field '+el.name+' doesnt contain a number value');
		}
		else {
			if(el.rangeMin && el.rangeMin>nbr || el.rangeMax && el.rangeMax<nbr) {
				if(el.message && el.message.length>0)prv.addError(el,el.message);
				else prv.addError(el,'value ('+value+') of field '+el.name+' has a invalid range, valid range is from '+el.rangeMin+' to '+el.rangeMax);
			}
		}
	}
	
	/*
	* check if value contains a int value or not
	* @param el Element with all data to the input field
	* @param value value from input field
	*/
	prv.validateInteger=function(el,value) {
		var nbr=Number(value);
		if(isNaN(nbr) || nbr!=parseInt(nbr)) {
			if(el.message && el.message.length>0)prv.addError(el,el.message);
			else prv.addError(el,'value ('+value+') of field '+el.name+' doesnt contain a integer');
		}
		else {
			if(el.rangeMin && el.rangeMin>nbr || el.rangeMax && el.rangeMax<nbr) {
				if(el.message && el.message.length>0)prv.addError(el,el.message);
				else prv.addError(el,'value ('+value+') of field '+el.name+' has a invalid range, valid range is from '+el.rangeMin+' to '+el.rangeMax);
			}
		}
	}
	
	/*
	* check if value match pattern
	* @param el Element with all data to the input field
	* @param value value from input field
	*/
	prv.validateRegularExpression=function(el,value)  { 
		
		if(!el.pattern.test(value)) {
			if(el.message && el.message.length>0)prv.addError(el,el.message);
			else prv.addError(el,'value ('+value+') of field '+el.name+' doesnt match given pattern ('+el.pattern+')');
		} 
	} 
	
	/*
	* check if value is a valid zip code (us style)
	* @param el Element with all data to the input field
	* @param value value from input field
	*/
	prv.validateZipCode=function(el,value) { 
        var pattern=/^\d{5}([ -]\d{4}){0,1}$/; 
        if(!pattern.test(value))	{
			if(el.message && el.message.length>0)prv.addError(el,el.message);
			else prv.addError(el,'value ('+value+') of field '+el.name+' doesnt contain a zip code');
		} 
	}  
	
	/*
	* check if value is a valid phone number (us style)
	* @param el Element with all data to the input field
	* @param value value from input field
	*/
	prv.validateTelephone=function(el,value) { 
        var pattern=/^(\+\d[ -\.])?\d{3}[ -\.]?\d{3}[ -\.]?\d{4}$/; 
        if(!pattern.test(value))	{
			if(el.message && el.message.length>0)prv.addError(el,el.message);
			else prv.addError(el,'value ('+value+') of field '+el.name+' doesnt contain a phone number');
		} 
	} 
	
	/*
	* check if value is a valid Social Security Number (us)
	* @param el Element with all data to the input field
	* @param value value from input field
	*/
	prv.validateSocialSecurityNumber=function(el,value) { 
        var pattern=/\d{3}[- ]\d{2}[- ]\d{4}/; 
        if(!pattern.test(value))	{
			if(el.message && el.message.length>0)prv.addError(el,el.message);
			else prv.addError(el,'value ('+value+') of field '+el.name+' doesnt contain a (us) Social Security Number');
		} 
	}
	
	/*
	* check if value is a valid credit card number
	* @param el Element with all data to the input field
	* @param value value from input field
	*/
	prv.validateCreditCard=function(el,value) {
		if(!prv._validateCreditCard(value)) {
			if(el.message && el.message.length>0)prv.addError(el,el.message);
			else prv.addError(el,'value ('+value+') of field '+el.name+' doesnt contain a valid creditcard number');
		}
	}
	prv._validateCreditCard=function(s) {
		// remove non-numerics
		var v = "0123456789";
		var w = "";
		for (i=0; i < s.length; i++) {
			x = s.charAt(i);
			if (v.indexOf(x,0) != -1) w += x;
		}
		// validate number
		j = w.length / 2;
		if (j < 6.5 || j > 8 || j == 7) return false;
		k = Math.floor(j);
		m = Math.ceil(j) - k;
		c = 0;
		for (i=0; i<k; i++) {
			a = w.charAt(i*2+m) * 2;
			c += a > 9 ? Math.floor(a/10 + a%10) : a;
		}
		for (i=0; i<k+m; i++) c += w.charAt(i*2+1-m) * 1;
		return (c%10 == 0);
	}
	
	prv.hasError=function() {
		return prv.errors!=0;
	}
	
	prv.addError=function(el,error) {
		prv.errors[prv.errors.length]={'element':el,'error':error};
	}
	prv.trim=function(inputString) {
	   // Removes leading and trailing spaces from the passed string. Also removes
	   // consecutive spaces and replaces it with one space. If something besides
	   // a string is passed in (null, custom object, etc.) then return the input.
	   if (typeof inputString != "string") { return inputString; }
	   var retValue = inputString;
	   var ch = retValue.substring(0, 1);
	   while (ch == " ") { // Check for spaces at the beginning of the string
		  retValue = retValue.substring(1, retValue.length);
		  ch = retValue.substring(0, 1);
	   }
	   ch = retValue.substring(retValue.length-1, retValue.length);
	   while (ch == " ") { // Check for spaces at the end of the string
		  retValue = retValue.substring(0, retValue.length-1);
		  ch = retValue.substring(retValue.length-1, retValue.length);
	   }
	   while (retValue.indexOf("  ") != -1) { // Note that there are two spaces in the string - look for multiple spaces within the string
		  retValue = retValue.substring(0, retValue.indexOf("  ")) + retValue.substring(retValue.indexOf("  ")+1, retValue.length); // Again, there are two spaces in each of the strings
	   }
	   return retValue; // Return the trimmed string back to the user
	}
}