

var validators = new Validators();

/*
*
*  Validators Class
*  holds list of Validator Objects, 1 for each form on the page
*
*/
function Validators () {
}

/*
*
*  Validator Class
*  There is 1 instance of this for each form
*
*/
function Validator (f_id) {
  this.form_id = f_id;                   // this is an int unique to each form on the page
  this.req_fields = new Array();         // the names and hints of the required fields (as set in the config file)
  this.validations = new Array();        // the names and validation rules for each field which requires validation
  this.error_replaces_intro = false;     //  a string with a general validation error to use instead of the generated error message. set to false to use the generated error message. - this is set by the config file
  this.custom_error = false;             // 
  this.fields_with_hints = new Array();  // array of element ids of fields in this form which use a hint
  
  
  /*
  *
  *  METHOD: add_req_field : appends an array of 2 elements to the req_fields property of this Validator. the array contains the field name and the hint.
  *  param: fieldname : the name of the field
  *  param: hint (optional) : The hint that should appear in the field
  *
  */
  this.add_req_field = function (fieldname, hint) {
	if (hint == null){  hint = '';  }	
	this.req_fields.push(new Array(fieldname, hint));	
  }
  
  /*
  *
  *  METHOD: add_validation : appends an array of 2 elements to the validations property of this Validator. the array contains the field name and the validation_type.
  *  param: fieldname : the name of the field
  *  param: validation_type : The type of validation. Possible values are :
  *         - email  : field can only contain an email address
  *         - phone  : field can only contain a phone number
  *         - no_url : field may not contain a url
  *         - captcha_url : captcha must be used if this field contains a url
  *
  */
  this.add_validation = function (fieldname, validation_type) {
  	  this.validations.push(new Array(fieldname, validation_type));
  }
  
  /*
  *
  *  METHOD: add_url_listeners : checks for validations of 'captcha_url' type and adds a keypress listener to the field which checks for a url on each keystroke
  *                              the keypress listener calls the function to show or hide the captcha if a url is present
  *
  */
  this.add_url_listeners = function () {
	
	// look at each validation
	for (i = 0; i < this.validations.length; i++) {
		
	  // check if the validation is 'captcha_url'
	  if (this.validations[i][1] == 'captcha_url') {
	
	    // get the field id (the field name plus underscore plus the form id
	    var field_id = (this.validations[i][0]+'_'+this.form_id);
		// make a local copy of the form id
		var form_id_ = this.form_id;
		
		
		// add keypress event handler for the field
	    document.getElementById(field_id).onkeypress=function () {
			
		  // check if the value of the field contains a url
		  // if it contains a url then show the captcha, otherwise hide the captcha
		  var el_id = field_id;
		  if (contains_url(document.getElementById(el_id).value)) {
			show_captcha(form_id_);
		  } else {
			hide_captcha(form_id_);
		  } 
		  
	    } // end onkeypress function
	
	  } // end if validation is captcha
	  
	} // end for all validations
  } // END ADD URL LISTENERS FUNCTION



  /*
  *
  *  METHOD: errorReplacesIntro : sets whether the validation error replaces the intro message. ie when the user gets a validation error does the intro message (set in the config file) disappear.
  *                               this method is called by javascript generated by php based on the setting in the config file
  *  PARAM: val : boolean
  *
  */
  this.errorReplacesIntro = function (val) {
	this.error_replaces_intro = val;
  }


  /*
  *
  *  METHOD: errorReplacesIntro : sets sets the custom error message. If this is set it is displayed instead of the general validation error.
  *  PARAM: err_msg : text string of a custom error message
  *
  */
  this.customErrorMessage = function (err_msg) {
	this.custom_error = err_msg;
  }

  
  /*
  *
  *  METHOD: validate_form : 
  *  PARAM: form : 
  *
  */
  this.validate_form = function (form) {
	
	// create a list to add empty required fields to
	var empty_req_fields = new Array(); 
	
	// create a list to add fields which fail their specific validation
	var invalid_fields = new Array(); 
	
	
	// look at each field in the list of required fields
	// if it is empty add the field name to the list of required fields
	for(var i = 0; i < this.req_fields.length; i++) {
      if (isEmpty(this.req_fields[i][0], form, this.req_fields[i][1])){
		  empty_req_fields.push(this.req_fields[i][0]);
	  }
	}
	
	// look at each fields which have a specific validation requirement
	// check if it is not already in the empty required fields list (fields can be on both required fields list and need specific validation)
    // check if it meets its validation requirements, and add it to the list of invalid fields if it doesnt
    for(i = 0; i < this.validations.length; i++) {
	  // only validate it if it is not an empty required field
	  if (index_of(this.validations[i][0], empty_req_fields) == -1) {

        if (!validate_field(this.validations[i][0], form, this.validations[i][1])){
		  invalid_fields.push(this.validations[i][0]);
	    }
	  }
	}
	

	
	// check if there were any errors in either of the 2 lists
	// if there were any errors in either of the 2 lists, then construct an error message based on those lists' contents
	if(empty_req_fields.length > 0 || invalid_fields.length > 0){
		
        var error_output = this.create_error_message (empty_req_fields, invalid_fields);
		
		if (this.error_replaces_intro) {
			 document.getElementById('intro_msg_'+this.form_id).style.display = 'none';
		}
		
		// show the error
		var js_form_error = document.getElementById('js_form_error_'+this.form_id);
		if (js_form_error == null) {
		    js_form_error = document.createElement('div');
		    js_form_error.setAttribute('id', 'js_form_error_'+this.form_id);
	   	    var submit_btn = document.getElementById("submit_"+this.form_id);
		    submit_btn.parentNode.insertBefore(js_form_error, submit_btn);
		}
		js_form_error.innerHTML = error_output;
		
		return false;

	}else {
		
		// will submit the form
		document.getElementById('form_error_'+this.form_id).style.display = 'none';
		var js_form_error = document.getElementById('js_form_error_'+this.form_id);
		if (js_form_error != null) {
			js_form_error.parentNode.removeChild(js_form_error);
		}

        return true;
		
	} // end if empty_req_fields.length > 0 || invalid_fields.length > 0
	
  } // END VALIDATE FORM FUNCTION
  
  
  /*
  *
  *  METHOD: create_error_message : creates an error message to output to the screen based on the arrays of empty required fields and fields that faced their validations
  *  PARAM: empty_req_fields : 
  *  PARAM: invalid_fields : 
  *
  */
  this.create_error_message = function (empty_req_fields, invalid_fields) {
	  
	    var  error_output = '<p class="error">';
		
		// if a customer error message has been 
		if (this.custom_error) {
			error_output = this.custom_error;
		} else {
			
			
	
		 
		  if (empty_req_fields.length > 0) {
		
		     error_output += 'You forgot to enter your ';
		
		    for (i = 0 ; i < empty_req_fields.length ; i++) {
		  
		  	  error_output += displayName(empty_req_fields[i]);
		  
		      if (i < empty_req_fields.length - 2) {
		        error_output += ", ";
		      } else if (i < empty_req_fields.length - 1) {
		        error_output += " and ";
		      }
		    }
		 
		  } // required
		 
		 
		  if (invalid_fields.length > 0) {
		 
		 
		     if (empty_req_fields.length > 0) {
		       error_output += ", and ";
		     }
		   
		   
		     for (i = 0 ; i < invalid_fields.length ; i++) {
		  
			   error_output += displayName(invalid_fields[i]);
		
		       if (i < invalid_fields.length - 2) {
		         error_output += ", ";
		       } else if (i < invalid_fields.length - 1) {
		         error_output += " and ";
		       }
		     }
		  
		     if (invalid_fields.length > 1) {
		       error_output += " are invalid";
		     } else if (invalid_fields.length == 1) {
		       error_output += " is invalid";
		     }
		  }
		 
		 error_output += ". Message not sent.";
		
		} // end if custom error
		
		 error_output += "</p>";
		 
		 return error_output;

	  
  }
  
  
  
  this.attachHint = function (elem_id, hint) {
	  
	  elem_id = elem_id+'_'+this.form_id;
	
	  this.fields_with_hints.push(elem_id);

      document.getElementById(elem_id).onfocus = function() {
		var form_element = document.getElementById(elem_id);
		var val = form_element.value;
		var hintstring = hint
		if (val == hintstring) {
		  if (jscss('check',form_element,'hint')) {
		    jscss('remove',form_element,'hint');
		  } 
		  
	        form_element.value = '';
			
		}
		 
		 
	  } // end on focus function
	  
      document.getElementById(elem_id).onblur = function() {
		  var form_element = document.getElementById(elem_id);
		  var val = form_element.value;
		  
		  
		  if (trim(val) == '') {
			  
			  
	          form_element.value = hint;
			
			
			if (!jscss('check',form_element,'hint')) {
		      jscss('add',form_element,'hint');
		    } 
			
		  }// if blur and empty

			
	  } // end onblur function
	  
	  
	}  // END ATTACH HINT
	
	
	this.applyHintClasses = function () {
	
	  for (var i = 0; i < this.fields_with_hints.length ; i++) {
		      jscss('add',document.getElementById(this.fields_with_hints[i]),'hint');
	
	  }
	
  } // end applyHintClasses
	 


}  
///////////////// end validator object class  ////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////

function validate(form, form_id) {
	
	return validators[form_id].validate_form(form);
	
}


function isEmpty(strfieldname, form, hint) {
	
	
	if (typeof(form[strfieldname].selectedIndex) != "undefined") {
		// for select element (dropdown list)
		
		if (form[strfieldname].selectedIndex > 0) {
			return false;
		} else {
			return true;
		}
		
		
	}	
	
	if (typeof(form[strfieldname].length) != "undefined")  {
		// for radio buttons
		
	    myOption = -1;
       for (i=form[strfieldname].length-1; i > -1; i--) {
         if (form[strfieldname][i].checked) {
            myOption = i; i = -1;
         }
       }
       if (myOption == -1) {
         return true;
       } else {
         return false;
	   }
		
	}
	
	
	
	if (typeof form[strfieldname].value != "undefined")  {
	// if not a set eg radio buttons
	
      strfield = form[strfieldname].value ;
	
      if (strfield == "" || strfield == null || strfield == hint)
      {
        return true;
      } else {
		  
		  
        return false;
	  }
	  
    }  
	
    return false;
}


function validate_field(strfieldname, form, validation_type) {
	
    if (typeof form[strfieldname].value != "undefined")  {
	  var value = form[strfieldname].value;
	  
	  switch (validation_type) {
		  case ('email') :
			  return isValidEmail(value, false);
		  case ('phone') :
			  return isValidPhone(value, false);
		  default :
		      return true
	  }
	  
	} else {
		return true; // if there is no value, then just say it is ok
    }  	
	
}


//function to check valid email address
function isValidEmail(strEmail, valid_if_empty){
	if (valid_if_empty == null) { valid_if_empty = false; }
     var emailReg = "^[\\w-_\.]*[\\w-_\.]\@[\\w]\.+[\\w]+[\\w]$";
     var regex = new RegExp(emailReg);   
	 
    if (valid_if_empty && strEmail == '') {
	   return true
    } else if (regex.test(strEmail) == false)  {
       return false;
    } else {
       return true; 
    }
}
//function to check valid email address
function isValidPhone(strPhonenum, valid_if_empty){
	
	return true; // not implemented yet
	
}


function displayName(field_name) {
	 return field_name.replace(/_/g, " ");
}





function index_of(val, array) {
	for (var i = 0; i<array.length; i++) {
		if (array[i] == val) { return i; }
	}
	return -1;	
}




/////////////////////////////////////////////////////////////////////////////////////////////////////////
//  a:  action to perform.
//  o:  the object in question.
//  c1:  the name of the first class
//  c2:  the name of the second class
//  Possible actions:
//  swap:  replaces class c1 with class c2 in object o.
//  add:  adds class c1 to the object o.
//  remove:  removes class c1 from the object o.
//  check:  test if class c1 is already applied to object o and returns true or false.
//////////////////////////////////////////////////////////////////////////////////////////////////////////
function jscss(a,o,c1,c2)
{
  switch (a){
    case 'swap':
      o.className=!jscss('check',o,c1)?o.className.replace(c2,c1): o.className.replace(c1,c2);
    break;
    case 'add':
      if(!jscss('check',o,c1)){o.className+=o.className?' '+c1:c1;}
    break;
    case 'remove':
      var rep=o.className.match(' '+c1)?' '+c1:c1;
      o.className=o.className.replace(rep,'');
    break;
    case 'check':
      return new RegExp('\\b'+c1+'\\b').test(o.className)
    break;
  }
}


function contains_url(str) {
  var v = new RegExp(); 
  v.compile("[A-Za-z]+://[A-Za-z0-9-_]+\\.[A-Za-z0-9-_%&\?\/.=]+");
  if (!v.test(str)) {
    return false;
  } else {
    return true;
  }

}
  function show_captcha (f_id) {
	  
	  var captcha_id = ('captcha_'+f_id);
	  var captcha_div = document.getElementById(captcha_id);
	  
	  captcha_div.style.display = 'block';
	  
	  var captcha_field_id = "captcha_code_"+f_id;
		
		
	  if (document.getElementById(captcha_field_id) == null) {
		
        var captcha_field = document.createElement("input");
	    captcha_field.setAttribute("value","");
	    captcha_field.setAttribute("name","code");
	    captcha_field.setAttribute("type","text");
	    captcha_field.setAttribute("id", captcha_field_id);
	  
	    captcha_div.appendChild(captcha_field);
		
	  }
}

  function hide_captcha (f_id) {
	  var captcha_id = ('captcha_'+f_id);
	  var captcha_div = document.getElementById(captcha_id);
	  var captcha_field_id = "captcha_code_"+f_id;
      var captcha_field = document.getElementById(captcha_field_id);
	  
	  captcha_div.style.display = 'none';
	  try { 
	    captcha_div.removeChild(captcha_field);
	  } catch(e) { }	 
  }
  
  
  function trim (str) {
	return str.replace(/^\s+|\s+$/g,"");
}
