var Validator = new Object();

	Validator.NOT_BLANK = 1; 
	Validator.NUMBER = 2;		// Integer
	Validator.FLOAT = 3;         
	Validator.MAX_LENGTH = 4; 
	Validator.PERCENTAGE = 5;		// between 0-100
	Validator.APOSTROPHE = 6;    		// ' or "
	Validator.DATE_ENTERED = 7;    		// typing in the date, instead of using the widget

	Validator.VALUE_MATCHES = 10; 
	Validator.VALUE_DOESNT_MATCH = 11;  
	
	Validator.VALUE_SELECTED = 20;
	Validator.RADIO_SELECTED = 21; // works for radios or checkboxes, make sure at least one was selected
	Validator.CHECKBOX_CHECKED = 22; // make sure a checkbox has been checked, for example agreeing to the terms

	Validator.EMAIL = 30;      
	Validator.EMAIL_MULTIPLE = 31;
	Validator.USERNAME = 32;            
	Validator.PASSWORD = 33;            
	Validator.VALID_FILE_TYPE = 34;    

	Validator.ZIP_CODE = 40; //5 digits
	Validator.YEAR = 41;    		// entered a year, 4 digits

	Validator.PROFANITY = 50;   
	Validator.SPECIAL_CHARACTERS = 51;   // characters that create displaying problems, such as \\, <, >, "  
	
	Validator.CUSTOM = 100; // pass in a custom function, that returns true/false, for validation
	
    Validator.arrValidations = new Array();
    
    Validator.DEFAULT_ERROR_MESSAGE = "Please complete the highlighted fields.";
    Validator.messages = new Array();
    //Validator.messages[Validator.NOT_BLANK] = "Please enter a value for \"{0}\"";
    Validator.messages[Validator.DATE_ENTERED] = "Please enter a valid date in the format \"mm/dd/yyyy\"";
    Validator.messages[Validator.NUMBER] = "Please enter a valid non-decimal number (ex. \"10\" or \"123\") for \"{0}\"";
    Validator.messages[Validator.FLOAT] = "Please enter a valid number (ex. \"10\" or \"1.23\") for \"{0}\"";
    Validator.messages[Validator.PERCENTAGE] = "Please enter a valid percentage between 0 and 100 (ex. \"10\" or \"99\") for \"{0}\"";
    Validator.messages[Validator.MAX_LENGTH] = "Please enter a maximum of {1} characters for \"{0}\", you currently have {2}";
    Validator.messages[Validator.SPECIAL_CHARACTERS] = "Please check that you have not entered any of the following characters for \"{0}\": \\, \", &gt;, &lt;";
    Validator.messages[Validator.PROFANITY] = "Please refrain from using profanity: '{1}' is not allowed.";
    Validator.messages[Validator.APOSTROPHE] = "Please check that you have not entered any of the following characters for \"{0}\": \'";

    Validator.messages[Validator.VALUE_MATCHES] = "Please confirm with the same value for \"{0}\".";
    Validator.messages[Validator.VALUE_DOESNT_MATCH] = "Please check that you have entered a different {0}.";

    Validator.messages[Validator.RADIO_SELECTED] = "Please select an option for \"{0}\"";
    //Validator.messages[Validator.VALUE_SELECTED] = "Please select a value for \"{0}\"";
    //Validator.messages[Validator.CHECKBOX_CHECKED] = "{0}";

    Validator.messages[Validator.EMAIL] = "Please enter a valid email address";// for \"{0}\"";
    Validator.messages[Validator.EMAIL_MULTIPLE] = "Please enter all valid email addresses, separated with a ',' for \"{0}\"";
    Validator.messages[Validator.USERNAME] = "Please select a {0} with a length of 4 to 15 characters";
    Validator.messages[Validator.PASSWORD] = "Please select a {0} with a length of 5 to 15 characters";
    Validator.messages[Validator.VALID_FILE_TYPE] = "You must upload a valid file type for \"{0}\".  Allowed file types include: {1}.";
    Validator.messages[Validator.ZIP_CODE] = "Please enter your zip code as a 5-digit number (ex. 94105)";
    Validator.messages[Validator.YEAR] = "Please enter a 4-digit number for \"{0}\" (ex. 2010)";

    Validator.messages['DATE_TIME_FORMAT'] = "Please fill in the time in the following format: hh:mm.  Ex: 12:30";
    Validator.messages['DATE_REQUIRED'] = "Please enter a complete date for \"{0}\"";   
    

Validator.validateInner = function(inputObj,fieldLabel,isRequired,validationType,arg0,arg1,arg2) {
    //alert('start validate, type: ' + validationType);
    var isValid = true;

    switch (validationType) {
		
    case Validator.NOT_BLANK:
        var inputValue = inputObj.value;
        if (inputValue.length <= 0 || inputValue.match(/^\s*$/)) {
            inputObj.value = '';
        	Validator.showMessage(inputObj, validationType, [fieldLabel]);
            return false;
        }
        break;
        
    case Validator.NUMBER:
        var inputValue = inputObj.value;
        if (isRequired || inputValue != '') {
            if (!inputValue.match(/^\d+$/)) {
            	Validator.showMessage(inputObj, validationType, [fieldLabel]);
                return false;
            }
        }
        break;

    case Validator.FLOAT:
        var inputValue = inputObj.value;
        //alert('input value:' + inputValue + '! required? ' + (isRequired ? 'true' : 'false'));
        if (isRequired || inputValue != '') {
            if (!inputValue.match(/^((\d+(\.\d*)?)|((\d*\.)?\d+))$/)) {
            	Validator.showMessage(inputObj, validationType, [fieldLabel]);
                return false;
            }
        }
        break;
        
    case Validator.PERCENTAGE:
        var inputValue = inputObj.value;
        if (isRequired || inputValue != '') {
            if (!inputValue.match(/^\d+$/)) {
            	Validator.showMessage(inputObj, validationType, [fieldLabel]);
                return false;
            }
            //try {
            	if (inputValue < 0 || inputValue > 100) {
            		Validator.showMessage(inputObj, validationType, [fieldLabel]);
                	return false;            	
            	}
            //} catch(e) {
            //}
        }
        break;

    case Validator.MAX_LENGTH:
        var inputValue = inputObj.value;
        if (inputValue.length > arg0) {
        	Validator.showMessage(inputObj, validationType, [fieldLabel,arg0,inputValue.length]);
            return false;
        }
        break;

    case Validator.APOSTROPHE:
        var inputValue = inputObj.value;

        if (inputValue.indexOf('\'') != -1 ||
            inputValue.indexOf('"') != -1 ) {
        	Validator.showMessage(inputObj, validationType, [fieldLabel]);
            return false;
        }
        if (isRequired) {
            return Validator.validateInner(inputObj,fieldLabel,isRequired,Validator.NOT_BLANK,arg0,arg1,arg2);
        }
        return true;
        
    case Validator.DATE_ENTERED:
    	if (!isRequired && inputObj.value.trim() == '') {
    		return true;
    	}
    	var retVal = Validator.isDateValid(inputObj);
    	if (!retVal) {
    		Validator.showMessage(inputObj, validationType, [fieldLabel]);
    		return false;
    	} else {
    		inputObj.value = retVal;
    	}
        return true;

    case Validator.VALUE_MATCHES:
        var inputValue = inputObj.value;
        var inputValue2 = arg0.value;
        //alert('val1: ' + inputValue + ' val2: ' + inputValue2);
        if (inputValue != inputValue2) {
        	Validator.showMessage(arg0, validationType, [fieldLabel, arg1]);
            return false;
        }
        break;		
		
    case Validator.VALUE_DOESNT_MATCH:
        var inputValue = inputObj.value.toLowerCase();
        var inputValue2 = arg0.toLowerCase();
        if (inputValue == inputValue2) {
        	Validator.showMessage(inputObj, validationType, [fieldLabel]);
            return false;
        }
        break;		

    case Validator.VALUE_SELECTED:
        if (isRequired && (inputObj.selectedIndex == -1 || inputObj.options[inputObj.selectedIndex].value == '')) {
        	Validator.showMessage(inputObj, validationType, [fieldLabel]);
            return false;
        }
        break;
		
    case Validator.RADIO_SELECTED: 
        if (isRequired) {
        	if (inputObj.length == undefined) {
        		if (inputObj.checked) {
        			return true;
        		}
        	} else {
	            for (var x=0;x<inputObj.length;x++) {
	                if (inputObj[x].checked) {
	                    return true;
	                }
	            }
	        }
            // if we're here, nothing was selected
        	Validator.showMessage(inputObj[0], validationType, [fieldLabel]);
        	//alert(Validator.buildMessage(validationType, fieldLabel));
            return false;
        }
        break;

    case Validator.CHECKBOX_CHECKED:
    	if (inputObj.checked) {
    		return true;
    	}
    	Validator.showMessage(inputObj, validationType, [fieldLabel]);
        //alert(Validator.buildMessage(validationType, fieldLabel));
        return false;		
        break;

    case Validator.EMAIL:
        var inputValue = inputObj.value;
        if (isRequired || '' != inputValue) {
            if (!inputValue.match(/^[_a-zA-Z0-9][_a-zA-Z0-9\'\w\.-]*@[_a-zA-Z0-9][_a-zA-Z0-9\w\.-]*\.[_a-zA-Z0-9\w\.-]*[_a-zA-Z0-9]$/)) {
                Validator.showMessage(inputObj, validationType, [fieldLabel]);
                return false;
            }
        }
        break;

    case Validator.EMAIL_MULTIPLE:
        var inputValue = inputObj.value;
        var valueArr = inputValue.split(',');

        for (var x=0; x<valueArr.length; x++) {
            if (!trim(valueArr[x]).match(/^[a-zA-Z0-9][a-zA-Z0-9\'\w\.-]*@[a-zA-Z0-9][a-zA-Z0-9\'\w\.-]*\.[a-zA-Z0-9\'\w\.-]*[a-zA-Z0-9]$/)) {
                Validator.showMessage(inputObj, validationType, [fieldLabel]);
                return false;
            }
        }
        break;
        
    case Validator.USERNAME:
        var inputValue = inputObj.value;
        if (isRequired || inputValue != '') {
            if (!(inputValue.length>=4 && inputValue.length<=15)) {
            	Validator.showMessage(inputObj, validationType, [fieldLabel]);
                return false;
            }
            return Validator.validateInner(inputObj,fieldLabel,isRequired,Validator.APOSTROPHE,arg0,arg1,arg2);
            return Validator.validateInner(inputObj,fieldLabel,isRequired,Validator.SPECIAL_CHARACTERS,arg0,arg1,arg2);
        }
        break;

    case Validator.PASSWORD:
        var inputValue = inputObj.value;
        if (isRequired || inputValue != '') {
            if (!(inputValue.length>=5 && inputValue.length<=15)) {
            	Validator.showMessage(inputObj, validationType, [fieldLabel]);
                return false;
            }
            return Validator.validateInner(inputObj,fieldLabel,isRequired,Validator.SPECIAL_CHARACTERS,arg0,arg1,arg2);
        }
        break;
		
    case Validator.VALID_FILE_TYPE:
        var theIndex = inputObj.value.lastIndexOf('.');
        if (theIndex <= 0 || theIndex == (inputObj.value.length + 1)) {
        	Validator.showMessage(inputObj, validationType, [fieldLabel]);
            return false;
        }		
        var fileExt = inputObj.value.substring(theIndex+1);
        var validExtensions = arg0.toLowerCase().split(/,[\s]*/);
		alert('fileExt: ' + fileExt + ' valid: ' + validExtensions);
        var isValid = false;
        for (var x=0;x<validExtensions.length;x++) {
            if (fileExt.toLowerCase() == validExtensions[x]) {
                isValid = true;
            }
        }
        if (!isValid) {
            //((fileExt == 'doc') ||
            //  (fileExt == 'txt') ||
            //  (fileExt == 'rtf') ||
            //  (fileExt == 'pdf') ||
            //  (fileExt == 'htm') ||
            //  (fileExt == 'html'))) {
        	Validator.showMessage(inputObj, validationType, [fieldLabel]);
            return false;
        }
        return true;
        
    case Validator.ZIP_CODE:
        var inputValue = inputObj.value;
        if (isRequired || inputValue != '') {
            if (!inputValue.match(/^\d\d\d\d\d$/)) {
            	Validator.showMessage(inputObj, validationType, [fieldLabel]);
                return false;
            }
        }
        break;
        
    case Validator.YEAR:
        var inputValue = inputObj.value;
        if (isRequired || inputValue != '') {
            if (!inputValue.match(/^\d\d\d\d$/)) {
            	Validator.showMessage(inputObj, validationType, [fieldLabel]);
                return false;
            }
        }
        break;
        

    case Validator.SPECIAL_CHARACTERS:
        var inputValue = inputObj.value;

        if (inputValue.indexOf("\\") != -1 ||
            inputValue.indexOf('<') != -1 ||
            inputValue.indexOf('>') != -1 ||
            inputValue.indexOf('"') != -1 ) {
        	Validator.showMessage(inputObj, validationType, [fieldLabel]);
            return false;
        }
        if (isRequired) {
            return Validator.validateInner(inputObj,fieldLabel,isRequired,Validator.NOT_BLANK,arg0,arg1,arg2);
        }
        return true;
        

    default:
    	alert('Unknown Validation type: ' + validationType);
        return true;

    }
    // default to true
    return true;
}

Validator.showMessage = function(inputObj, validationType, arrMessageVars) {
	if (!Validator.hasError) { //this is the first one
		Validator.focusField(inputObj);	
		Validator.errorMessage = Validator.buildMessage(validationType, arrMessageVars);
	}
}

// any arguments passed in after validationType are substituted
Validator.buildMessage = function(validationType, arrMessageVars) {
	//alert('arrMessageVars:' + arrMessageVars + ' length: ' + arrMessageVars.length);
    var msgToReturn = Validator.messages[validationType];
    if (msgToReturn == undefined) {
    	msgToReturn = Validator.DEFAULT_ERROR_MESSAGE;
    }
    //alert('msgToReturn: ' + msgToReturn + ' validationType: ' + validationType + ' args: ' + Validator.buildMessage.arguments.length);
    for (var x=0; x<arrMessageVars.length; x++) {
    	msgToReturn = msgToReturn.replace('{'+x+'}',arrMessageVars[x]);
    }
    return msgToReturn;
}

Validator.focusField = function(inputObj) {
	// don't focus if it's hidden
	try {
    	inputObj.focus();
    } catch(err) {
    }
}

/**
* useful if a multi-step ajax form; the validations are held in memory since the page doesn't reload, so need to manually clear them out
*/
Validator.clearValidations = function(options) {
	//alert('in clearValidations: ' + options.strFormName);
    if (options.strFormName == undefined) {
    	options.strFormName = 'frmMain';
    }
    Validator.arrValidations[options.strFormName] = new Array();
}

/**
 * addValidation
 * adds the passed in validation call to the array of validations to perform on form submittal
 * options: can include all the options passed to validate, plus:
 * 		    strTestFunc: func to test, if true then perform the validation, otherwise not
 *			strFormName: call this validation when validation the form named strFormName.  Defaults to frmMain if not passed in.
 */
Validator.addValidation = function(options) {
//alert('adding validation for form: ' + options.inputObj.val() + '!');
    if (options.strTestFunc == undefined) {
    	options.strTestFunc = 'true';
    }
    if (options.strFormName == undefined) {
    	options.strFormName = 'frmMain';
    }
    if (Validator.arrValidations[options.strFormName] == undefined) {
    	Validator.arrValidations[options.strFormName] = new Array();
    }	
    var index = Validator.arrValidations[options.strFormName].length;
    Validator.arrValidations[options.strFormName][index] = options;
}

// iterates the validation array strings returning false at the first occurence of an invalid field
Validator.isFormValid = function(strFormName) {
  if (strFormName === undefined) {
  	strFormName = 'frmMain';
  }
  Validator.hasError = false;
  if (Validator.arrValidations[strFormName] == undefined) {
  	return true; // nothing to validate
  }
  var validations = Validator.arrValidations[strFormName];
  
  // want to validate the whole form, show the first error 
  for(var x=0;x<validations.length;x++)
  {
  	//alert('Validating: ' + validations[x].validationType);
      if (eval(validations[x].strTestFunc)) {
          if (!Validator.validate(validations[x])) {
              Validator.hasError = true;
          }
      }
  }
  return !Validator.hasError;
}

/**
* checks if a date is entered in some reasonable format
* method can be called on blur / change of the date field or when the form is submitted (validation type Validator.DATE_ENTERED)
* tries to make the date match the format 'mm/dd/yyyy', returns the formatted date
*/
Validator.isDateValid = function(objTxtInput) {
	var strDate = objTxtInput.value.trim();
    //alert('validating date: ' + strDate);
    if (!(
    	strDate.match(/^[0-9][0-9]?-[0-9][0-9]?-[0-9]+$/) || 
    	strDate.match(/^[0-9][0-9]?\/[0-9][0-9]?\/[0-9]+$/)
    	)) {
    	//alert('not a valid date');
        return false;
    }
    var delim = (strDate.indexOf('-') > 0 ? '-' : '/');
    var arrDate = strDate.split(delim);
    try {
    //if (arrDate.length == 3) {
    	var month = parseInt(arrDate[0],10);
    	var day = parseInt(arrDate[1],10);
    	var year = parseInt(arrDate[2],10);
    	//alert('year: ' + year + ' arrDate[2]: ' + arrDate[2] + ' parseInt: ' + parseInt('09'));
		return (month < 10 ? '0' : '') + month + (day < 10 ? '/0' : '/') + day + (year < 10 ? '/200' : (year < 100 ? '/20' : '/')) + year;    	
    } catch(err) {
    	return false;
    }
    //alert('good date');
	//return true;
}

/**
* options can include: inputObj, fieldLabel, strFormName, validationType, isRequired, arg0, arg1, arg2, fnValidation, strCustomMessage
*/
Validator.validate = function(options) {
	var inputObj = options.inputObj;
	var fieldLabel = options.fieldLabel;
	var validationType = options.validationType;
	var isRequired = options.isRequired;
	var strInputName = (inputObj.name !== undefined ? inputObj.name : (inputObj.length > 0 ? inputObj[0].name : inputObj.name)); //for radio buttons, need to get the object first inside the array; for select, has a length but also a name
	var strLabelId = 'lbl' + Util.escapeStringForJQuery(strInputName);//'lbl' + strInputName.replace(/\./g,'\\.').replace(/\[/g,'\\[').replace(/\]/g,'\\]').replace(/\_/g,'\\_'); // escape in case the form field references a child property ex. (editing a site) homeowner.firstName
	
	var bResult = true;
	if (validationType == Validator.CUSTOM) {
		//alert('custom validate, calling fn: ' + options.fnValidation + '!');
		bResult = eval(options.fnValidation);
	} else {
		bResult = Validator.validateInner(inputObj,fieldLabel,isRequired,validationType,options.arg0,options.arg1,options.arg2);
	}
	
	if (!bResult) {
		//alert('strLabelId: ' + strLabelId + ' = ' + $('#' + strLabelId) + '!');
		if (strLabelId) { 
			$('#' + strLabelId).addClass('error'); 
		}
		//alert('adding error class to inputObj: ' + inputObj[0].outerHTML);
		$(inputObj).addClass('error');
		if (options.strCustomMessage !== undefined) {
			Validator.errorMessage = options.strCustomMessage;
		} 
		return false;
	} else {
		return true;
	}
}

/**
* The old way the validation worked, to be removed once everything is converted
*/
Validator.validateOld = function(inputObj,fieldLabel,isRequired,validationType,arg0,arg1,arg2) {
	var bValid = Validator.validateInner(inputObj,fieldLabel,isRequired,validationType,arg0,arg1,arg2);
	if (!bValid) {
		$(inputObj).addClass('error');
		inputObj.focus();
		if (validationType == Validator.NOT_BLANK) {
			alert("Please enter a value for " + fieldLabel);
		} else {
			alert(Validator.buildMessage(validationType, [fieldLabel]));
		}		
	}
	return bValid;
}

Validator.checkDateEntry = function(objFormInput) {
  var newDateVal = Validator.isDateValid(objFormInput);
  if (!newDateVal) {
  	$(objFormInput).addClass('error');
  	objFormInput.focus();
  	return false;
  } else {
    $(objFormInput).removeClass('error');
  	$(objFormInput).val(newDateVal);
  	return true;
  }
}
