//////////////////////////////////////////////////////////////////////////////////////////////////////
// FIELD VALIDATION FUNCTIONS
//////////////////////////////////////////////////////////////////////////////////////////////////////

// ValidateOnFly - validates this field then sets all classes as necessary
TigerField.prototype.ValidateOnFly = function () {
//	this.parent.DataChanged = true;
	ValidResults = this.Validate(false);
	this.SetClasses(); 
};


// Validate - Performs validation, and sets & returns an issue result and message
TigerField.prototype.Validate = function (lFullForm) {
	var nIssueLevel = 0;
	var nIssueLevelForMissingData = 3;
	nIssueLevelForMissingData = eIssueLevel.Error;
	if ( this.BypassCompulsoryIfRoleAbove <= this.parent.UserRole ) nIssueLevelForMissingData = eIssueLevel.Warning;
	var cMessage = "";
	var temp;
	if (this.RealField) {
		var oField = this.GetDataField();
		if (this.Compulsory) {
			if (oField.length > 1 && (oField[0].type == "radio" || oField.length > 1 && oField[0].type == "checkbox") ) {
				switch (oField[0].type) {
				case "radio":
					var group = oField;
					var checked = false;
					if (!group.length)
						checked = el.checked;
					else
						for (var r = 0; r < group.length; r++)
							if ((checked = group[r].checked))
								break;
					if (!checked) {
						nIssueLevel = nIssueLevelForMissingData
						cMessage = this.ErrorMsgEmpty
					}
					break;
				case "checkbox":
					var group = oField;
					if (group.length) {
						var checked = false;
						for (var r = 0; r < group.length; r++)
							if ((checked = group[r].checked))
								break;
						if (!checked) {
							nIssueLevel = nIssueLevelForMissingData
							cMessage = this.ErrorMsgEmpty
				        }
				    }
			        break;
			    }
			} else {
				switch (oField.type) {
				case "text":
				case "textarea":
					temp = AllTrim(oField.value);
					if (temp.length==0) {
						nIssueLevel = nIssueLevelForMissingData
						cMessage = this.ErrorMsgEmpty
					}
					break;
				case "select-one":
					if (oField.value == '') {
						nIssueLevel = nIssueLevelForMissingData
						cMessage = this.ErrorMsgEmpty
					}
					break;
				case "select-multiple":
					if (oField.selectedIndex == -1) {
						nIssueLevel = nIssueLevelForMissingData
						cMessage = this.ErrorMsgEmpty
					}
					break;
				case "checkbox":
					if (!oField.checked) {
						nIssueLevel = nIssueLevelForMissingData
						cMessage = this.ErrorMsgEmpty
				    }
			        break;
				case "radio":
					if (!oField.checked) {
						nIssueLevel = nIssueLevelForMissingData
						cMessage = this.ErrorMsgEmpty
				    }
			        break;
				}
			}
		}
		if (nIssueLevel == 0) {
			// Do further validation checks if required
			switch (oField.type) {
			case "text":
			case "textarea":
				retval =  this.ValidateText(lFullForm);
				nIssueLevel = retval.issuelevel;
				cMessage = retval.message;
				break;
			}
	
		}
		if (cMessage.length>0) cMessage = cMessage.substring(0,1).toUpperCase() + cMessage.substring(1);
		
		this.IssueLevel = nIssueLevel;
		this.CurrentErrorMsg = cMessage;
	}
	
	return { issuelevel : nIssueLevel, message : cMessage }
};



// This checks specific text according to the relevant rules
TigerField.prototype.ValidateText = function (lFullForm) {
	var oField = this.GetDataField();
	var cText = AllTrim(oField.value);
	var cNiceControlName = this.NiceFieldName;


	var nIssueLevel, cMessage;
	nIssueLevel = 0;
	cMessage = "";
	if (cText.length > 0 || this.ValidType==eValidType.Postcode) {
		switch (this.ValidType) {
			case eValidType.Firstname:
				if (cText.length==1) {
					nIssueLevel = eIssueLevel.Error;
					cMessage = cNiceControlName+" is too short!";
				} else if (ContainsOnlyConsonants(cText)) {
					nIssueLevel = eIssueLevel.Warning;
					cMessage = cNiceControlName+" doesn't have any vowels!";
				} else if (cText != RemoveNumbers(cText)) {
					nIssueLevel = eIssueLevel.Query;
					cMessage = cNiceControlName+" contains numbers!";
				} else if (ContainsBannedWord(cText)) {
					nIssueLevel = eIssueLevel.Warning;
					cMessage = cNiceControlName+" contains a banned word!";
				}
				break;
			case eValidType.Lastname:
				if (cText.length==1) {
					nIssueLevel = eIssueLevel.Error;
					cMessage = cNiceControlName+" is too short!";
				} else if (ContainsOnlyConsonants(cText)) {
					nIssueLevel = eIssueLevel.Warning;
					cMessage = cNiceControlName+" doesn't have any vowels!";
				} else if (cText != RemoveNumbers(cText)) {
					nIssueLevel = eIssueLevel.Query;
					cMessage = cNiceControlName+" contains numbers!";
				} else if (ContainsBannedWord(cText)) {
					nIssueLevel = eIssueLevel.Warning;
					cMessage = cNiceControlName+" contains a banned word!";
				}					
				break;
			case eValidType.Job:
				if (cText.length<3) {
					nIssueLevel = eIssueLevel.Error;
					cMessage = cNiceControlName+" is too short!";
				} else if (ContainsOnlyConsonants(cText)) {
					nIssueLevel = eIssueLevel.Warning;
					cMessage = cNiceControlName+" doesn't have any vowels!";
				}
				break;
			case eValidType.Company:
				if (cText.length < 2) {
					nIssueLevel = eIssueLevel.Error;
					cMessage = cNiceControlName+" is too short!";
				}
				break;
			case eValidType.Address:
				if (cText.length < 1) {
					nIssueLevel = eIssueLevel.Error;
					cMessage = cNiceControlName+" is too short!";
				}
				break;
			case eValidType.Postcode:
				if (!lFullForm) {
					if (cText != "" && !ContainsDigits(cText)) {
						nIssueLevel = eIssueLevel.Warning;
						cMessage = cNiceControlName+" may not be valid - please check";
					} 
				}
				else {
					var ctrycode = this.parent.CountryField.GetValue();
					switch (ctrycode) {
						case "GB":
							if (cText.length==0) {
								if (this.parent.UserRole >= this.BypassCompulsoryIfRoleAbove) {
									nIssueLevel = eIssueLevel.Warning;
									cMessage = cNiceControlName+" expected for "+Country[ctrycode][0];
								} else {
									nIssueLevel = eIssueLevel.Error;
									cMessage = cNiceControlName+" required for "+Country[ctrycode][0];
								}
							} else if (!validatepcode(cText)) {
								if (this.parent.UserRole >= this.BypassCompulsoryIfRoleAbove) {
									nIssueLevel = eIssueLevel.Warning;
									cMessage = cNiceControlName+" not valid for "+Country[ctrycode][0];
								} else {
									nIssueLevel = eIssueLevel.Error;
									cMessage = cNiceControlName+" not valid for "+Country[ctrycode][0];
								}
							}
							break;
						case "US":
						case "FR":
						case "PL":
						case "DE":
						case "SE":
						case "BE":
						case "IT":
						case "ES":
						case "AU":
						case "NO":
						case "PT":
						case "DK":
						case "CA":
						case "NL":
							if (cText.length==0) {
								nIssueLevel = this.parent.IssueLevelForCompulsory;
								cMessage = cNiceControlName+" required for "+Country[ctrycode][0];
							}
							break;
						default:
							if (cText != "" && !ContainsDigits(cText)) {
								nIssueLevel = eIssueLevel.Warning;
								cMessage = cNiceControlName+" may not be valid - please check";
							}
					}
				}
				break;
			case eValidType.Phone:
				return validatephone(cText, this.parent.CountryField.GetValue(), cNiceControlName) ;
				break;
			case eValidType.Email:
				if (!validateemail(cText)) {
					nIssueLevel = eIssueLevel.Error;
					cMessage = cNiceControlName+" is not valid!";
				} 
				break;
			case eValidType.Text:
				break;
			case eValidType.Money:
				break;
			case eValidType.Integer:
				break;
			case eValidType.Date:
				var aText=cText.split("/",4);
				var nYear=parseInt(aText[2]);
				var nMonth=parseInt(aText[1]);
				var nDay=parseInt(aText[0]);

				if (aText[3] || !aText[2]) {
					nIssueLevel = eIssueLevel.Error;
					cMessage = cNiceControlName+" is not a valid date!";
				}
				if (nYear <1 || nYear > 2100 || nMonth < 1 || nMonth > 12 || nDay < 1 || nDay > 31) {
					nIssueLevel = eIssueLevel.Error;
					cMessage = cNiceControlName+" is not a valid date!";
				} 
				if ((nMonth==2 && nDay>28) || ( (nMonth==4 || nMonth==6 || nMonth==9 || nMonth==11) && nDay==31)) {
					nIssueLevel = eIssueLevel.Error;
					cMessage = cNiceControlName+" is not a valid date!";
				}
				break;
			case eValidType.Time:
				break;
			case eValidType.CreditCardNumber:
				break;
			default:
		}
	}
	if ( this.BypassCompulsoryIfRoleAbove <= this.parent.UserRole && nIssueLevel==eIssueLevel.Error) nIssueLevel = eIssueLevel.Warning;
	return { issuelevel : nIssueLevel, message : cMessage }
}


// routine to check email integrity

function validateemail(s) {
	s=AllTrim(s)
	s=s.toLowerCase()
	if (s.indexOf("@") < 1) {
		return false
	}
	var cAfterAt=s.substr(s.indexOf("@")+1)
	
	if (s.indexOf(" ") >= 0) {
		return false
	} else if (s.indexOf(",") >= 0) {
		return false
	} else if (s.indexOf("/") >= 0) {
		return false
	} else if (s.indexOf("\\") >= 0) {
		return false
	} else if (s.indexOf(";") >= 0) {
		return false
	} else if (s.indexOf("<") >= 0) {
		return false
	} else if (s.indexOf(">") >= 0) {
		return false
	} else if (s.indexOf("(") >= 0) {
		return false
	} else if (s.indexOf(")") >= 0) {
		return false
	} else if (cAfterAt.indexOf("@") >= 0) {
		return false
	} else if (cAfterAt.indexOf(".") <1) {
		return false
	} else if (cAfterAt.indexOf("..") >=0) {
		return false
	}
	
	var cReverse=ReverseString(cAfterAt)
	if (cReverse.indexOf(".")<2 || cReverse.indexOf(".")>8) {
		return false
	}
	return true
} 


function validateccno(st) {
  // Encoding only works on cards with less than 19 digits
  if (st.length > 19)
    return (false);

  sum = 0; mul = 1; l = st.length;
  for (i = 0; i < l; i++) {
    digit = st.substring(l-i-1,l-i);
    tproduct = parseInt(digit ,10)*mul;
    if (tproduct >= 10)
      sum += (tproduct % 10) + 1;
    else
      sum += tproduct;
    if (mul == 1)
      mul++;
    else
      mul--;
  }

  if ((sum % 10) == 0)
    return (true);
  else
    return (false);
}



// check postcode is valid

function validatepcode(s) {
	s=s.toUpperCase()
	var temp1=ChrTran(ChrTran(s,".","")," ","")
	var temp2=""
	if (temp1.substr((temp1.length)-3,1)=="O") {
		temp1=temp1.substr(0,(temp1.length)-3)+"0"+temp1.substr((temp1.length)-2,2)
	}
	for (var i=0; i<temp1.length; i++) {
		if (isAlpha(temp1.substr(i,1))) {
			temp2=temp2+"X"
		} else if (isDigit(temp1.substr(i,1))) {
			temp2=temp2+"9"
		} else {
			temp2=temp2+"?"
		}
	}
	switch (temp2) {
		case "XX99XX":
		case "X9X9XX":
		case "X999XX":
		case "XX999XX":
		case "XX9X9XX":
		case "X99XX":
		case "XX9":
		case "X9X":
		case "X99":
		case "XX9":
		case "XX9":
		case "X9":
			return true
			break;
		default:
			return false
			break;
	}
	return false
}
// Check that a Expiry Data on Credit Card 

function checkccdate(frm) {
if (checkcard(frm))
{
d=new Date()
dMonth=d.getMonth()
dMonth+=1
dYear=d.getYear()
dYear-=2000
var exmonth=Number(frm.ccexp1.options[frm.ccexp1.selectedIndex].value)
var exyear=Number(frm.ccexp2.options[frm.ccexp2.selectedIndex].value)
if (exyear<dYear) {
        alert('Credit Card has Expired Year')
        frm.ccexp2.focus()
        return false
        }

if (exyear == dYear && exmonth<dMonth) {
        alert('Credit Card has Expired Month')
        frm.ccexp1.focus()
        return false
        }

}
else
{
return false
}
return true
}
// Check that a Credit card is a Valid Number

function checkcard(frm) {
        var cc1=0
        var cc2=""
        var cc3=0
        var ccsum=0
        var add=0
        var ctr=0
        cc=ltrim(trim(frm.ccno.value))
        if (cc.length==0) {
        alert('Please Enter a Card Number')
        frm.ccno.focus()
        return false
        }
        cc1=cc.length
        cc1=cc1-1
        while (cc1>=0) {
        if (cc.substr(cc1,1)>="0" && cc.substr(cc1,1)<="9") {
        cc2=cc2+cc.substr(cc1,1)
        }
        cc1=cc1-1
        }
        cc1=0
        while (cc1<cc2.length) {
                                if (cc3==1) {
                                             if (cc2.substr(cc1,1)>="5")
                                                 {
                                                  add = Number(cc2.substr(cc1,1))*2 -9;
                                                  }
                                              else
                                                  {
                                                  add = Number(cc2.substr(cc1,1)) *2;
                                                  }
                                              }
                                              else
                                              {
                                                  add = Number(cc2.substr(cc1,1));
                                              }
                ccsum=ccsum+add;
                if (cc3==1) {
                cc3=0;
                } else {
                cc3=1;
                }

                cc1=cc1+1;
                }
        while (ccsum>0)
        {
        ccsum=ccsum-10
        }
        if (ccsum<0)
        {
        alert ('Your Card number is invalid')
        frm.ccno.focus()
        return false
        }

        cc=ltrim(trim(frm.ccno.value))
        cc1=cc.length
        ctr=0;
        cc2=""
        while (ctr<=cc1) {
        if (cc.substr(ctr,1)>="0" && cc.substr(ctr,1)<="9") {
        cc2=cc2+cc.substr(ctr,1)
        }
        ctr=ctr+1
        }
        frm.ccno.value=cc2
        cc=ltrim(trim(frm.ccno.value))


        if (cc.length>16) {
         if (checkcardtype(frm,"SWIT")) {
         frm.cctype.options.value="SWIT"
         return true
         }
        else {
        alert ('We do not accept Switch Cards \nPlease use another type of Credit Card')
        frm.ccno.focus()
        return false
         }
         }

        if (cc.length==15) {
         if (checkcardtype(frm,"AMEX")) {
         frm.cctype.options.value="AMEX"
         return true
         }
        else {
        alert ('We do not accept American Express \nPlease use another type of Credit Card')
        frm.ccno.focus()
        return false
         }
         }
         if (cc.substr(0,1)=="4") {
         if (checkcardtype(frm,"VISA")) {
         frm.cctype.options.value="VISA"
         return true
         }
        else {
        alert ('We do not accept VISA Cards \nPlease use another type of Credit Card')
        frm.ccno.focus()
        return false
         }
         }

         if (cc.substr(0,1)=="5") {
         if (checkcardtype(frm,"MAST")) {
         frm.cctype.options.value="MAST"
         return true
         }
        else {
        alert ('We do not accept MasterCard \nPlease use another type of Credit Card')
        frm.ccno.focus()
        return false
         }
         }

return true
}
//alert(frm.cctype.options.length)
         //alert(frm.cctype.options[0].value)
         //alert(frm.cctype.options[1].value)
         //alert(frm.cctype.options[2].value)
         //alert(frm.cctype.options[3].value)

function checkcardtype(frm,req) {
        var y
        for (var j=0; j<frm.cctype.options.length; j++) {
                y=frm.cctype.options[j]
                if (y.value==req) {
                return true
                        }
        }
      return false
}




function emailCheck (emailStr) {

/* The following variable tells the rest of the function whether or not
to verify that the address ends in a two-letter country or well-known
TLD.  1 means check it, 0 means don't. */

var checkTLD=1;

/* The following is the list of known TLDs that an e-mail address must end with. */

var knownDomsPat=/^(com|net|org|edu|int|mil|gov|arpa|biz|aero|name|coop|info|pro|museum|xxx|jobs|mobi|travel)$/;

/* The following pattern is used to check if the entered e-mail address
fits the user@domain format.  It also is used to separate the username
from the domain. */

var emailPat=/^(.+)@(.+)$/;

/* The following string represents the pattern for matching all special
characters.  We don't want to allow special characters in the address. 
These characters include ( ) < > @ , ; : \ " . [ ] */

var specialChars="\\(\\)><@,;:\\\\\\\"\\.\\[\\]";

/* The following string represents the range of characters allowed in a 
username or domainname.  It really states which chars aren't allowed.*/

var validChars="\[^\\s" + specialChars + "\]";

/* The following pattern applies if the "user" is a quoted string (in
which case, there are no rules about which characters are allowed
and which aren't; anything goes).  E.g. "jiminy cricket"@disney.com
is a legal e-mail address. */

var quotedUser="(\"[^\"]*\")";

/* The following pattern applies for domains that are IP addresses,
rather than symbolic names.  E.g. joe@[123.124.233.4] is a legal
e-mail address. NOTE: The square brackets are required. */

var ipDomainPat=/^\[(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\]$/;

/* The following string represents an atom (basically a series of non-special characters.) */

var atom=validChars + '+';

/* The following string represents one word in the typical username.
For example, in john.doe@somewhere.com, john and doe are words.
Basically, a word is either an atom or quoted string. */

var word="(" + atom + "|" + quotedUser + ")";

// The following pattern describes the structure of the user

var userPat=new RegExp("^" + word + "(\\." + word + ")*$");

/* The following pattern describes the structure of a normal symbolic
domain, as opposed to ipDomainPat, shown above. */

var domainPat=new RegExp("^" + atom + "(\\." + atom +")*$");

/* Finally, let's start trying to figure out if the supplied address is valid. */

/* Begin with the coarse pattern to simply break up user@domain into
different pieces that are easy to analyze. */

var matchArray=emailStr.match(emailPat);

if (matchArray==null) {

/* Too many/few @'s or something; basically, this address doesn't
even fit the general mould of a valid e-mail address. */

//alert("Email address seems incorrect (check @ and .'s)");
return false;
}
var user=matchArray[1];
var domain=matchArray[2];

// Start by checking that only basic ASCII characters are in the strings (0-127).

for (i=0; i<user.length; i++) {
if (user.charCodeAt(i)>127) {
//alert("Ths username contains invalid characters.");
return false;
   }
}
for (i=0; i<domain.length; i++) {
if (domain.charCodeAt(i)>127) {
//alert("Ths domain name contains invalid characters.");
return false;
   }
}

// See if "user" is valid 

if (user.match(userPat)==null) {

// user is not valid

//alert("The username doesn't seem to be valid.");
return false;
}

/* if the e-mail address is at an IP address (as opposed to a symbolic
host name) make sure the IP address is 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) {
//alert("Destination IP address is invalid!");
return false;
   }
}
return true;
}

// Domain is symbolic name.  Check if it's valid.
 
var atomPat=new RegExp("^" + atom + "$");
var domArr=domain.split(".");
var len=domArr.length;
for (i=0;i<len;i++) {
if (domArr[i].search(atomPat)==-1) {
//alert("The domain name does not seem to be valid.");
return false;
   }
}

/* domain name seems valid, but now make sure that it ends in a
known top-level domain (like com, edu, gov) or a two-letter word,
representing country (uk, nl), and that there's a hostname preceding 
the domain or country. */

if (checkTLD && domArr[domArr.length-1].length!=2 && 
domArr[domArr.length-1].search(knownDomsPat)==-1) {
//alert("The address must end in a well-known domain or two letter " + "country.");
return false;
}

// Make sure there's a host name preceding the domain.

if (len<2) {
//alert("This address is missing a hostname!");
return false;
}

// If we've gotten this far, everything's valid!
return true;
}


function validatephone(cText, cCountry, cNiceControlName) {
	var issuelevel, message="", s

	s = cText;
	s = s.replace( /[\(\)\-\.\[\]\{\}\=\s]/g, "");
	s = s.replace( /^00/, "+" );
	s = s.replace( /^\+\+/, "+" );
	s = s.replace( /^([^A-Za-z/]*)(.*)/, "$1" );

	// Extract the country code if possible
	var CtryCodeInNumber = "";
	var MinLength = 7;
	var MaxLength = 17;
	var Dial
	if (StartsWith(s,"+")) {
		if (cCountry) {
			Dial = Country[cCountry][1].replace(/\s/g,"");
			if (!StartsWith(s, "+"+Dial)) {
				return { issuelevel:2, message:cNiceControlName+" does not appear to be from "+Country[cCountry][0] }
			}
		}
		
		var CtryCodeInNumber = ExtractCountryCode(s.substring(1));
		if (CtryCodeInNumber) {
			if (Dialcode[CtryCodeInNumber]) {
				if (Dialcode[CtryCodeInNumber][1]) {
					MinLength = Dialcode[CtryCodeInNumber][1];
				}
				if (Dialcode[CtryCodeInNumber][2]) {
					MinLength = Dialcode[CtryCodeInNumber][2];
				}
			}
			s = s.substring(CtryCodeInNumber.length+1); //+1 to account for the + at the beginning
		}
	}
	if (s.length < MinLength) return {issuelevel:2, message:cNiceControlName+" seems too short"}
	if (s.length > MaxLength) return {issuelevel:2, message:cNiceControlName+" seems too long"}


	return { issuelevel:0, message:"" }
}

function NameChanged(cOrigFirstName, cOrigSurName, cNewFirstName, cNewSurName ) {

	var FNDiff, SNDiff, FNMaxLength, SNMaxLength;
	cOrigFirstName = AllTrim(cOrigFirstName.toUpperCase())
	cNewFirstName = AllTrim(cNewFirstName.toUpperCase())
	FNMaxLength=cOrigFirstName.length
	if (cNewFirstName.length > FNMaxLength) FNMaxLength=cNewFirstName.length
	FN1a = cOrigFirstName.substring(0,1)
	FN2a = cNewFirstName.substring(0,1)
	cOrigSurName = AllTrim(cOrigSurName.toUpperCase())
	cNewSurName = AllTrim(cNewSurName.toUpperCase())
	SNMaxLength=cOrigSurName.length
	if (cNewSurName.length > SNMaxLength) SNMaxLength=cNewSurName.length
	SNDiff = LD(cOrigSurName, cNewSurName) / SNMaxLength
	if ( (cNewSurName.length<cOrigSurName.length && StartsWith(cOrigSurName,cNewSurName)) || (cNewSurName.length>cOrigSurName.length && StartsWith(cNewSurName,cOrigSurName)) ){
			SNDiff=0
		}
	FNDiff = LD(cOrigFirstName, cNewFirstName) / FNMaxLength
	if ( (cNewFirstName.length<cOrigFirstName.length && StartsWith(cOrigFirstName,cNewFirstName)) || (cNewFirstName.length>cOrigFirstName.length && StartsWith(cNewFirstName,cOrigFirstName)) ){
			FNDiff=0
		}
	return (SNDiff > 0.35 || FNDiff > 0.35) && !(cOrigFirstName==cNewSurName && cOrigSurName==cNewFirstName) 
}


