//Terra-Virtua's Fabulous Forms-handling Javascripts
//All contents (C) 2003-2007 Larry Groebe
//     11/27/2007 CSC: strip underscores from fieldnames in error msg
//      9/20/2007 Sanden: corrected validations and ValidateAll
//      2/01/2007 formcalc is here; more validations
//      2/01/2006 and more new validations
//      8/05/2005 more new validations
//      7/26/2005 new validations
//v1.10 6/08/2005 revised include
//v1.00 4/24/2005 adapted from tv_formagic

//globals for forms validation
TV_required=new Array()
TV_required.optional=false
TV_required.message="\nThe '{name}' field is required to complete the form. "
//----
TV_email=new Array()
TV_email.regex= /^([a-zA-Z0-9_.-])+@([a-zA-Z0-9_.-])+\.([a-zA-Z])+([a-zA-Z])+/
TV_email.message= "'{name}' is not a valid email address. Please correct it. "
TV_email.optional=true
//----
TV_email_required=new Array()
TV_email_required.regex= /^([a-zA-Z0-9_.-])+@([a-zA-Z0-9_.-])+\.([a-zA-Z])+([a-zA-Z])+/
TV_email_required.message= "'{name}' is not a valid email address. Please correct it. "
TV_email_required.optional=false
//----
TV_phone=new Array()
TV_phone.regex=/^[\(]?([0-9]{1,4})[-| |\)]+([0-9]{3,4})[-| ]?([0-9]{3,})$/
TV_phone.result='{1}+"-"+{2}+"-"+{3}'
TV_phone.message= "'{name}' must be entered with correctly (including area code). "
TV_phone.optional=true
//----
TV_phone_required=new Array()
TV_phone_required.regex=/^[\(]?([0-9]{1,4})[-| |\)]+([0-9]{3,4})[-| ]?([0-9]{3,})$/
TV_phone_required.result='{1}+"-"+{2}+"-"+{3}'
TV_phone.message= "'{name}' must be entered with correctly (including area code). "
TV_phone_required.optional=false
//----
TV_mmddyyyy=new Array()
TV_mmddyyyy.type="date"
TV_mmddyyyy.regex= /^(\d\d?)\D+(\d\d?)(\D+(\d\d\d?\d?))?$/
TV_mmddyyyy.result='{1}*1+"/" + {2}*1 + "/"+(!{4}?2002:({4}<50?{4}*1+2000:({4}<100?{4}*1+1900:{4})))'
TV_mmddyyyy.internal="new Date({4},{1},{2})"
TV_mmddyyyy.optional=true
//----
TV_mmddyyyy_required=new Array()
TV_mmddyyyy_required.type="date"
TV_mmddyyyy_required.regex= /^(\d\d?)\D+(\d\d?)(\D+(\d\d\d?\d?))?$/
TV_mmddyyyy_required.result='{1}*1+"/" + {2}*1 + "/"+(!{4}?2002:({4}<50?{4}*1+2000:({4}<100?{4}*1+1900:{4})))'
TV_mmddyyyy_required.internal="new Date({4},{1},{2})"
TV_mmddyyyy_required.optional=false
//----
TV_yyyy=new Array()
TV_yyyy.regex= /^(\d\d\d?\d?)$/
TV_yyyy.result='!{1}?2002:({1}<50?{1}*1+2000:({1}<100?{1}*1+1900:{1}))'
TV_yyyy.optional=true
//----
TV_dollar=new Array()
TV_dollar.regex=/^\$?([1-9]{1}[0-9]{0,2}(\,[0-9]{3})*(\.[0-9]{0,2})?|[1-9]{1}[0-9]{0,}(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|(\.[0-9]{1,2})?)$/
TV_dollar.optional=true
//----
TV_dollar_required=new Array()
TV_dollar_required.regex=/^\$?([1-9]{1}[0-9]{0,2}(\,[0-9]{3})*(\.[0-9]{0,2})?|[1-9]{1}[0-9]{0,}(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|(\.[0-9]{1,2})?)$/
TV_dollar_required.optional=false
//----
TV_integer=new Array()
TV_integer.type="int"
TV_integer.regex= /^(\d*)$/
TV_integer.result='{1}'
TV_integer.min=0
TV_integer.max=32000
TV_integer.optional=true

//----
TV_integer_required=new Array()
TV_integer_required.type="int"
TV_integer_required.regex= /^(\d*)$/
TV_integer_required.result='{1}'
TV_integer_required.min=0
TV_integer_required.max=32000
TV_integer_required.optional=false
//----
TV_percent=new Array()
TV_percent.regex= /^(\d\d?\d?)%?$/
TV_percent.result='{1}'
TV_percent.type="int"
TV_percent.min=0
TV_percent.max=100
TV_percent.optional=true
//----
TV_ssnum=new Array()
TV_ssnum.regex=/^([0-9]{3})[-| )]?([0-9]{2})[-| ]?([0-9]{4})$/
TV_ssnum.result='{1}+"-"+{2}+"-"+{3}'
TV_ssnum.optional=true
//----
TV_web=new Array()
TV_web.regex= /^((http:\/\/)?)(.+\..+)$/
TV_web.result='{3}'
TV_web.optional=true
//----
TV_web_required=new Array()
TV_web_required.regex= /^((http:\/\/)?)(.+\..+)$/
TV_web_required.result='{3}'
TV_web_required.optional=false
//----
TV_mmyy=new Array()
TV_mmyy.regex= /^(\d{1,2})\/(\d{2})$/
TV_mmyy.optional= true
TV_mmyy.message= "Please enter only a two-digit month and year separated with a slash for '{name}'."
//----
TV_mmyy_required=new Array()
TV_mmyy_required.regex= /^(\d{1,2})\/(\d{2})$/
TV_mmyy_required.optional= false
TV_mmyy_required.message= "Please enter only a two-digit month and year separated with a slash for '{name}'."
//----
TV_creditcard=new Array()
//TV_creditcard.regex= 	/^\d{4}-?\d{4}-?\d{4}-?\d{3,4}$/
TV_creditcard.regex=/^((4\d{3})|(5[1-5]\d{2})|(6011))-?\d{4}-?\d{4}-?\d{4}|3[4,7]\d{13}$/
TV_creditcard.optional= false
TV_creditcard.message= "Please check for a valid credit card number. Do NOT enter the dashes on American Express cards."
//----
TV_creditcard_required=new Array()
//TV_creditcard.regex= 	/^\d{4}-?\d{4}-?\d{4}-?\d{3,4}$/
TV_creditcard_required.regex=/^((4\d{3})|(5[1-5]\d{2})|(6011))-?\d{4}-?\d{4}-?\d{4}|3[4,7]\d{13}$/
TV_creditcard_required.optional= false
TV_creditcard_required.message= "Please check for a valid credit card number. Do NOT enter the dashes on American Express cards."
//----
TV_height=new Array()
TV_height.regex=/^([0-9])\D*([0-9]{0,2}).*$/
TV_height.result='{1} + "-" + {2}'
TV_height.optional=false
//----
TV_bigbucks=new Array()
TV_bigbucks.regex= /^\$?(([1234567890.]+.*)[Dd]ollars?|([1234567890.]+.*))/
TV_bigbucks.result='"$"+{2}+{3}'
TV_bigbucks.message="Dollar amount in {name} is invalid. "
TV_bigbucks.optional=true


var TV_errormsg=''

//-------------------
//LG 09/20/2006  fieldsets are (unnnamed) form elements!
//LG 10/26/2004  fixes Zope and PHP pseudoname parsing

TV_inUse=false

function TV_validateAll(myform) {
//run through all known fields in the form so that ValidateForm can also work
//but only those fields which match our cookie'd "interests"
  TV_errormsg=''
  cnt=myform.elements.length

//  smatch=document.cookie.match(/interest=(.{3,6})!/)
	pmsg ="xxxx"		//the "previous error message"...so we don't present duplicate errormessages 

  for (x=0; x<cnt;x++) {
	  myfield=myform.elements[x]
	  if (myfield.name!=undefined) {	//skip unnamed elements
		  fieldname = myfield.name.split(":")[0] //get rid of any Zope pseudoname stuff
		  fieldname = fieldname.split("[")[0] //get rid of any PHP pseudoname stuff too
		  if (validation[fieldname]) {
				success=TV_validateItem(myfield, validation[fieldname])
				if (!success) {badfield=myfield}
				}
		  }
	  }  
  if (TV_errormsg>'') {
	  alert ("The form couldn't be submitted due to the following errors:\r " + TV_errormsg + "\n")
	  badfield.focus()
	  return false
 	  }
  return true	
  }


//lg 10/26/2004 correctly reads fieldname
//lg 02/19/2004 now allows passing of a basic validation spec with the fieldname
//single-field wrapper for validateItem, so that validateAll can also work
function TV_validate(thingee,validationspec) {
  if (TV_inUse){return}
  pmsg=''
  TV_inUse=true
  TV_errormsg=''
  fieldname=thingee.name.split(":")[0] //get rid of any PHP pseudoname stuff
  fieldname=fieldname.split("[")[0] //get rid of any Zope pseudoname stuff

  if (!validationspec) {			//we didn't pass a validation spec?
	if (!validation[fieldname]) {	//and there isn't a global one already
		alert ("WARNING: the " + fieldname.replace("_"," ") + " field has no validation template")
		TV_inUse=false
		return false
	 	}
	  if (!TV_validateItem(thingee,validation[fieldname])) {
	  	alert (TV_errormsg+"\n")
  		thingee.focus()
		TV_inUse=false
  		return false
	  } else {
	  	TV_inUse=false
  		return true
		}
	}
  if (!TV_validateItem(thingee,validationspec)) {
	  	alert (TV_errormsg+"\n")
  		thingee.focus()
		TV_inUse=false
  		return false
	  } else {
	  	TV_inUse=false
  		return true
	}
  }

// 11/11/04 LG - handles a single-checkbox-required situation  
//  2/19/04 LG - now pass the validation spec from the calling routine  
//  8/19/03 LG - fixed optional when it's a feildname; also added a matchfield '<>' type which looks to see if the two fields are mutually-exclusively-blank  
//7/15/02 LG MATCHFIELD can be "don't match"; OPTIONAL a field that must also be blank; radio buttons sorta in place 
//6/7/02 LG now with MATCHFIELD for text fields to test against one another
function TV_validateItem(me, vspec) {
  fieldname=me.name.split(":")[0] //get rid of any Zope pseudoname stuff
  fieldname=fieldname.split("[")[0] //get rid of any PHP pseudoname stuff too
  displayname=fieldname.replace("_"," ") //also clean up the underscores
  //error msg depends if ALL we're doing is required field, or OK with a default msg 
  if (typeof vspec=="string") {
 	  vmsg=vspec
  } else {  
	  vmsg= (vspec.message)?vspec.message:"\nThe '{name}' field is incorrect; please fix it and submit again. "
  }

  vmsg=vmsg.replace("{name}",displayname.replace(/_/g," "))
  vmsg=vmsg.replace("{min}",eval(vspec.min))
  vmsg=vmsg.replace("{max}",eval(vspec.max))
  vmsg="\r"+vmsg
  if (vmsg==pmsg) { vmsg=''} else { pmsg=vmsg}		//don't duplicate our previous message
  //decide if we're looking at a SELECT element, RADIO buttons, or something else
  //NOTE WE SHOULD INSTEAD TRY TO GET VALUE out of the DIFFERENT TYPES, THEN PROCESS IT ALIKE 
  myvalue=''
	
  switch (me.type.substring(0,3)) {
  case 'sel': //SELECT STATEMENTS
  case 'rad': // radio buttons
  case 'che': //checkboxes
    if (me.type.substring(0,3)=='sel') {
    		myvalue=me[me.selectedIndex].value
    	} else {
    	itemcount=me.form.elements[me.name].length	//is this, like, a single chackbox?
    	if (itemcount==undefined) {
			if (me.form.elements[me.name].checked) { myvalue= me.form.elements[me.name].value }
		} else { 
			for (z=0; z<itemcount; z++) {
				if (me.form.elements[me.name][z].checked) { myvalue= me.form.elements[me.name][z].value }
				}
			 }
    	}
    	
  	if (vspec.matchfield) {
  	  element2=me.form.elements[vspec.matchfield]
  	  if (element2.type.substring(0,3)=='sel') {
  	  	altvalue=element2.options[element2.selectedIndex].value
  	  	} else {
  	  	altvalue=element2.value }
  	  success = (myvalue==altvalue)
  	  if (vspec.matchtype) {
  	  	if (vspec.matchtype=='!') {success= 1-success}
  	  	}
	  if (!success) {
		TV_errormsg=TV_errormsg + vmsg		//didn't match; don't pass 
		return false
		}
	  }

  	if ((myvalue=='') || (myvalue==null)) {
	  if (vspec.optional) {
 		if (vspec.optional==true) {return true}	//that's OK...we're allowed to be blank.
		element2=me.form.elements[vspec.optional]
		vmsg=vmsg.replace("{optional}",vspec.optional)
	  	if (element2.type.substring(0,3)=='sel') {
  	  		altvalue=element2.options[element2.selectedIndex].value
 	 	  	} else {
  		  	altvalue=element2.value }
		if (altvalue>'') {
			TV_errormsg=TV_errormsg + vmsg 
			return false}	//our trigger value isn't blank but we are - bad news
		}
	  }

	tval=0
	for (i=0; i<me.length; i++) {
		tval = tval + (me.options[i].selected && me.options[i].value>'') }
	if (!(vspec.min) && !(vspec.max)) { 				//neither min nor max?then simply  required 
		if (myvalue=='') {
			TV_errormsg=TV_errormsg + vmsg 			//it didn't pass 
			return false
			}
		return true
		}
	tmin = (vspec.min)? eval(vspec.min): 0 
	tmax = (vspec.max)? eval(vspec.max): me.length
//	tmin = (vspec.min)? tmin : (vspec.max) ? tmin: 1	//neither min nor max?then required 
	if ((tval>tmax)||(tval<tmin)) {
		TV_errormsg=TV_errormsg + vmsg 			//it didn't pass 
		return false
		}
	return true
    break
  	
  default:  //TEXT BOXES & TEXTAREAS
	//should we match another field?

  	if (vspec.matchfield) {
  	  element2=me.form.elements[vspec.matchfield]
  	  if (element2.type.substring(0,3)=='sel') {
  	  	altvalue=element2.options[element2.selectedIndex].value
  	  	} else {
  	  	altvalue=element2.value }
  	  success = (me.value==altvalue)
  	  if (vspec.matchtype) {
  	  	if (vspec.matchtype=='!') {success= 1-success}
  	  	if (vspec.matchtype=='<>') {success= !(altvalue>"")&&( me.value>"")}
  	  	}
	  if (!success) {
		TV_errormsg=TV_errormsg + vmsg 		//didn't match; don't pass 
		return false
		}
	  }

  	// are we empty data?
	if (me.value=='') {
		if (vspec.optional) {
//	  alert ("testing optional on '" + fieldname)
			if (vspec.optional==true) {return true}	//that's OK...we're allowed to be blank and we are.
			element2=me.form.elements[vspec.optional]  //only allowedto be blank if other field is too.
		    vmsg=vmsg.replace("{optional}",vspec.optional) //get ready; tell the world the other field name
	  		if (element2.type.substring(0,3)=='sel') {  //get the other field's value
  	  			altvalue=element2.options[element2.selectedIndex].value
 	 	  	} else {
  		  		altvalue=element2.value
  		  	}
//		  alert ('altvalue field is  '+ element2.name)
//		  alert ('altvalue value is  '+ altvalue)

			if (altvalue>'') {
				TV_errormsg=TV_errormsg + vmsg
				return false //our trigger value isn't blank but we are - bad news
			} else {
				return true
			}
	  	} else { 
			TV_errormsg=TV_errormsg + vmsg 		//OPTIONAL flag isn't there; we must be filled in so don't pass 
			return false
		}
	}

    if (!vspec.regex) {return true}			//if no regex exists, we're done....
  	result=vspec.regex.exec(me.value)			//if regex exists, validate it
  	if (result==null) {
		TV_errormsg=TV_errormsg + vmsg			//it didn't pass 
		return false
		}
	
	  //it passed regex at least; reformat it and redisplay it 
  	if (vspec.result) {
		  tmp=vspec.result
		  me.value=eval(tmp.replace(/\{/g,"result[").replace(/\}/g,"]"))
		  }
  	  
  	//now, do we have any min/max testing?
 	 if (vspec.min||vspec.max) {
		//first we extract the whole field or our submatches from our (cleaned-up) datafield
		result= (vspec.result) ? vspec.regex.exec(me.value): result=me.value

		//convert it/them to an actual value -- according to internal model if there is one.
		tval=eval( vspec.internal? vspec.internal.replace(/\{/g,"result[").replace(/\}/g,"]") : me.value)

		//if we could detect a failure here, we could fail validation 
		//if no min or max specified, create something to test that always passes
		tmin = (vspec.min)? eval(vspec.min): tval - 1 
		tmax = (vspec.max)? eval(vspec.max): tval + 1 
		if ((tval>tmax)||(tval<tmin)) {
			TV_errormsg=TV_errormsg + vmsg			//it didn't pass 
			return false
			}
		}
		return true
	}
}

//------------------
//v1.32 1/24/07 LG the return, as part of eklipse 
//v1.31 7/28/04 LG handles longer formulaes more elegantly.
//v1.30 7/08/04 LG handles more complex fieldnames
//v1.20 2/19/02 LG pass in optional overriding formula or allow default "formulas"
//v1.10 3/21/01 LG formulas can get too long, so FIRST split, THEN parse
//v1.0a 1/24/01 LG

function TV_calcForm(ftext) {
	mf=document.forms[0]										//define the forms shortname
	if (typeof(mf.formulas)!='object') {return} 	//anything at all?
	clist=mf.formulas.value.split(";")			//separate out multiple 
	for (x = 0; x < clist.length; x++) {						//look at each line
		calc=clist[x]
		eval(calc)
		}
	}

function pf(x) {	//short version of Parsefloat makes js run longer formulaes
	if (typeof(x)!='object') {return 0} 	//does it exist?
//	alert(x.name + " typeof:" + typeof(x))
//	alert(x.name + " type:" + x.type)
//	alert(x.name + " checked:" +x.checked)
//	alert(x.name + " value:" +x.value)
//	alert(x.name + " selected:" +x.selected)
	if (x.type=='radio') {
		return parseFloat(x.checked * 1)
	} else {
		return parseFloat(x.value * 1)
		}
	}
