/**
*Constructor for form validator to define a a new form simply
*my_form=new form_validator('form');
*Where form is the properity defined in the name attribute in the form
*you can define the critera for the form once the form has been been set by
*setting the following properities:
*
*@constructor
*@author John Joske
*/

function form_validator(name) {
	this.name=name;
	this.errors=new Array();
	this.elements=new Array();
	this.error=false;
	this.add_error=add_error;
	this.get_error=get_error;
	this.set_date=set_date;
	this.verify=verify;
	this.verify_string=verify_string;
	this.verify_int=verify_int;
	this.verify_email=verify_email;
	this.verify_url=verify_url;
	this.verify_postcode=verify_postcode;
	this.verify_mobile=verify_mobile;
	this.verify_boolean=verify_boolean;
	this.verify_date=verify_date;
	this.verify_code=verify_code;
	this.verify_date_with_slashes = verify_date_with_slashes;
	//add in the elements
	for(var i=0;i<document[name].length;i++) {
		var elem=new Object();
		elem.name=document[name][i].name;
		this.elements[document[name][i].name]=elem;
	}
	
}

/**
*Loops through all elements that require verfication in the
*form and sets an error message if they don't meet the defined critera
*@return {BOOLEAN} true if all elements meet defined critera, otherwise false
*/

function verify() {
	//reset error stuff
	this.error=false;
	this.errors=new Array();
	for(var i in this.elements) {
		var element=this.elements[i];
		switch(element.type) {
			case 'string' :
			this.verify_string(element);
			break;		
			
			case 'int' :
			this.verify_int(element);
			break;
			
			case 'email' :
			this.verify_email(element);
			break;
			
			case 'url' :
			this.verify_url(element);
			break;
			
			case 'postcode' :
			this.verify_postcode(element);
			break;
			
			case 'mobile' :
			this.verify_mobile(element);
			break;
			
			case 'boolean' :
			this.verify_boolean(element);
			break;
			
			case 'date' :
			this.verify_date(element);
			break;
			
			case 'code' :
			this.verify_code(element);
			break;
			
			case 'date_with_slashes' :
			this.verify_date_with_slashes(element);
			break;
		}
	}
	
	if(this.error) {
		return false;
	} else {
		return true;
	}
}

/**
*Sets date type
*a date type consists of three
*fields field[day], field[month], field[year]
*/
function set_date(field) {
	var elem=new Object();
	elem.name=field;
	elem.type='date';
	this.elements[field]=elem;
}


/**
*Adds a new error to the error stack and sets the error flag to true
*/
function add_error(error) {
	this.error=true;
	this.errors[this.errors.length]=error;
}

/**
*Returns a string of errors
@return {string}
*/
function get_error() {
	var error="The following errors have occured:\n";
	for(var i=0;i<this.errors.length;i++) {
		error+=this.errors[i]+"\n";
	}
	return error;
}

/**
*Verifies that a string is within allowed citeria
*properities of a string are
*type-string (mandtory)
*null_allowed (optional assumed true if not set)
*min_length (optional)
*max_length (optional)
*@return {boolean} returns true if meets critera, otherwise false
*/
function verify_string(constr) {
	var error=false;
	var element=document[this.name][constr.name];
	var value=element.value;
	
	if((constr.null_allowed==false) && value=="") {
		this.add_error(constr.message);
		error=true;
	}
	if(constr.min_length!=undefined && value!='') {
		if(value.length<constr.min_length) {
			this.add_error("Field "+constr.name+" must be a least "+constr.min_length+" long.");
			error=true;
		}
	}
	
	if(constr.max_length!=undefined && value!='') {
		if(value.length>constr.max_length) {
			this.add_error("Field "+constr.name+" can't be longer than "+constr.max_length+" long.");
			error=true;
		}
	}
	if(error) {
		return false;
	} else {
		return true;
	}
}

/**
* checks that an integer is valid
* Checks that it is a valid integer.  If the const.null_allowed is true or not set
* then the field can be a blank ''.
* If constraint min is set to false or not set then there is no min value otherwise the value has to
* be greater than min.  If const.max is set to false or not set then there is no max value
* other wise it has to be less than $max.
*/	
function verify_int(constr) {
	var error=false;
	var element=document[this.name][constr.name];
	var value=element.value;
	if(isNaN(parseInt(value))) {
		this.add_error(constr.message);
		error=true;
	}
	if(constr.null_allowed==false && value=='') {
		this.add_error("Field "+constr.name+" can't be blank.")
		error=true;
	}
	
	if(constr.min!=undefined && value<constr.min) {
		this.add_error("Field "+constr.name+" must be greater than "+constr.min+".");
		error=true;
	}
	
	if(constr.max!=undefined && value>constr.max) {
		this.add_error("Field "+constr.name+" must be less than "+constr.max+".");
		error=true;
	}
	
	if(error) {
		return false;
	} else {
		return true;
	}
	
}

/**
*Validates an email address
*@param {object} 
*@return {boolean}
*/
function verify_email(constr) {
	var error=false;
	var element=document[this.name][constr.name];
	var value=element.value;
	if(constr.null_allowed==false && value=='') {
		this.add_error(constr.valid_email_message);
		error=true;
	}
	var match=/^([a-zA-Z0-9])+([\.a-zA-Z0-9_-])*@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-]+)+/;
	if(value!='' && !match.test(value)) {
		this.add_error(constr.valid_email_message);
		error=true;
	}
	return !error;
	
}

/**
*Validates that the field is in correct url format
*correct format is considered anything that starts with
*http:// or https://
*/
function verify_url(constr) {
	var error=false;
	var element=document[this.name][constr.name];
	var value=element.value;
	if(constr.null_allowed==false && value=='') {
		this.add_error("Url can't be null.");
		error=true;
	}
	if(value!='' && value.substring(0,7)!="http://" && value.substring(0,8)!="https://") {
		this.add_error("Illegal url.");
		error=true;
	}
	return !error;
}

/**
*Validates that a postcode is in Australian
*postcode format
*Postcode must be numeric only and 2-4 characters long
*/
function verify_postcode(constr) {
	var error=false;
	var element=document[this.name][constr.name];
	var value=element.value;
	var match= /[^0-9]+/
	if(match.test(value)) {
		this.add_error("You can only have numeric characters in a postcode.");
		error=true;
	}
	if(value.length<3) {
		this.add_error("A postcode can not be less than 2 characters long.");
		error=true;
	}
	if(value.length>4) {
		this.add_error("A postcode must can not be more than 4 charactes long.");
		error=true;
	}
	return !error;
}

/**
*Validates that a number is correct for mobile number format
*format is numbers only, starting with a 0 and 10 characters long
*/
function verify_mobile(constr) {
	var error=false;
	var element=document[this.name][constr.name];
	var value=element.value;
	var match= /[^0-9]+/
	if(match.test(value)) {
		this.add_error("You can only have numeric characters in your phone number.");
		error=true;
	}
	if(value.length!=10) {
		this.add_error("Mobile number must be 10 numeric characters long.");
		error=true;
	}
	if(value.substr(0,1)!='0') {
		this.add_error("Mobile number must start with a 0.");
		error=true;
	}
	return !error;
}

/**
*Validates that a date is correct format
*date format is day between 0-31
*month 1-12
*Year any integer
*Also validates that is a valid date ie not 31/2/2006
*if nulls are allowed all fields must be blank
*/
function verify_date(constr) {
	var error=false;
	var day=document[this.name][constr.name+'[day]'].value;
	var month=document[this.name][constr.name+'[month]'].value;
	var year=document[this.name][constr.name+'[year]'].value;
	if(day!='' && isNaN(parseInt(day))) {
		this.add_error('Day field is not correct format.');
		error=true;
	}
	if(month!='' && isNaN(parseInt(month))) {
		this.add_error('Month field is not correct format.');
		error=true;
	}
	if(year!='' && isNaN(parseInt(year))) {
		this.add_error('Year field is not correct format.');
		error=true;
	} 
	
	if(constr.null_allowed==false && day=='' && month=='' && year=='') {
		this.add_error('Null date not allowed');
		error=true;
	} 
	
	//everything is ok work whether legal date
	if(error==false && !(day=='' && month=='' && year=='')) {
		var month_length = new Array(31,28,31,30,31,30,31,31,30,31,30,31);
		if (year/4 == parseInt(year/4)) {
			month_length[1] = 29;
		}
		if(month<1 || month >12) {
			this.add_error("Illegal date2.");
			error=true;
		} else if(day<1 || day>month_length[month-1]) {
			this.add_error("Illegal date3.");
			error=true;
		} else if(year<0) {
			this.add_error("Illegal date4.");
			error=true;
		}
	}
	return !error;
}

/**
*Validates that valid boolean
*valid boolean is defined as (true) Y,y,t,true,TRUE
*(false) N,n,t,T,true,TRUE
*/
function verify_boolean(constr) {
	var error=false;
	var element1=document.getElementById(constr.name+'[Y]');
	var element2=document.getElementById(constr.name+'[N]');
	if(constr.null_allowed==false && !element1.checked && !element2.checked) {
		this.add_error("Null value for "+constr.name+".");
		error=true;
	}
	return !error;
}

function verify_code(constr) {
	var error=false;
	var element=document[this.name][constr.name];
	var value=element.value;
	match=/[^A-Z0-9]+/;
	if(value!='' && match.test(value)) {
		this.add_error("Code must be alphanumeric characters only.");
		error=true;
	}
	if(value!='' && value.length!=8) {
		this.add_error("Code must be 8 characters long.");
		error=true;
	}
}

/**
*	verifies date if it is a date with slashes
*/

function verify_date_with_slashes(constr){
	var error=false;
	var element=document[this.name][constr.name];
	var value=element.value;

	var re = /^\d{2}\/\d{2}\/\d{2}$/;
	
   	if (re.test(value)) {
    //  var dArr = sDate.split("/");
     // var d = new Date(sDate);
 	} else {
 	      this.add_error("Date must be in the format DD/MM/YY and must be numeric values.");
		error=true;
	}
	
	return !error; 
}
