// formcheck.js
// a group of form-checking routines 
// for use on *.bzzagent.com
// adapted by Greg Bowne


// is the item an array (used for single radio/check
function isArray(obj){
	return(typeof(obj.length)=="undefined")?false:true;
}

// is checkbox or radio checked? 
function isChecked(s) {
	if (isArray(s)) {
		for (i=0; i< s.length; i++) {
			if (s[i].checked==true) { return true; }
		}
	} else {
		if (s.checked==true) { return true; }
	}
	return false;
}

// is item in option list selected? 
function isSelected(s) {
	if ((s.options[0].value != "") && (s.selectedIndex > -1)) { return true; }
	else if (s.selectedIndex > 0) { return true; }
	return false;
}

// Is the string non-existent (null) or is its length equal to zero?
function isEmpty(s)
{   return ((s == null) || (s.length == 0))
}

var USStateCodeDelimiter = "|";
var USStateCodes = "AL|AK|AS|AZ|AR|CA|CO|CT|DE|DC|FM|FL|GA|GU|HI|ID|IL|IN|IA|KS|KY|LA|ME|MH|MD|MA|MI|MN|MS|MO|MT|NE|NV|NH|NJ|NM|NY|NC|ND|MP|OH|OK|OR|PW|PA|PR|RI|SC|SD|TN|TX|UT|VT|VI|VA|WA|WV|WI|WY|AA|AE|AP";

function isState (s)
// Is the string a US state abbreviation(CT, VT, az)?
{       
    upState = s.toUpperCase();
    return ( (USStateCodes.indexOf(upState) != -1) &&
             (upState.indexOf(USStateCodeDelimiter) == -1) )
}

var ProvinceCodes = "AB|BC|MB|NB|NL|NT|NS|NU|ON|PE|PQ|QC|SK|YT";
function isProvince (s)
// Is the string a Canadian abbreviation(ON, YT, ab)?
{       
    upState = s.toUpperCase();
    return ( (ProvinceCodes.indexOf(upState) != -1) &&
             (upState.indexOf(USStateCodeDelimiter) == -1) )
}

var ZIPCodeDelimiters = "- ";
function isZIPCode (s)
// Is the string a valid zipcode, minus the symbols (12345, 123412345)?
{  
   return (isInteger(s) && 
            ((s.length == 5) ||
             (s.length == 9)))
}

// Convert a string to zip code format (12345 stays the same, 123456789 becomes 12345-6789)
function reformatZIPCode (ZIPString)
{   if (ZIPString.length == 5) return ZIPString;
    else return (reformat (ZIPString, "", 5, "-", 4));
}

// Is a given field a valid zipcode format?
// Reformat it if it's OK.
// If an alert is requested and the field is invalid then put up an alert.
function checkZIPCode (theField)
{
  var normalizedZIP = stripCharsInBag(theField.value, ZIPCodeDelimiters);
  if (!isZIPCode(normalizedZIP)) { return false;
  } else {
    theField.value = reformatZIPCode(normalizedZIP);
    return true;
  }
}

// Is the string a valid Canadian Postal Code, A1B2C3?
var CanadaFormat = /^\s*[a-ceghj-npr-tvxy]\d[a-z](\s)?\d[a-z]\d\s*$/i;
function isCanadaPostalCode(s) {
	if (!s.match(CanadaFormat)) { return false; }
	return true;
}


function checkCanadaPostalCode (theField, isAlert)
{
  var normalizedCPC = stripCharsInBag(theField.value, ZIPCodeDelimiters);
  if (!isCanadaPostalCode(normalizedCPC)) { return false
  } else {
    theField.value = reformat(normalizedCPC.toUpperCase(),"",3," ",3);
    return true;
  }
}

// Is the string a valid UK Postal Code, A1B2C3?
var UKPostalFormat = /^[A-Z]{1,2}[0-9R][0-9A-Z]?[0-9][ABD-HJLNP-UW-Z]{2}$/i;
function isUKPostalCode(s) {
	if (!s.match(UKPostalFormat)) { return false; }
	return true;
}

function checkUKPostalCode (theField, isAlert)
{
  var normalizedUKP = stripCharsInBag(theField.value, ZIPCodeDelimiters).toUpperCase();
  if (!isUKPostalCode(normalizedUKP)) { return false
  } else {
  	len = normalizedUKP.length
  	incode = normalizedUKP.substr(len-3,3); // last 3 characters
	outcode = normalizedUKP.substr(0,normalizedUKP.length-3); // first n characters
    theField.value = outcode+" "+incode;
    return true;
  }
}

var emailFormat = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,6})$/;
//list of TLDs garnered from http://en.wikipedia.org/wiki/List_of_Internet_top-level_domains

function isEmail (s)
// Is the string in a valid email address format (x@y.z)?
{ 
	if (!s.match(emailFormat)) { // now see if they've got something else going on
		return false; 
	} else {
		return true; 
	}
	// keep old way of doing just in case!
    var i = 1;
    var sLength = s.length;
	while ((i < sLength) && (s.charAt(i) != "@")) { 
		i++
 	}
    if ((i >= sLength) || (s.charAt(i) != "@")){
		return false;
	} else i += 2;
    while ((i < sLength) && (s.charAt(i) != ".")) { 
		i++
    }
    if ((i >= sLength - 1) || (s.charAt(i) != ".")) {
		return false;
	} else {
		return true;
	}
}

function cleanEmail(s) { // for emails like Greg Bowne <greg@bzzagent.com> returns just greg@bzzagent.com
	if(s.match(/<(mailto:)?(.*)>/)) {
	doublecheck = s.match(/<(mailto:)?(.*)>/);
	//alert(doublecheck[0]);
	s =doublecheck[2];
	//alert(s);
	}
	return s;
}

function isURL (s)
// Is the string in a valid url (http(s)://)?
{ var site = s.substring(0, 8);
	if ((site.substring(0,7) != "http://") && (site != "https://") ) {
	return false;
	} else {
	return true;
	}
}

var digits = "0123456789";
var phoneNumberDelimiters = "()-. ";
var validWorldPhoneChars = digits + phoneNumberDelimiters + "+" + "/";

function allCharsInBag (s, bag)
{   
	flag=true;
	for (i = 0; i < s.length; i++)
	{
		flag=flag&&(bag.indexOf(s.charAt(i)) != -1);
	}
    return (flag);
}

function isDigit (c)
{   return ((c >= "0") && (c <= "9"))
}

function isLetter (c)
{   return ( ((c >= "a") && (c <= "z")) || ((c >= "A") && (c <= "Z")) )
}

function isInteger (s)
{   var i;
    
	for (i = 0; i < s.length; i++)
    {   
        var c = s.charAt(i);
        if (!isDigit(c)) return false;
    }
        return true;
}

function noShout (s) // checks to make sure the text isn't all caps
{
	if (s.length > 3 && s.match(/[A-Z]/i) && !s.match(/\d/)) { // make sure there are letters. if letters and numbers, okay.
		uc = s.toUpperCase();
		if (s == uc) {
			return false;		
		}	
	}
	return true;
}

function stripCharsNotInBag (s, bag)
{   var i;
    var returnString = "";
        
    for (i = 0; i < s.length; i++)
    {   
        var c = s.charAt(i);
        if (bag.indexOf(c) != -1) returnString += c;
    }
    return returnString;
}
	
function stripCharsInBag (s, bag)
{   var i;
    var returnString = "";
        
    for (i = 0; i < s.length; i++)
    {   
        var c = s.charAt(i);
        if (bag.indexOf(c) == -1) returnString += c;
    }
    return returnString;
}

// Is the field a valid Credit Card number following the Luhn formula?
function luhnCheck(s) {
   var CardNumber = stripCharsNotInBag(s,digits)	
   var no_digit = CardNumber.length;
   var oddoeven = no_digit & 1;
   var sum = 0;

   for (var count = 0; count < no_digit; count++) {
      var digit = parseInt(CardNumber.charAt(count));
      if (!((count & 1) ^ oddoeven)) {
         digit *= 2;
         if (digit > 9)
         digit -= 9;
      }
      sum += digit;
   }
   //alert(sum);
   if (sum % 10 == 0)
   return true;
   else 
   return false;
}

function isCvv2 (s)
// Is the string a valid Card Verification number, i.e. 3 or 4 digits?
{  
   return (isInteger(s) && 
            ((s.length == 3) ||
             (s.length == 4)))
}

function checkCredit(theField, isAlert) {
var cleanedCard = stripCharsNotInBag(theField.value, digits);
  if (!luhnCheck(cleanedCard)) { return false;
  } else {
    theField.value = cleanedCard;
    return true;
  }
}

// is the card a valid Nectar Card (UK)
//Data - contains the significant 11 digits (i.e. does not include the UK IIN), plus a leading character of '3'. 
//This data is displayed in human readable format beneath the code. 
//The Nectar (luhn-10) check can be performed on the card number in this data segment by 
//dropping the leading '3' and adding in the IIN prefix of '98263000'
function NectarCard(s) {
	len = s.length;
  	cardtest = '98263000' + s.substr(len-11,11); // last 11 characters
	return luhnCheck(cardtest);
}

// is the field a valid US/North-American phone number?
function isUSPhone (s)
{   
    return (isInteger(s) && s.length ==10)
}
function reformat (s)
{   var arg;
    var sPos = 0;
    var resultString = "";
    for (var i = 1; i < reformat.arguments.length; i++) {
       arg = reformat.arguments[i];
       if (i % 2 == 1) resultString += arg;
       else {
           resultString += s.substring(sPos, sPos + arg);
           sPos += arg;
       }
    }
    return resultString;
}
function reformatUSPhone (USPhone)
{ 
	 return (reformat (USPhone, "(",3, ") ", 3, "-", 4));
}

// Is a given field a valid US phone number format?
// Reformat it if it's OK.
function checkUSPhone (theField, isAlert)
{   
  var normalizedPhone = stripCharsInBag(theField.value, phoneNumberDelimiters);
  //alert(normalizedPhone);
  if (!isUSPhone(normalizedPhone)) { return false;
  } else {
    theField.value = reformatUSPhone(normalizedPhone)
    return true;
  }
}

var UKPhoneFormat = /^(\+?[1-9][0-9]{0,3})?([(/ ]?0[0-9]+[)/ ]?)([0-9 -]+)$/; // country code optional
// if this doesnt' work, we might try this: http://regexlib.com/REDetails.aspx?regexp_id=684

function isUKPhone (s)
{
	if (!s.match(UKPhoneFormat)) { return false; }
	if (s.length <= 9) { return false; }
	return true;
}

function reformatUKPhone (UKPhone)
{ 
	var sections = UKPhone.match(UKPhoneFormat);
	if (sections !=  null) {
		if (sections[1] == '' || undefined === sections[1] || null===sections[1]) { sections[1] = ''; }
		else {
			sections[1] = "+" + sections[1].match(/[0-9]+/)+"/";
		}
		sections[3] = stripCharsInBag(sections[3]," -");
		if (sections[3].length >=7) { // reformat to XXX[X] XXXX
			len = sections[3].length;
			part2 = sections[3].substr(len-4); // last 4 digits
			part1 = sections[3].substr(0,len-4); // first n characters
		    sections[3] = part1+" "+part2;
		} else {  // reformat to XXX XXX
			len = sections[3].length;
			part2 = sections[3].substr(len-3); // last 3 digits
			part1 = sections[3].substr(0,len-3); // first n characters
		    sections[3] = part1+" "+part2;
		}
		newformat = sections[1] + sections[2].match(/[0-9]+/) + " "+ sections[3];
	}
	return (newformat);
}


// Is a given field a valid UK phone number format?
// Reformat it if it's OK.
function checkUKPhone (theField, isAlert)
{   
  if (!isUKPhone(theField.value)) { return false;
  } else {
    theField.value = reformatUKPhone(theField.value)
    return true;
  }
}

//var intPhoneFormat = /^(\+[0-9]{1,3})[(/ ]?([0-9])+[)/ ]?([0-9- ]+)$/; // country code required
var intPhoneFormat = /^((\+\d{1,3}(-| )?\(?\d\)?(-| )?\d{1,3})|(\(?\d{2,3}\)?))(-| )?(\d{3,4})(-| )?(\d{4})(( x| ext)\d{1,5}){0,1}$/;
function isInternationalPhone (s) 
// Do all the characters in the string fit in the bag of valid world phone number characters?
{   
    return (allCharsInBag(s, validWorldPhoneChars));
}
function checkInternationalPhone (theField, isAlert)
{   
  if (!isInternationalPhone(theField))
    {
      if (isAlert) warnInvalid (theField, iWorldPhone);
      return false;
    }
    else
    {
      return true;
    }
}

// check to see if item is a floating
function checkMoney(theField) {
	num = theField.value.toString().replace(/\$|\,/g,'');
	if(isNaN(num)) { return false; }
	sign = (num == (num = Math.abs(num)));
	num = Math.floor(num*100+0.50000000001);
	cents = num%100;
	num = Math.floor(num/100).toString();
	if(cents<10)
	cents = "0" + cents;
	for (var i = 0; i < Math.floor((num.length-(1+i))/3); i++)
	num = num.substring(0,num.length-(4*i+3))+','+
	num.substring(num.length-(4*i+3));
	theField.value = (((sign)?'':'-') + num + '.' + cents);
	return true;
}

var defaultEmptyOK = false;
// *******************************************************
// Does the string represent a valid signed integer (+7, -111)?
function isSignedInteger (s)
{   if (isEmpty(s)) 
       if (isSignedInteger.arguments.length == 1) return defaultEmptyOK;
       else return (isSignedInteger.arguments[1] == true);
    else {
        var startPos = 0;
        var secondArg = defaultEmptyOK;
        if (isSignedInteger.arguments.length > 1)
            secondArg = isSignedInteger.arguments[1];
                if ( (s.charAt(0) == "-") || (s.charAt(0) == "+") )
           startPos = 1;    
        return (isInteger(s.substring(startPos, s.length), secondArg))
    }
}
// *******************************************************
// Does the string represent a positive integer (7, 111, +9)?
function isPositiveInteger (s)
{   var secondArg = defaultEmptyOK;
    if (isPositiveInteger.arguments.length > 1)
        secondArg = isPositiveInteger.arguments[1];
                        
    return (isSignedInteger(s, secondArg)
         && ( (isEmpty(s) && secondArg)  || (parseInt (s, 10) > 0) ) );
}
// *******************************************************
// Does the string represent a non-negative integer (7, 111, +9, 0)?
function isNonnegativeInteger (s)
{   var secondArg = defaultEmptyOK;
    if (isNonnegativeInteger.arguments.length > 1)
        secondArg = isNonnegativeInteger.arguments[1];
                        
    return (isSignedInteger(s, secondArg)
         && ( (isEmpty(s) && secondArg)  || (parseInt (s, 10) >= 0) ) );
}
// *******************************************************
// Does the string represent a negative integer (-9)?
function isNegativeInteger (s)
{   var secondArg = defaultEmptyOK;
    if (isNegativeInteger.arguments.length > 1)
        secondArg = isNegativeInteger.arguments[1];
                        
    return (isSignedInteger(s, secondArg)
         && ( (isEmpty(s) && secondArg)  || (parseInt (s, 10) < 0) ) );
}
// *******************************************************
// Does the string represent a non-positive integer (-9, 0)?
function isNonpositiveInteger (s)
{   var secondArg = defaultEmptyOK;
    if (isNonpositiveInteger.arguments.length > 1)
        secondArg = isNonpositiveInteger.arguments[1];
                        
    return (isSignedInteger(s, secondArg)
         && ( (isEmpty(s) && secondArg)  || (parseInt (s, 10) <= 0) ) );
}
// *******************************************************
function isYear (s)
// Is the string a valid positive year (43, 1911, 2011)?
{   if (isEmpty(s)) 
       if (isYear.arguments.length == 1) return defaultEmptyOK;
       else return (isYear.arguments[1] == true);
    if (!isNonnegativeInteger(s)) return false;
    return (s.length == 4);
}
// *******************************************************
// Is the integer in the range a to b?
function isIntegerInRange (s, a, b)
{   if (isEmpty(s)) 
       if (isIntegerInRange.arguments.length == 1) return defaultEmptyOK;
       else return (isIntegerInRange.arguments[1] == true);
            if (!isInteger(s, false)) return false;
                    var num = parseInt (s, 10);
    return ((num >= a) && (num <= b));
}

var decimalPointDelimiter=".";
// Is the number a float?
function isFloat (s)
{   var i;
    var seenDecimalPoint = false;
    if (isEmpty(s)) 
       if (isFloat.arguments.length == 1) return defaultEmptyOK;
       else return (isFloat.arguments[1] == true);
    if (s == decimalPointDelimiter) return false;
            
    for (i = 0; i < s.length; i++)
    {   
                var c = s.charAt(i);
        if ((c == '.') && !seenDecimalPoint) seenDecimalPoint = true;
        else if (!isDigit(c)) return false;
    }
        return true;
}
// *******************************************************
// Does the string represent a signed floating-point number (-9.1, +0.5)?
function isSignedFloat (s)
{   if (isEmpty(s)) 
       if (isSignedFloat.arguments.length == 1) return defaultEmptyOK;
       else return (isSignedFloat.arguments[1] == true);
    else {
        var startPos = 0;
        var secondArg = defaultEmptyOK;
        if (isSignedFloat.arguments.length > 1)
            secondArg = isSignedFloat.arguments[1];
                if ( (s.charAt(0) == "-") || (s.charAt(0) == "+") )
           startPos = 1;    
        return (isFloat(s.substring(startPos, s.length), secondArg))
    }
}

// *******************************************************
// Is the float in the range a to b?
function isFloatInRange (s, a, b)
{   if (isEmpty(s)) 
       if (isFloatInRange.arguments.length == 1) return defaultEmptyOK;
       else return (isFloatInRange.arguments[1] == true);
            if (!isFloat(s, false)) return false;
                    var num = parseFloat (s);
    return ((num >= a) && (num <= b));
}

// if the date isn't in SQL date format, then try to fix it.
function checkSQLDate(fieldName) {
	var tbd = /tbd/i;
	var sqlDate = /(\d+){4,4}-(\d+){2,2}-(\d+){2,2}/;
	if (fieldName.value.match(sqlDate)) {
		return true;
	}
	if (fieldName.value.match(tbd)) {
		fieldName.value="TBD";
		return true;
	}
	if (fieldName.value.match(/\./)) {
		fieldName.value = fieldName.value.replace(/\./g,"/");
	}
	dateInfo = Date.parse(fieldName.value);
	var d = new Date(dateInfo);
	var curr_date = d.getDate();
	if (isNaN(curr_date)) { return false; }
	var curr_month = d.getMonth();
	curr_month++;
	var curr_year = d.getFullYear();
	if (curr_year < 2000) { curr_year += 100; }
	fieldName.value = (curr_year+"-");
	if (curr_month < 10) {fieldName.value += "0"; }
	fieldName.value += (curr_month + "-");
	if (curr_date < 10) {fieldName.value += "0"; }
	fieldName.value += (curr_date);
	return true;
}

// Make a blank array of size n (1..n), populated with zeroes
function makeArray(n) {
   for (var i = 1; i <= n; i++) {
      this[i] = 0;
   } 
   return this;
}

// Make an array called daysInMonth
var daysInMonth = makeArray(12);
daysInMonth[1] = 31;
daysInMonth[2] = 29;
daysInMonth[3] = 31;
daysInMonth[4] = 30;
daysInMonth[5] = 31;
daysInMonth[6] = 30;
daysInMonth[7] = 31;
daysInMonth[8] = 31;
daysInMonth[9] = 30;
daysInMonth[10] = 31;
daysInMonth[11] = 30;
daysInMonth[12] = 31;
// *******************************************************
function isMonth (s)
// Is the string a month value (1..12)?
{   
    return isIntegerInRange (s, 1, 12);
}
// *******************************************************
// Is the string a day of the month (1..31)?
function isDay (s)
{    
    return isIntegerInRange (s, 1, 31);
}
// *******************************************************
// Given a year, return the number of days February will have.
function daysInFebruary (year)
{           return (  ((year % 4 == 0) && ( (!(year % 100 == 0)) || (year % 400 == 0) ) ) ? 29 : 28 );
}
// *******************************************************
// Given year, month and day strings (1917, 11, 4) are they valid dates?
function isDate (year, month, day)
{       if (! (isYear(year, false) && isMonth(month, false) && isDay(day, false))) return false;
            var intYear = parseInt(year);
    var imonth = parseInt(month);
    var intDay = parseInt(day);
        if (intDay > daysInMonth[imonth]) return false; 
    if ((imonth == 2) && (intDay > daysInFebruary(intYear))) return false;
    return true;
}

//*****************************************************
//checks forms dynamically
// requires class field to be filled with the following data
// type [required] [Field Name in Text] [min value] [max value]
// email required Contact.Email
// money
// required
// integer required
// ZIP optional 'ZIP Code'
// integer
function checkForm(thisForm) {
	var undefined;
	var extraMessage = "";
	if (arguments[1] != undefined) {
		extraMessage = arguments[1] + "\n";
	} 
	for ( z = 0 ; z < thisForm.elements.length; z++) {
		var iclass = thisForm.elements[z].className;
		var iname = thisForm.elements[z].name;
		var iID = thisForm.elements[z].id;
		var itype = 'text';
		var required = false;
		var ifield;
	if (iclass.length ==0) { // no class info means no checking;
			//alert("noclass z='"+z+"' class='"+iclass+"' name='"+iname+"' id= '"+iID+"'");
			continue; 
		} else {
			// decide what reference to use. if the 'name' begins with # and the id is there, use it.
			//alert("z='"+z+"' class='"+iclass+"' name='"+iname+"' id= '"+iID+"'");
			if (!iname.match(/^\d/)) {
				ifield = thisForm[iname];
				//alert("Using Name="+iname);
			} else if (!iID.match(/^\d/)) {
				ifield = thisForm[iID];
				//alert ("Using ID "+ iID+" name="+iname);
			} else {
				//alert ("Field not addressable id="+iID+" name="+iname);
				continue;
			}
			var check_info = iclass.split(' ');
			if (check_info[1] == 'required') { required = true; }
			if (check_info[0] == 'required') { 
				required = true; 
				itype = thisForm.elements[z].type;
			} else {
				itype = check_info[0]; 
			}
			if (check_info[2] != undefined && check_info[2] != '') { ititle = check_info[2].replace(/\./g, ' '); } // change dots to spaces
			else { ititle = false; }
			//min and max are used for numbers and for stringlength
			rangecheck = false;
			if (check_info[3] != undefined && check_info[3] != '') { imin = 1*check_info[3]; } 
			else { imin = undefined; }
			if (check_info[4] != undefined && check_info[4] != '') { imax = 1*check_info[4]; }
			else { imax = undefined; }
			if (imin != undefined  && imin != false) { rangecheck=true;}
		}
		// first make sure not empty, checked, etc.
		valid = true;
		focusable = true;
		if (required) {
			switch(itype) {
				case "hidden" : if (isEmpty(ifield.value)) { valid = false; focusable = false;}
								break;
				case "checkbox" :
				case "checkbox-matrix" :
				case "radio"    :
				case "radio-matrix" : if (!isChecked(ifield)) { valid = false; focusable = false;}
								break
				case "select-multiple" :				
				case "select-one" : if (!isSelected(ifield)) { valid = false;}
								break
				case "textarea" : 
				case "password" :
				case "TEXT"		: // allows for allcaps
				case "text"		: if (isEmpty(ifield.value)) { valid = false;}
								break
				default 	    : if (isEmpty(ifield.value)) { valid = false;}	
			}
		}	
		
		if (!valid) { 
			if (ititle != '') { msg = extraMessage+ititle+' '+locale.get("formcheck_maynotbeblank"); } 
			else { msg = extraMessage+locale.get("formcheck_requiredblank"); }
			if (itype == 'radio' || itype == 'checkbox' || itype.match(/select/)) { 
				msg = extraMessage+locale.get("formcheck_requiredblank_radio"); 
				if (ititle != '') { msg= extraMessage+locale.get("formcheck_requiredblank_named")+' '+ititle; }
			}
			if (itype == 'radio-matrix' || itype == 'checkbox-matrix') { 
				msg = extraMessage+locale.get("formcheck_requiredblank_matrix"); 
				if (ititle != '') { msg= extraMessage+locale.get("formcheck_requiredblank_matrix_named")+' '+ititle; }
			}
			msg = msg.replace(/<br(\/?)>/g,"\n");
			if (focusable) {alert(msg); ifield.focus(); }
			else { alert(msg); 
				if (isArray(ifield)) { ifield[0].focus(); } // if there's only one, it's not an array.
				else { ifield.focus(); }
			}
			scrollBy(0,-45);
			return false;
		}
		// then validate on type
		switch(itype) {
			case "textarea":
			case "text": if (!isEmpty(ifield.value) && !noShout(ifield.value)) {
							valid=false;
							msg2 = locale.get("formcheck_text_mixedcase");
							}
			case "TEXT": if (rangecheck && !isNaN(imin)) {
								if (!isNaN(imax) && (imax > imin)) {
									if ((ifield.value.length > imax) || (ifield.value.length < imin)) {
										valid = false;
										msg2 = locale.get("formcheck_range_between") + imin + locale.get("formcheck_range_and") + imax + locale.get("formcheck_range_characters");
									}
								} else {
									if (ifield.value.length < imin) {
										valid = false;
										msg2 = locale.get("formcheck_range_atleast") + imin + locale.get("formcheck_range_characters");
									}
								}
							}
							break;
			case "integer" : if (!isEmpty(ifield.value) && !isInteger(ifield.value)) {
							valid = false;
							msg2 = locale.get("formcheck_integer"); 
							break; }
							if (rangecheck && !isNaN(imin)) {
								if (!isNaN(imax) && imax > imin) {
									if (ifield.value > imax || ifield.value < imin) {
										valid = false;
										msg2 = locale.get("formcheck_range_between") + imin + locale.get("formcheck_range_and") + imax;
									}
								} else {
									if (ifield.value < imin) {
										valid = false;
										msg2 = locale.get("formcheck_range_greater") + imin;
									}
								}
							}
							break; 
			case "ZIP"     :
			case "zip" 	   : if (!isEmpty(ifield.value) && !checkZIPCode(ifield)) {
							valid = false;
							msg2 = locale.get("formcheck_zip"); }
							break; 
			case "canada"  : if (!isEmpty(ifield.value) && !checkCanadaPostalCode(ifield)) {
							valid = false;
							msg2 = locale.get("formcheck_canadapostal"); }
							break; 
			case "postal" : if (!isEmpty(ifield.value) && !checkCanadaPostalCode(ifield) && !checkZIPCode(ifield)) {
							valid = false;
							msg2 = locale.get("formcheck_zip_or_canada"); }
							break; 
			case "ukpostal" :
			case "ukpost"  : if (!isEmpty(ifield.value) && !checkUKPostalCode(ifield)) {
							valid = false;
							msg2 = locale.get("formcheck_ukpostal");}
							break; 
			case "state" :  if (!isEmpty(ifield.value) && !isState(ifield.value)) {
							valid = false;
							msg2 = locale.get("formcheck_usstate"); }
							break;
			case "province" :  if (!isEmpty(ifield.value) && !isProvince(ifield.value)) {
							valid = false;
							msg2 = locale.get("formcheck_province"); }
							break;  
			case "stateprov" : if (!isEmpty(ifield.value) && !isState(ifield.value) && !isProvince(ifield.value)) {
							valid = false;
							msg2 = locale.get("formcheck_usstate_or_province"); }
							break;
			case "e-mail":				
			case "email" : // first clear out any extraneous crap
							ifield.value=cleanEmail(ifield.value);
							if (!isEmpty(ifield.value) && !isEmail(ifield.value)) {
							valid = false;
							msg2 = locale.get("formcheck_email"); }
							break; 
			case "URL":	
			case "url" : if (!isEmpty(ifield.value) && !isURL(ifield.value)) {
							valid = false;
							msg2 = locale.get("formcheck_url"); }
							break; 
			case "phone" : if (!isEmpty(ifield.value) && !checkUSPhone(ifield)) {
							valid = false;
							msg2 = locale.get("formcheck_phone"); } 
							break; 
			case "ukphone" : if (!isEmpty(ifield.value) && !checkUKPhone(ifield)) {
							valid = false;
							msg2 = locale.get("formcheck_phone_uk"); } 
							break; 
			case "intphone" : if (!isEmpty(ifield.value) && !isInternationalPhone(ifield.value)) {
							valid = false;
							msg2 = locale.get("formcheck_phone_int"); } 
							break; 
			case "date" :  if (!isEmpty(ifield.value) && !checkSQLDate(ifield)) {
							valid = false;
							msg2 = locale.get("formcheck_date"); }
							break;
			case "money" : if (!isEmpty(ifield.value) && !checkMoney(ifield)) {
							valid = false;
							msg2 = locale.get("formcheck_money"); 
							break; }
							if (!isNaN(imin)) {
								if (!isNaN(imax) && imax > imin) {
									if (ifield.value > imax || ifield.value < imin) {
										valid = false;
										msg2 = locale.get("formcheck_range_between") + imin + locale.get("formcheck_range_and") + imax;
									}
								} else {
									if (ifield.value < imin) {
										valid = false;
										msg2 = locale.get("formcheck_range_greater") + imin;
									}
								}
							}
							break;
			case "number" : if (!isEmpty(ifield.value) && !(isFloat(ifield.value) || isInteger(ifield.value))) {
							valid = false;
							msg2 = locale.get("formcheck_number"); }
							break;
							// this is for the UK's Nectar program, a special type of credit card. 
			case "Nectar" : if (!isEmpty(ifield.value) && !NectarCard(ifield.value)) { 
							valid = false;
							msg2 = locale.get("formcheck_nectar"); }
							break; 				
			case "credit" : // luhn is a standard mathematical formula for credit cards involving a check-digit.
			case "luhn"   : if (!isEmpty(ifield.value) && !checkCredit(ifield)) { 
							valid = false;
							msg2 = locale.get("formcheck_credit"); }
							break; 
			case "cvv2"  :  if (!isEmpty(ifield.value) && !isCvv2(ifield.value)) {
							valid = false;
							msg2 = locale.get("formcheck_credit_verify"); }
							break; 
			//default 	
		}	
		if (!valid) { 
			if (ititle) { msg = extraMessage+ititle+" "+msg2; } 
			else { msg = extraMessage+locale.get("formcheck_thisfield") + msg2; }
			msg = msg.replace(/<br(\/?)>/g,"\n");
			alert(msg);
			if (focusable) { ifield.focus(); }
			return false;
		} 	
	}
	return true;
}
