var oValidation = new validationObj();

addEvent(window,"load",validationObj_onLoadActions);
function validationObj_onLoadActions() {
	oValidation.markRequiredFields();
}

function validationObj() {
	this.typeName = "validationObj";
	return this;
}

validationObj.prototype.getValidationElement = function(sFieldname) {
	var sParams, oParams;
	
	var aEl = document.getElementsByTagName("ckvalidate")
	for (var index=0; index < aEl.length; index++) {
		if (sParams = aEl[index].getAttribute("params")) oParams=eval(sParams);
		if ((oParams) && (oParams.fieldname==sFieldname))return aEl[index];
	}
	return null;
}

validationObj.prototype.markRequiredFields = function() {
	var sParams,oParams, oLabel, oSpanReqd;
	var aEl = document.getElementsByTagName("ckvalidate")
	for (var index=0; index < aEl.length; index++) {
		if (sParams = aEl[index].getAttribute("params")) oParams=eval(sParams);
		if ((oParams) && (oParams.bReqd)) {
			sLabelID = (oParams.elName ? oParams.elName + "." : ""); 
			sLabelID += oParams.fieldname + ".label";
			if (oLabel = document.getElementById(sLabelID)) {
				if (!(oSpanReqd = oDHTML.seekWithin(oLabel,"span",oParams.fieldname + ".reqd"))) {
					oSpanReqd = document.createElement("SPAN");
					oSpanReqd.id = oParams.fieldname + ".reqd";
					oSpanReqd.className="formMandatory";
					oSpanReqd.innerHTML="*&nbsp;";
					oLabel.insertBefore(oSpanReqd,oLabel.firstChild);
				}
			}
		}
	}
}

validationObj.prototype.markRequiredField = function(sFieldname) {
	var bReqd = (arguments.length==2 ? arguments[1] : true);
	var oSpanReqd, oEl, oParams;

	if (oEl = this.getValidationElement(sFieldname)) {
		var aValidation = Array();
		var sParams = oEl.getAttribute("params");

		if (sParams) oParams=eval(sParams);

		if (oParams.v) {
			oParams.v = oParams.v.replace("blank","");
			aValidation = oParams.v.split(",");
		}
		oParams.v = (bReqd ? "blank" : "");
		for (var index=0; index < aValidation.length; index++) {
			if (aValidation[index] != "") oParams.v=oParams.v + (oParams.v != "" ? "," : "") + aValidation[index];
		}
		sParams = getJSON(oParams);

		oEl.setAttribute("params","(" + sParams + ")");
	}

	if (oSpanReqd = document.getElementById(sFieldname + ".reqd")) { //mandatory label span must already be created
		oSpanReqd.innerHTML=(bReqd ? "*&nbsp;" : "");
	}
}

/*--------------------------------------------------------------------------------
 As you Type Validation
--------------------------------------------------------------------------------*/
validationObj.prototype.allowRegExp = function(oEvent,strRegExp) {
	var key,keychar;
	if (window.event) key = window.event.keyCode;
	else if ((oEvent) && (oEvent.charCode != 0 && !oEvent.ctrlKey)) key = oEvent.charCode; //checking charCode for non-zero allows backspace, CTRL+V and other functional keys to pass through and always go to next statement to return true
	else return true;

	var reg = new RegExp(strRegExp)
	keychar = String.fromCharCode(key);
	var matchedArr = keychar.match(reg)
	//alert("keyChar=" + keychar + "\nstrRegExp=" + strRegExp + "\nmatchedArr=" + matchedArr);
	return (matchedArr != null);
}
validationObj.prototype.disallowRegExp = function(oEvent,strRegExp) {
	//opposite of above. We can just return the negative result of allowRegExp() function because that would also block backspace, delete, etc
	var key,keychar;
	if (window.event) key = window.event.keyCode;
	else if ((oEvent) && (oEvent.charCode != 0 && !oEvent.ctrlKey)) key = oEvent.charCode; //checking charCode for non-zero allows backspace, CTRL+V and other functional keys to pass through and always go to next statement to return true
	else return true;

	var reg = new RegExp(strRegExp)
	keychar = String.fromCharCode(key);
	var matchedArr = keychar.match(reg)

	return (matchedArr == null);
}

validationObj.prototype.allowAlphaNumeric = function()  {
	var args = validationObj.prototype.allowAlphaNumeric.arguments;
	var strChars = '';
	if (args.length >= 1) strChars += args[0];
	var oEvent = (args.length >= 2 ? args[1] : (window.event || arguments.callee.caller.arguments[0]));
	return oValidation.allowRegExp(oEvent,'[a-zA-Z0-9' + strChars + ']');
}
validationObj.prototype.allowNumeric = function()  {
	var args = validationObj.prototype.allowNumeric.arguments;
	var strChars = '';
	if (args.length >= 1) strChars += args[0];
	var oEvent = (args.length >= 2 ? args[1] : (window.event || arguments.callee.caller.arguments[0]));
	return oValidation.allowRegExp(oEvent,'[0-9' + strChars + ']');
}
validationObj.prototype.allowEmail = function()  {
	var args = validationObj.prototype.allowEmail.arguments;
	var oEvent = (args.length==1 ? args[0] : (window.event || arguments.callee.caller.arguments[0]));
	return oValidation.allowAlphaNumeric('@\._\-',oEvent);
}
validationObj.prototype.allowPhone = function()  {
	var args = validationObj.prototype.allowPhone.arguments;
	var oEvent = (args.length==1 ? args[0] : (window.event || arguments.callee.caller.arguments[0]));
	return oValidation.allowRegExp(oEvent,'[0-9\\.\\-]');
}

validationObj.prototype.allowCurrency = function()  {
	var args = validationObj.prototype.allowCurrency.arguments; //option exists to pass in event object so this function can be called from within another function instead of just used as a direct event handler
	var oEvent = (args.length==1 ? args[0] : (window.event || arguments.callee.caller.arguments[0]));
	return oValidation.allowRegExp(oEvent,'[\b,0-9\.,\-]');
}

validationObj.prototype.allowDate = function()  {
	//option exists to pass in event object so this function can be called from within another function instead of just used as a direct event handler
	var oEvent = (arguments.length==1 ? arguments[0] : (window.event || arguments.callee.caller.arguments[0]));
	return oValidation.allowRegExp(oEvent,'[\b,0-9\/]');
}
validationObj.prototype.allowTime = function()  {
	//option exists to pass in event object so this function can be called from within another function instead of just used as a direct event handler
	var oEvent = (arguments.length==1 ? arguments[0] : (window.event || arguments.callee.caller.arguments[0]));
	return oValidation.allowRegExp(oEvent,'[0-9\:apmAPM ]');
}
validationObj.prototype.allowDateTime = function()  {
	//option exists to pass in event object so this function can be called from within another function instead of just used as a direct event handler
	var oEvent = (arguments.length==1 ? arguments[0] : (window.event || arguments.callee.caller.arguments[0]));
	return oValidation.allowRegExp(oEvent,'[0-9\:apmAPM\-\/ ]');
}

validationObj.prototype.allowAllExcept = function(strRegExp) {
	var args = validationObj.prototype.allowAllExcept.arguments; 
	var oEvent = (args.length >= 2 ? args[1] : (window.event || arguments.callee.caller.arguments[0]));
	return oValidation.disallowRegExp(oEvent,strRegExp);
}


/*--------------------------------------------------------------------------------------------------
isBlank
--------------------------------------------------------------------------------------------------*/
validationObj.prototype.isBlank = function(oEl) {
	var bBlank;
	if (oEl) {
		if (!oEl.type) {
			switch (oEl[0].type) {
				case "radio" :
				case "checkbox":
					bBlank = true;
					for (var i=0; i < oEl.length && bBlank; i++) {
						bBlank = (!oEl[i].checked);
					}
					break;
				case "select-one": //will occur if two select boxes with same name on page
					bBlank = true;
					for (var i=0; i < oEl.length && bBlank; i++) {
						bBlank = (oEl[i].value == "");
					}
					break;
			}
			//for (var i=0; i < oEl.length; i++) indicateFieldStatus(oEl[i],!bBlank)
		} else {
			switch (oEl.type) {
				case "checkbox" : //will get here instead of above if there is only one checkbox with this name on the page
					bBlank = !oEl.checked;
					break;
				case "select-one" :
					//if the select box size is > 1 then we're assuming the first element is a valid selection
					if (oEl.size > 1) bBlank = oEl.selectedIndex < 0
					else {
						//if the value of the first field is an empty string, assume that it is a blank ([Select...]) type option
						bBlank = ((trim(oEl.options[0].value).length==0 && oEl.selectedIndex <=0) || (oEl.selectedIndex == -1));
					}
					break;
				case "text" :
				case "textarea" :
				case "hidden" :
				case "password" :
				case "file":
					bBlank = trim(oEl.value).length == 0;
					break;
				case "select-multiple" : //return false if select list is empty...unless special attribute set since this mainly applies to the multiple selects in Reports
					bBlank = (oEl.options.length == 0);
					if ((!bBlank) && (oEl.validateIndex)) bBlank = oEl.selectedIndex < 0;
					break;
				default: 
					alert("Encountered a "+oEl.type+" data type that is not handled.  Name:"+oEl.name);
			}
				
		}
			
	}

	return (bBlank);
}
/*--------------------------------------------------------------------------------------------------
isValid : auto-decision field validation based on field name
--------------------------------------------------------------------------------------------------*/
validationObj.prototype.isValid = function(oEl) {
	var bValid = false;
	if (oEl){
		if (oEl.type != "text") {
			bValid = true; //can't handle anything other than text form fields right now
		} else {
			sFieldname = oEl.getAttribute("fieldname"); //key on this first since most unique;
			if (!sFieldname) sFieldname = oEl.name;
			if (!sFieldname) sFieldname = oEl.id;
			if (!sFieldname) throwConsoleError("validationObj.isValid","Unable to make an auto-decision based on fieldname");
			
			sValue = oEl.value;	
						
			if (sValue != "") {
				if (sFieldname.search(/areacode/i) >=0) {
					bValid = this.isValidAreaCode(sValue);
				} else if (sFieldname.search(/phonenumber|faxnumber|cellularnumber|faximportnumber/i) >=0) {
					bValid = this.isValidPhoneNumber(sValue);
					if (bValid) oEl.value = formatPhoneNumber(sValue);
				} else if (sFieldname.search(/email/i) >=0) {
					var aReturn = validateEmail(sValue);
					bValid = aReturn[0];
				} else if (sFieldname.search(/zip/i) >=0) {
					bValid = this.isValidZipCode(sValue);
				} else if (sFieldname.search(/date/i) >=0) {
					bValid = this.isValidDate(sValue);
				} else {
					bValid = true;
				}
			} else {
				bValid = true;
			}
			
		}
		
	} 
	
	return (bValid);
}


/*--------------------------------------------------------------------------------------------------
Utilities
--------------------------------------------------------------------------------------------------*/
validationObj.prototype.isMatchRegExp = function(sValue,sRegExp) {
	var bValid = true; //only validates if not a blank value!
	if (sValue != "") {
		var reg = new RegExp(sRegExp);
		bValid = (sValue.match(reg) != null)
	}
	return bValid;
}
/*--------------------------------------------------------------------------------------------------
Custom data types or functions to call directly when not automatically handled by name search
	within isValid()
--------------------------------------------------------------------------------------------------*/
validationObj.prototype.isValidURL = function(sValue) {
	return this.isMatchRegExp(sValue,"(http:\/\/|https:\/\/|mailto:).+")
}
/*--------------------------------------------------------------------------------------------------*/
validationObj.prototype.isValidZipCode = function(sValue) {
	if (sValue.indexOf(".") != -1) return false;
	if (sValue.indexOf(",") != -1) return false;
		
	var len =  sValue.length;	
	if (len == 5) return !isNaN(sValue);
	else {		
	    if (len == 10) return (!isNaN(sValue.substr(0,5))) && (!isNaN(sValue.substr(6,4))) && (sValue.substr(5,1)=="-");
		else return false;	
	}
	return false;
}
/*--------------------------------------------------------------------------------------------------*/
validationObj.prototype.isValidAreaCode = function(sValue) {
	if (sValue.indexOf(".") != -1) return false;
	if (sValue.indexOf(",") != -1) return false;
	if (sValue.length == 3) return !isNaN(sValue);
	return false;
}
/*--------------------------------------------------------------------------------------------------*/
validationObj.prototype.isValidPhoneNumber = function(sValue) {
	if (sValue.indexOf(",") != -1) return false;
	var len = sValue.length;	
	if (len == 7) return !isNaN(sValue);
	else {
	    if (len == 8) return (!isNaN(sValue.substr(0,2))) && (!isNaN(sValue.substr(4,4))) && (sValue.substr(3,1)=="-");
		else return false;	
	}
	return false;
}
/*--------------------------------------------------------------------------------------------------*/
validationObj.prototype.isValidDate = function(sValue) {
	var args = validationObj.prototype.isValidDate.arguments;
	var oEl = (args.length==2 ? args[1] : null);
	
	//requires date to be in mm/dd/yyyy, mm/dd/yy, mm-dd-yy, mm-dd-yyyy, or mmddyyyy format
	var datePat = /^(\d{1,2})([\/-]*)(\d{1,2})([\/-]*)(\d{2,4})$/;
	var matchArray = sValue.match(datePat); 
	if ((matchArray == null) || ((sValue.indexOf("/") == -1) && (sValue.length != 8)) ) {
		return false;
	} else {
		//now validate the values
		var month = matchArray[1]*1;
		var day = matchArray[3]*1;
		var year = parseInt(matchArray[5]);
		if ((month < 1) || (month > 12)) return false;
		if ((day < 1) || (day > 31)) return false;
		if ((month == 4 || month == 6 || month == 9 || month == 11) && (day == 31)) return false;
		if (month == 2) {
			var bLeap = (year % 4 == 0 && (year % 100 !=0 || year % 400 == 0));
			if (day > 29 || (day == 29 && !bLeap)) return false
		}
		if ((year >= 100) && (year <= 999)) return false; //do not allow three digit year
		
		if (oEl) formatDate(oEl,month,day,year)

		return true;
	}
}
/*--------------------------------------------------------------------------------------------------*/
validationObj.prototype.isValidTime = function(sValue) {

	//requires date to be in hh:mm AM/PM
	var timePat = /^(\d{1,2}):(\d{1,2}) *(AM|PM)$/i;
	var matchArray = sValue.match(timePat); 
	if ((matchArray == null) || ((sValue.indexOf(":") == -1) && (sValue.length != 8)) ) {
		return false;
	} else {
		//now validate the values
		var hour = matchArray[1]*1;
		var min = matchArray[2]*1;
		if ((hour < 1) || (hour > 12)) return false;
		if (min > 59) return false;
		
		return true;
	}
}

/*--------------------------------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------------------------------*/
validationObj.prototype.validateEmail = function(sEmail) {
	var objReturn = Array();
	var emailPat=/^(.+)@(.+)$/
	var specialChars="\\(\\)<>@,;:\\\\\\\"\\.\\[\\]"
	var validChars="\[^\\s" + specialChars + "\]"
	var quotedUser="(\"[^\"]*\")"
	var ipDomainPat=/^\[(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\]$/
	var atom=validChars + '+'
	var word="(" + atom + "|" + quotedUser + ")"
	var userPat=new RegExp("^" + word + "(\\." + word + ")*$")
	var domainPat=new RegExp("^" + atom + "(\\." + atom +")*$")
	var matchArray=sEmail.match(emailPat)
	
	if (matchArray==null) return Array(false,"Format is incorrect (check @ and .'s)");

	var user=matchArray[1];
	var domain=matchArray[2];
	if (user.match(userPat)==null) return Array(false,"The user name doesn't seem to be valid");

	var IPArray=domain.match(ipDomainPat)
	if (IPArray!=null) { // this is an IP address
		for (var i=1;i<=4;i++) {
			if (IPArray[i]>255) return Array(false,"Destination IP address is invalid");
	    }
	    return Array(true)
	}

	var domainArray=domain.match(domainPat)
	if (domainArray==null) return Array(false,"The domain name doesn't seem to be valid");

	var atomPat=new RegExp(atom,"g")
	var domArr=domain.match(atomPat)
	var len=domArr.length
	if (domArr[domArr.length-1].length<2 ||  domArr[domArr.length-1].length>4) return Array(false,"The address must end in a three or four letter domain, or two letter country");

	if (len < 2) return Array(false,"This address is missing a hostname");

	return Array(true);
}
