/************************************************************
Form Auto Validation Library
->Relies on generic_library.js for AttachEvent(), FormatDateTime(), and PreventDefault()<-
Copyright © 2002-2003 Gavin Kistner and Refinery, Inc. -- http://www.refinery.com
Reuse and modification permitted provided the previous line is included in full
v 1.1    20020721 -- added email, date, minLen, maxlength
v 1.2    20020723 -- tersified as library, NS6 compat, bug fixin, date ranges
v 1.2.1  20020730 -- non-required empty dates no longer incorrectly fail with bad format
v 1.2.2  20020808 -- extra \ added to email regexp to really require period
v 1.3    20030122 -- radio buttons now support required="true"
v 1.3.5  20030201 -- added generic form-level requiredMessage
v 1.3.6  20030228 -- integer types can now be negative
v 1.4    20030506 -- showAllErrors added
v 1.4.5  20030529 -- skips disabled elements
v 1.4.6  20030612 -- minor tweak on event attaching to work with Safari
v 1.4.7  20030728 -- fix to skip 'elements' without .value (fieldset)
v 1.4.8  20030731 -- minlength only enforced on non-required elements when a value is supplied
v 1.5    20030801 -- regexp are now insensitive by default; added 'mustMatchCaseSenstive="true"' option
*************************************************************/

function AVF_Validate(f){
	var els = f.elements;
	var formReqMessage=f.getAttribute('requiredMessage');
	var showAllErrors = f.getAttribute("showAllErrors") && (f.getAttribute("showAllErrors")+"").toLowerCase()=="true";
	var allErrors={ firstEl:null, errorMsg:'' };
	if (formReqMessage=="") formReqMessage=null;
	for (var i=0,len=els.length;i<len;i++){
		var el = els[i];
		if (el.disabled || IsHidden(el) || el.value==null) continue;

		var reqd = el.getAttribute("required") && (el.getAttribute("required")+"").toLowerCase()=="true";
		var mustMatch = el.getAttribute("mustMatch"); if (mustMatch=="") mustMatch=null;
		var minVal = el.getAttribute("minvalue"); if (minVal=="") minVal=null;
		var maxVal = el.getAttribute("maxvalue"); if (maxVal=="") maxVal=null;
		var minLen = el.getAttribute("minlength"); if (minLen=="") minLen=null;
		var maxLen = el.getAttribute("maxlength"); if (maxLen=="") maxLen=null;
		var valAs = el.getAttribute("validateAs"); if (valAs=="") valAs=null;

		var valLen = el.value.length;

		if (!reqd && mustMatch==null && minVal==null && maxVal==null && minLen==null && maxLen==null && valAs==null) continue;

		var niceName = el.getAttribute("niceName");
		if (!niceName) niceName=el.name;

		var valMsg = el.getAttribute("mustMatchMessage"); if (valMsg=="") valMsg=null;
		if (valAs!=null){
			valAs = valAs.toLowerCase();
			if (valAs=="email"){
				mustMatch='[^@]+@[^.]+\\..+';
				if (!valMsg) valMsg = niceName+" doesn't look like a valid email address. It must be of the format 'john@host.com'";
			} else if (valAs=="phone"){
				mustMatch='\\D*\\d*\\D*(\\d{3})?\\D*\\d{3}\\D*\\d{4}\\D*';
				if (!valMsg) valMsg = niceName+" doesn't look like a valid phone number.";
			} else if (valAs=="zipcode"){
				mustMatch='\\d{5}(-\\d{4})?';
				if (!valMsg) valMsg = niceName+" doesn't look like a valid zip code. It should be 5 digits, optionally followed by a dash and four more, e.g. 19009 or 19009-2314";
			} else if (valAs=="integer"){
				mustMatch='-?\\d+';
				if (!valMsg) valMsg = niceName+" must be an integer.";
			} else if (valAs=="float"){
				mustMatch='-?\\d*(\.\\d+)?';
				if (!valMsg) valMsg = niceName+" must be a number, such as 1024 or 3.1415 (no commas are allowed).";
			}
		}

		var failMessage = el.getAttribute("requiredMessage")?el.getAttribute("requiredMessage"):formReqMessage?formReqMessage.replace(/%niceName%/gi,niceName):(niceName+" is a required field.");
		if (reqd && ((el.type!='radio' && (el.value==null || el.value=="")) || (el.type=='radio' && !AVF_RadioSelected(el)))){
			if (showAllErrors) AVF_AddError(allErrors,el,failMessage);
			else return AVF_Fail(el,failMessage);
		}
		if (mustMatch && el.value!="" && (!(new RegExp('^'+mustMatch+'$',(el.getAttribute("mustMatchCaseSensitive")=="true"?null:"i")).test(el.value)))){
			failMessage = valMsg?valMsg:(niceName+" is not in a valid format.");
			if (showAllErrors) AVF_AddError(allErrors,el,failMessage);
			else return AVF_Fail(el,failMessage);
		}
		if (minVal!=null && valLen>0 && el.value*1<minVal*1){
			failMessage = niceName+" may not be less than "+minVal+".";
			if (showAllErrors) AVF_AddError(allErrors,el,failMessage);
			else return AVF_Fail(el,failMessage);
		}
		if (maxVal!=null && valLen>0 && el.value*1>maxVal*1){
			failMessage = niceName+" may not be greater than "+maxVal+".";
			if (showAllErrors) AVF_AddError(allErrors,el,failMessage);
			else return AVF_Fail(el,failMessage);
		}
		if (minLen!=null && valLen<minLen*1 && (reqd || valLen>0)){
			failMessage = niceName+" must have at least "+minLen+" characters.";
			if (showAllErrors) AVF_AddError(allErrors,el,failMessage);
			else return AVF_Fail(el,failMessage);
		}
		if (maxLen!=null && valLen>maxLen*1){
			failMessage = niceName+" may not be more than "+maxLen+" characters (it is currently "+valLen+" characters).";
			if (showAllErrors) AVF_AddError(allErrors,el,failMessage);
			else return AVF_Fail(el,failMessage);
		}
		if (valAs=="date" && valLen>0){
			var curVal = new Date(el.value);
			if (isNaN(curVal)){
				failMessage = niceName+" must be a valid date (e.g. 12/31/2001)";
				if (showAllErrors) AVF_AddError(allErrors,el,failMessage);
				else return AVF_Fail(el,failMessage);
			}
			if (minVal!=null && new Date(minVal)>curVal){
				failMessage = niceName+" must be no earlier than "+FormatDateTime(new Date(minVal),"#M#/#D#/#YYYY#")+".";
				if (showAllErrors) AVF_AddError(allErrors,el,failMessage);
				else return AVF_Fail(el,failMessage);
			}
			if (maxVal!=null && new Date(maxVal)<curVal){
				failMessage = niceName+" must be no later than "+FormatDateTime(new Date(maxVal),"#M#/#D#/#YYYY#")+".";
				if (showAllErrors) AVF_AddError(allErrors,el,failMessage);
				else return AVF_Fail(el,failMessage);
			}
		}
	}

	if (showAllErrors && allErrors.firstEl) return AVF_Fail(allErrors.firstEl,allErrors.errorMsg);

	return true;
}

function AVF_RadioSelected(el){
	var f = el.form;
	var els = f.elements[el.name];
	for (var i=0,len=els.length;i<len;i++) if (els[i].checked){
		return true;
	}
	return false;
}

function AVF_AddError(allErrors,el,msg){
	if (el && !allErrors.firstEl) allErrors.firstEl=el;
	allErrors.errorMsg += (allErrors.errorMsg?'\n\n':'')+msg;
}

function AVF_Fail(el,msg){
	if (el){
		try{ el.focus(); } catch(e){};
		try{ el.select(); } catch(e){};
	}
	alert(msg);
	return false;
}

function AVF_Init(){
	for (var i=0,len=document.forms.length;i<len;i++){
		var f = document.forms[i];
		if (!f.getAttribute("autoValidate") || f.getAttribute("autoValidate").toLowerCase()!="true") continue;
		var valFunc = function(event){ if (!AVF_Validate(f)) return PreventDefault(event) };
		AttachEvent(f,'submit',valFunc,true);
	}
}

AttachEvent(window,'load',AVF_Init,true);


/*********************************************************************************
Following are copied from generic_library.js and should be checked for currentness
*********************************************************************************/

function AttachEvent(obj,evt,fnc,useCapture){
	if (!useCapture) useCapture=false;
	if (obj.addEventListener){
		obj.addEventListener(evt,fnc,useCapture);
		return true;
	} else if (obj.attachEvent) return obj.attachEvent("on"+evt,fnc);
	else obj['on'+evt]=fnc;
} 

Date.prototype.customFormat = function(formatString){
	var YYYY,YY,MMMM,MMM,MM,M,DDDD,DDD,DD,D,hhh,hh,h,mm,m,ss,s,ampm,AMPM,dMod,th;
	var dateObject = this;
	YY = ((YYYY=dateObject.getFullYear())+"").substr(2,2);
	MM = (M=dateObject.getMonth()+1)<10?('0'+M):M;
	MMM = (MMMM=["January","February","March","April","May","June","July","August","September","October","November","December"][M-1]).substr(0,3);
	DD = (D=dateObject.getDate())<10?('0'+D):D;
	DDD = (DDDD=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"][dateObject.getDay()]).substr(0,3);
	th=(D>=10&&D<=20)?'th':((dMod=D%10)==1)?'st':(dMod==2)?'nd':(dMod==3)?'rd':'th';
	formatString = formatString.replace("#YYYY#",YYYY).replace("#YY#",YY).replace("#MMMM#",MMMM).replace("#MMM#",MMM).replace("#MM#",MM).replace("#M#",M).replace("#DDDD#",DDDD).replace("#DDD#",DDD).replace("#DD#",DD).replace("#D#",D).replace("#th#",th);

	h=(hhh=dateObject.getHours());
	if (h==0) h=24;
	if (h>12) h-=12;
	hh = h<10?('0'+h):h;
	AMPM=(ampm=hhh<12?'am':'pm').toUpperCase();
	mm=(m=dateObject.getMinutes())<10?('0'+m):m;
	ss=(s=dateObject.getSeconds())<10?('0'+s):s;
	return formatString.replace("#hhh#",hhh).replace("#hh#",hh).replace("#h#",h).replace("#mm#",mm).replace("#m#",m).replace("#ss#",ss).replace("#s#",s).replace("#ampm#",ampm).replace("#AMPM#",AMPM);
}
function FormatDateTime(date,str){ return date?date.customFormat(str):'' }

function PreventDefault(evt){
	if (!evt && window.event) evt=window.event;
	if (evt.preventDefault) evt.preventDefault();
	else evt.returnValue=false;
	return false;
}

function IsHidden(el){
	while (el!=null){
		if ((el.style && (el.style.display=='none' || el.style.visibility=='hidden')) ||	(el.currentStyle && (el.currentStyle.display=='none' || el.currentStyle.visibility=='hidden')))	return true;
		el=el.parentNode;
	}
	return false;
}
