/******************************************************************************\

	Class FormHandler

	The FormValidator will check a form on submission. All data is compared to
	certain rules. If some data does not match the criteria, all errors are
	displayed in an alert box, and the form is not submitted.

	1. Classes with their variables and methods:
	---------------------------------------------------------------------------

	- FormHandler
		variables:
		+ frm				(object Form)
		+ frm.frmError		(object FrmError)
		methods:
		+ onsubmit			(fv_handle_submit)
		+ addVal			(fv_add_validation)
	
	- ValidationSet
		variables:
		+ set				(array Validation)
		+ frmField			(object Form.Field)
		methods:
		+ add				(vs_add_validation)
		+ validate			(vs_validate)

	- Validation
		variables:
		+ frmField			(object Form.Field)
		+ validation		(string)
		+ message			(string)
		methods:
		+ validate			(v_validate)

	- FrmError
		variables:
		+ errstr			(string)
		methods:
		+ isError			(fe_is_error : boolean)
		+ add				(fe_add_error)
		+ show				(fe_show_error)
		+ clear				(fe_clear_error)


	functions which are not bind to a class:
		+ v_validate_data	(called Validation.validate)
		+ v_build			(called v_validate_data)
		+ v_check_date_us	(called v_validate_data)


	2. Hierarchy of classes
	---------------------------------------------------------------------------

	- FormHandler
		¬ frm
			¬ FrmError
			¬ frmField
				¬ ValidationSet
					¬ Validation
	
	The Form						has one FrmError, which stores all errors.
	The Form.Field					has zero or one ValidationSet.
	The Form.Field.ValidationSet	has one or more Validations.


	3. Description of program
	---------------------------------------------------------------------------

	There must be a html-page with a form to validate.

	A new FormValidator-object is created with the formname.
	Then all the Validationtypes will be added.

	Normally, the onsubmit-function of the Form will send the form. In this 
	case however, FormValidator overrides the onsubmit-function with an own
	function fv_onsubmit_handler().
	This function loops through all the validationsets, and adds the errors
	to the FrmError-object.
	When there are errors, the FrmError-object gives a warning, and the
	errormessage is displayed.
	When there is an error, the form will not be submitted. Else, the form
	will be submitted

	4. Sample code
	---------------------------------------------------------------------------

	*** First create the form
	<form method=post action=process.html name=nameForm>
	<input type=text name=Name value="" size=20 maxlength=20>
	<select name=selection>
		<option>Choose</option>
		<option>Option 1</option>
		<option>Option 2</option>
	</select>
	<input type=submit value=Store>
	</form>

	*** Add the validator
	<script language="javascript">
	fv			= new FormValidator('nameForm');
	fv.addVal("Name","req","You must enter a name");	//field is required
	fv.addVal("Name","min=10");							//min length of 10
	fv.addVal("selection","dontselect=0");				//first can't be select


	5. Version information and copyright notice
	---------------------------------------------------------------------------

	Version 1.0

	Copyright Vinetix Internet 2003


	6. Changelog
	---------------------------------------------------------------------------
	[no changes were made yet]

\*****************************************************************************/
	

/***** Class FormValidator ***************************************************/
function FormHandler(frmName) {
	//this.frm				= document.forms[frmName];
  this.frm          = document.getElementById(frmName);
	this.frm.frmError		= new FrmError();
	this.frm.onsubmit		= fv_handle_submit;
	this.addVal				= fv_add_validation;
	this.frm.setmd5			= new Array();
	this.addMd5				= fv_add_md5;
}

function fv_handle_submit() {
  //alert(this.elements.length);
  this.frmError = new FrmError();

	for(var x=0;x<this.elements.length;x++) {
    //alert(this.elements[x].validationSet);
    //alert(x +': '+ this.elements[x].id);
		if(this.elements[x].validationSet) {
      //alert('gaan iets toevoegen');
      //alert('frmError: '+ this.frmError);
      //alert(this.elements[x].id +': '+ this.elements[x].validationSet.set.length);
      str = this.elements[x].validationSet.validate();
      //alert(str);
			this.frmError.add(str);
      //alert(this.frmError.show());
		}
	}

  
  //alert('errors gedaan');
	if(this.frmError.isError()) {
		this.frmError.show();
		this.frmError.clear();
		return false;
	} else {
		for(x=0; x<this.setmd5.length;x++) {
			this.setmd5[x].value = hex_md5(this.setmd5[x].value);
		}
		return true;
    //return false;
	}
}

function fv_add_md5(strName) {
	var frmField	= this.frm[strName];
	var found		= false;
	if(!frmField) {
		this.frmError.add('Veld '+strName+' bestaat niet');
	} else {
		for(var x=0;x<this.frm.setmd5.length;x++) {
			if(this.frm.setmd5[x]==frmField) {
				found = true;
			}
		}
		if(!found) {
			this.frm.setmd5[this.frm.setmd5.length] = frmField;
		}
	}
}

function fv_add_validation(strName,strValidation,strMessage) {
	//var	frmField	= this.frm[strName];
  var frmField = document.getElementById("fld"+ strName);
	if(!frmField) {
		this.frm.frmError.add('Veld '+ strName +' bestaat niet');
	} else {
    //alert('hebben een field om iets aan toe te voegen');
		if(!frmField.validationSet) {
			frmField.validationSet = new ValidationSet(frmField,this.frm);
		} else {
      //alert('Er is een validationset');
    }
		frmField.validationSet.add(strValidation,strMessage);
	}
}

/***** Class ValidationSet ***************************************************/
function ValidationSet(frmField,frm) {
	this.set		= new Array();
	this.add		= vs_add_validation;
	this.validate	= vs_validate;
	this.frmField	= frmField;
	this.frm		= frm
}
function vs_add_validation(strValidation,strMessage) {
	this.set[this.set.length] = new Validation(this.frmField,strValidation,strMessage,this.frm);
}
function vs_validate() {
  //alert('gaan valideren');
	var ret = '';
  
	for(var x=0;x<this.set.length;x++) {
    //alert('gaan validatie '+ x +' bekijken');
		ret += this.set[x].validate();
	}
	return ret;
}

/***** Class Validation ******************************************************/
function Validation(frmField,strValidation,strMessage,frm) {
	this.frmField	= frmField;
	this.validation	= strValidation;
	this.message	= strMessage;
	this.frm		= frm;
	this.validate	= v_validate;
}
function v_validate() {
	var ret			= '';
	ret += v_validate_data(this.validation,this.frmField,this.message,this.frm);
	return ret;
}

function v_validate_data(validation,field,message,frm) {
	var ret			= '';
	var ispos		= validation.search("=");
	var cmd			= '';
	var cmdv		= '';
	var length		= '';
	var value		= '';

	if(ispos >= 0) { 
    //alert('ispos is groter dan 0');
		cmd			= validation.substr(0,ispos);
		cmdv		= validation.substr(ispos+1);
	} else {
		cmd			= validation;
	}

	switch(cmd) {
		case 'req':
			if(eval(field.value.length)==0) {
				ret		+= v_build(field.name+' is niet ingevuld',message);
			}
			break;
		case 'maxlength':
    case 'max':
    case 'maxlen':
			length = (cmdv.length>0)?eval(cmdv):10;
			if(eval(field.value.length) > length) {
				ret		+= v_build(field.name +' is langer dan '+length+' karakters',message);
			}
			break;
		case 'minlength':
		case 'min':
		case 'minlen':
			length = (cmdv.length>0)?eval(cmdv):10;
			if(field.value.length > 0 && eval(field.value.length) < length) {
				ret		+= v_build(field.name +' is korter dan '+length+' karakters',message);
			}
			break;
		case 'alphanumeric':
		case 'alfanumeriek':
		case 'alnum':
			if(field.value.length > 0 && field.value.search('[^a-zA-z0-9]') >= 0) {
				ret		+= v_build(field.name +' bevat niet-alfanumerieke karakters',message);
			}
			break;
		case 'num':
		case 'numeriek':
			if(field.value.length > 0 && field.value.search('[^0-9-]') >= 0) {
				ret		+= v_build(field.name +' bevat niet alleen cijfers',message);
			}
			break;
    case 'double':
      if(field.value.length > 0 && field.value.search('[^0-9.,-]') >= 0) {
        ret   += v_build(field.name +' bevat geen (decimaal) getal',message);
      }
      break;
		case 'alpha':
			if(field.value.length > 0 && field.value.search('[^a-zA-z]') >= 0) {
				ret		+= v_build(field.name +' bevat niet alleen letters',message);
			}
			break;
		case 'alnumhyph':
			if(field.value.length > 0 && field.value.search('[^a-zA-z0-9\-_]') >= 0) {
				ret		+= v_build(field.name +' mag alleen de karakters a-z,A-Z,0-9,- en _ bevatten',message);
			}
			break;
		case 'email':
			if(field.value.length > 0 && field.value.search(/^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/)!=0) {
				ret		+= v_build(field.name +' is geen geldig e-mailadres',message);
			}
			break;
    case 'emailmulti':
      value = (cmdv.length>0)?cmdv:';';
      if(field.value.length > 0) {
        var multipleEmails = field.value.split(value);
        for(x=0;x < multipleEmails.length;x++) {
          if(multipleEmails[x].length>0 && multipleEmails[x].search(/^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/)!=0) {
            ret += v_build(field.name +' bevat geen geldig e-mailadres: '+ multipleEmails[x],message);
          }
        }
      }
      break;
		case 'lt':
		case 'lessthan':
			value = (cmdv.length>0)?eval(cmdv):10;
			if(isNaN(field.value)) {
				ret		+= v_build(field.name +' is geen nummer','');
			} else {
				if(eval(field.value) >= value) {
					ret += v_build(field.name +' moet kleiner zijn dan '+ value,message);
				}
			}
			break;
		case 'gt':
		case 'greaterthan':
			value	= (cmdv.length>0)?eval(cmdv):10;
			if(isNaN(field.value)) {
				ret		+= v_build(field.name +' is geen nummer','');
			} else {
				if(eval(field.value) <= value) {
					ret	+= v_build(field.name +' moet groter zijn dan '+ value,message);
				}
			}
			break;
		case 'le':
		case 'lessequal':
			value	= (cmdv.length>0)?eval(cmdv.replace(",",".")):10;
      var valueDot  = field.value.replace(",",".");
			if(isNaN(valueDot)) {
				ret		+= v_build(field.name +' is geen nummer','');
			} else {
				if(eval(valueDot) > value) {
					ret += v_build(field.name +' ('+ valueDot +') moet kleiner of gelijk zijn aan '+ value,message);
				}
			}
			break;
		case 'ge':
		case 'greaterequal':
			value	= (cmdv.length>0)?eval(cmdv):10;
			if(isNaN(field.value)) {
				ret		+= v_build(field.name +' is geen nummer','');
			} else {
				if(eval(field.value) < value) {
					ret	+= v_build(field.name +' moet groter of gelijk zijn aan '+ value,message);
				}
			}
			break;
		case 'regexp':
			if(field.value.length > 0 && !field.value.match(cmdv)) {
				ret		+= v_build(field.name +' voldoet niet aan de filter: '+ cmdv, message);
			}
			break;
		case 'dontselect':
			if(field.selectedIndex==null) {
				ret		+= v_build('Fout in validatie-omschrijving voor veld '+ field.name,'');
			} else {
				if(field.selectedIndex == eval(cmdv)) {
					ret	+= v_build('Geen optie gekozen in selectievak '+ field.name,message);
				}
			}
			break;
		case 'zip':
		case 'postal':
			switch(cmdv) {
				case 'nl':
				default:
					if(field.value.length>0 && field.value.search(/^[1-9][0-9][0-9][0-9] ?[a-zA-z][a-zA-z]$/) != 0) {
						ret += v_build(field.name +' bevat geen geldige Nederlandse postcode',message);
					}
			}
			break;
		case 'date':
      //alert('gaan date checken');
			switch(cmdv) {
				case 'us':
				case 'en':
        case 'uk':
					if(field.value.length>0 && !v_check_date_us(field.value)) {
						ret += v_build(field.name +' bevat geen geldige Engelse datum (mm-dd-jjjj)',message);
					}
					break;
				case 'nl':
				default:
					if(field.value.length>0) {
						var correct = true;
						var datum	= field.value.split("-");
            //alert('lengte datum: '+ datum.length);
						if(datum.length != 3 || !v_check_date_us(datum[1] +'-'+ datum[0] +'-'+ datum[2])) {
							ret	+= v_build(field.name +' bevat geen geldige Nederlandse datum (dd-mm-jjjj)',message);
						}
					}
			}
			break;
    case 'time':
      var arrtime = field.value.split(":");
      switch(cmdv) {
        case '5':
        case '10':
        case '15':
        case '30':
          if(arrtime[1]%cmdv > 0) {
            ret += v_build(field.name +' moet afgerond worden op '+ cmdv +' minuten',message);
          }
          break;
      }
      break;
    case 'dateMinNL':
      var correct = true;
      var arrDate = field.value.split("-");
      if(arrDate.length!=3) {
        //ret += v_build(field.name +' bevat geen geldige Nederlandse datum (dd-mm-jjjj)',message);
      } else {
        var arrVal = cmdv.split("-");
        if(arrVal.length!=3) {
          ret += v_build(field.name +' bevat geen geldige controledatum (dd-mm-jjjj)',message);
        } else {
          //check if year is before minimum year
          if(arrDate[2] < arrVal[2]) {
            correct = false;
            //check if year is minimum year
          } else if(arrDate[2] == arrVal[2]) {
            //check if month is before minimum month
            if(arrDate[1] < arrVal[1]) {
              correct = false;
              //check if month is minimum month
            } else if(arrDate[1] == arrVal[1]) {
              //check if day is before minimum day
              if(arrDate[0] < arrVal[0]) {
                correct = false;
              }
            }
          }
          if (!correct) {
            ret += v_build(field.name +' ligt voor '+ cmdv,message);
          }
        }
      }
      break;
    case 'dateMaxNL':
      var correct = true;
      var arrDate = field.value.split("-");
      if(arrDate.length!=3) {
        //ret += v_build(field.name +' bevat geen geldige Nederlandse datum (dd-mm-jjjj)',message);
      } else {
        var arrVal = cmdv.split("-");
        if(arrVal.length!=3) {
          ret += v_build(field.name +' bevat geen geldige controledatum (dd-mm-jjjj)',message);
        } else {
          //check if year is before minimum year
          if(arrDate[2] > arrVal[2]) {
            correct = false;
            //check if year is minimum year
          } else if(arrDate[2] == arrVal[2]) {
            //check if month is before minimum month
            if(arrDate[1] > arrVal[1]) {
              correct = false;
              //check if month is minimum month
            } else if(arrDate[1] == arrVal[1]) {
              //check if day is before minimum day
              if(arrDate[0] > arrVal[0]) {
                correct = false;
              }
            }
          }
          if (!correct) {
            ret += v_build(field.name +' ligt na '+ cmdv,message);
          }
        }
      }
      break; 
		case 'cmp':
		case 'compare':
		case 'comp':
			var found	= false;
			for(var x=0;x<frm.elements.length;x++) {
				if(frm.elements[x].name==cmdv) {
					found = true;
					if(field.value!=frm.elements[x].value) {
						ret+=v_build(field.name +' is niet gelijk aan '+ cmdv);
					}
				}
			}
			if(!found) {
				ret+=v_build(cmdv+' kan niet worden gevonden om te vergelijken met '+ field.name);
			}
			break;
	}
	return ret;
}
function v_build(string,message) {
	var ret				= '';
	ret					+= (!message||message.length==0)?'- '+string+'\n':'- '+message+'\n';
	return ret;
}
function v_check_date_us(dateStr) {
	var arrDate = dateStr.split("-");
	if(arrDate.length!=3) { return false; }
	var strYear		= arrDate[2];
	var numDay		= eval(arrDate[1]);
	var numMonth	= eval(arrDate[0]);
  //alert('jaar bekijken');
  var tmpStrYear = strYear;
  if(tmpStrYear != parseInt(tmpStrYear)) { return false; }
	var numYear		= eval(strYear);
  //alert('jaar bekeken');

	if(strYear.length!=2&&strYear.length!=4) { return false; }
	if(strYear.length==2&&numYear<=50) { numYear += 2000; }
	if(strYear.length==2&&numYear>50) { numYear += 1900; }
	if(numYear<0||numYear>9999) { return false; }

	if(numMonth<1||numMonth>12) { return false; }

	if(numDay>=32) { return false; }
	if(numDay>=31 && (numMonth==2||numMonth==4||numMonth==6||numMonth==9||numMonth==11)) { return false; }
	if(numDay>=30 && numMonth==2) { return false; }

	if(numMonth==2&&numDay==29) {
		var div4	= numYear % 4;
		var div100	= numYear % 100;
		var div400	= numYear % 400;
		if(div4!=0) { return false; }
		if(div100==0&&div400!=0) { return false; }
	}
	return true;
}

/***** Class FrmError ********************************************************/
function FrmError() {
	this.isError		= fe_is_error;
	this.errstr			= '';
	this.add			= fe_add_error;
	this.show			= fe_show_error;
	this.clear			= fe_clear_error;
}
function fe_add_error(strError) {
	if(strError != '') {
		this.errstr			+= strError;
	}
}
function fe_show_error() {
	if(this.errstr!='') {
		alert('De volgende punten zijn niet juist:\n\n'
			 + this.errstr 
			 +'\n\n'
			 +'Het formulier is niet opgestuurd');
	}
}
function fe_is_error() {
	if (this.errstr=='') {
		return false;
	} else {
		return true;
	}
}
function fe_clear_error() {
	this.errstr='';
}

