// Test var 
// alert("scriptishere");
///////////////////
// @ validate.js //
///////////////////
//
// @ Author: Simon Potter (simon@honk.com.au)
// @ Created: 18-9-01
// @ Author: $Author: $
// @ Workfile: $WorkFile: $
// @ Update No.:  $Revision: $
// @ Last Modified: $Modtime: $ 
//
// @ Bugs Status
//	20-9-01 - Known bug with range value in multiple field checks, fix if you dare!
//
//	11-01-02 - Known bug with looping through content validated fields, i.e. will fail if you have multiple RisEml etc
//
// @ Suggestions/Modifications please contact above
//
// @ This script will validate:
//		- EXISTENCE of a value in a field 
//				(fieldName,RisVal,displayName)
//		- EXISTENCE of a string value in a field 
//				(fieldName,RisStr,displayName)
//		- EXISTENCE select field
//				(fieldName,RisSel,displayName)
//		- EXISTENCE of an unpunctuated string value in a field 
//				(fieldName,NnoPun,displayName)
//		- VALIDITY of a unpunctuatedstring value in a field 
//				(fieldName,RnoPun,displayName)
//		- EXISTENCE of a value one of several fields 
//				(fieldName1/fieldname2/fieldname3,condition1/condition2/condition3,displayMsg)
//		- EXISTENCE of a value in a dropDown 
//				(fieldName,RisVal,displayName)
//		- EXISTENCE & VALIDITY of an Email address 
//				(fieldName,RisEml,displayName)
//		- VALIDITY (not requirement) of an Email address  
//				(fieldName,isEml,displayName)
//		- EXISTENCE of a numeric value in a field 
//				(fieldName,RisNum,displayName)
//		- VALIDITY (not requirement) of a numeric value in a field 
//				(fieldName,isNum,displayName)
//		- EXISTENCE of a numeric value within a range in a field 
//				(fieldName,RisNum-from:to,displayName)
//		- VALIDITY (not requirement) of a numeric value within a range in a field 
//				(fieldName,isNum-from:to,displayName)
//		- VALIDITY (not requirement) of a date
//				(fieldName,isDat,displayName)
//		- COMPARE two field values ie: password and confirm password
//				(fieldName1,compar:fieldName2,displayName1:displayName2)
//		- LENGTH of a field value
//				(fieldName1,strlen:maxlength,displayName)
//				
// @ Standard Syntax
// 
//	Insert the following into your form somewhere useful ie onClick or onSubmit
//	onclick/onSubmit = "return validate(fieldName,condition,displayName)"

// @ Basic process outline

// Change this if required
var adminEmailAddress  = 'simon.potter@tmg.co.uk';

// @ Define global vars
var NisNum = 'a NUMBER';
var NisEml = 'a valid EMAIL ADDRESS';
var NnoPun = 'TEXT without punctuation';
var RisNum = 'a NUMBER';
var RisEml = 'a valid EMAIL ADDRESS';
var RisVal  = 'FILLED';
var RisStr  = 'TEXT';
var RnoPun  = 'TEXT without punctuation';
var RisSel = 'SELECTED';

///////////////////////////////////////////////////////////////////////////////////////////////
/// ** validate() this function sets up the parameters to be passed to the main function ** ///
///////////////////////////////////////////////////////////////////////////////////////////////
function validate(fieldsToValidate,formReference) {
	// Set the first array
	fieldsToValidate = fieldsToValidate.split(",");
	// validate sufficient arguments have been passed
	// if not divisible by 4 then it is unusuable
	var valueCheck = fieldsToValidate.length / 3;
	if (valueCheck != parseInt(valueCheck)){
		alert("Administrator Error: You have not provided a sufficient number of parameters \n email:"+adminEmailAddress+" for info \n or READ the instructions!");
	}
	// Local vars
	var errorMsg = new Array();
	// loop counter independent of array number
	var x = 0;
	// if the request is usable, loop through the request groups
	// a group is a section of the csv separated by three commas ',' (ie four values)
	for (i=0; i<fieldsToValidate.length; i+=3){	
			
			// Vars common to single and multiple entry checks
			var fieldToCheck = fieldsToValidate[i]; // field to check
			//alert(fieldToCheck);
			var displayMsg = fieldsToValidate[i+2];	// the message to display if not met					
			//alert(displayMsg);
			
			// find out if it is a multiple field check, ie one of several fields must be filled
			// * Single attribute * //
			if (fieldsToValidate[i].indexOf("/") < 1){  // value does not contain '/' symbol
				var doValidate = 'yes'; // default process directive 

				var condition = fieldsToValidate[i+1].substring(0,6); // condition the fields must meet
				//alert(condition);
				var range = fieldsToValidate[i+1].substring(7,fieldsToValidate[i+1].length); // the range (if specified)
				//alert(range);
				// is the value present?
				// alert(document.forms[formReference].elements[fieldToCheck].value);
				if(document.forms[formReference].elements[fieldToCheck].value == ''){
					//the value is not present, so do not validate, but complain if the field was required
					if(condition.substring(0,1) == 'R'){
						errorMsg[x] = 'The ' + displayMsg + ' is required and must be ' + eval(condition) + '.';
						x++;
					}
					doValidate = 'no';
				}// end valid content check
				
				if (doValidate == 'yes'){
					// now ensure the data meets the requirement;
					var returnErrorMsg = validateData(fieldToCheck,condition,range,formReference);
					if (returnErrorMsg.length > 0){
						if(condition == 'compar'){
							//special case as the error message will be different for this type of validation
							var divider = displayMsg.indexOf(":");
							errorMsg[x] = 'The fields ' + displayMsg.substring(0,divider) + ' and ' + displayMsg.substring(divider+1,displayMsg.length)  + ' ' + returnErrorMsg;
						}else{
							errorMsg[x] = 'The ' + displayMsg + ' field ' + returnErrorMsg;
						}
						x++;
					}// end return errorMsg
				}// end do validate	
				
					
			// * Multiple field validation * //
			}else{
				alert(condition);
				doValidate = 'yes';
				needOne = 0;
				var fieldsArray = fieldToCheck.split('/');
				var conditionArray = fieldsToValidate[i+1].split('/');
				
				// Validators validation
				if (fieldsArray.length != conditionArray.length){
					alert("Validation Administrator Error: You have not provided an equal value pairing in your one of several select.  /n email:" + adminEmailAddress + " for info /n or READ the instructions!");
				}
			
				// * Now loop through the validation fields * //
				for (i=0; i<fieldsArray.length; i++){
					alert(fieldsArray[i]);
					// if there is at least one field filled in we're ok
					if(document.forms[formReference].elements[fieldsArray[i]].value != ''){
							needOne = 1;	
						} // end basic requirement check
						needOne = needOne;
					}// end fieldsarray loop			
					// Check to see if we need en entry still					
					if (needOne == 0){
						errorMsg[x] = 'You must provide values for at least one of the following fields: ' + displayMsg;
						doValidate = 'no';
						x = x + 1;
						}// end valid content check

						// * Do Validate if neccessary * //
						if (doValidate == 'yes'){
								for (i=0; i<fieldsArray.length; i++){
								if(document.forms[formReference].elements[fieldsArray[i]].value != ''){
									var fieldToCheck = fieldsArray[i]; // field to check
									var condition = conditionArray[i].substring(0,6); // condition the fields must meet
									//var range = conditionArray[i].substring(7,fieldsToValidate[i+1].length)); // the range (if specified)
								
									// now ensure the data meets the requirement;
										var returnErrorMsg = validateData(fieldToCheck,condition,range,formReference);
										if (returnErrorMsg.length > 0){
													errorMsg[x] = 'The ' + displayMsg + ' field ' + returnErrorMsg;
													x = x + 1;
												}//end check values field				
										}// end return errorMsg
								}//end valid fields loop				
						} // end if doValidate == yes		
			}// end check for multiple
		}//end function loop
		
		// Now decide on what we're returning
		// * An error message * //
		if (errorMsg[0]){
			for (i=0; i<errorMsg.length; i++){
				if (i == 0){
				var errorMsgDisplay = '\tINFORMATION NOT COMPLETE:\n\n';
				errorMsgDisplay = errorMsgDisplay + '1) '  + errorMsg[i] + '\n';
				}else{
				errorMsgDisplay = errorMsgDisplay + (i+1) + ') ' + errorMsg[i] + '\n';
				}
			}
			alert(errorMsgDisplay);
			return false;
		// * or nothing * //
		}else{
			return true;
		}//end return check
}// end function
	
///////////////////////////////////////////////////////////
/// ** validataeData is the main validation function ** ///
///////////////////////////////////////////////////////////
function validateData(fieldToCheck,condition,range,formReference){
var returnErrorMessage = '';
var currentValue = document.forms[formReference].elements[fieldToCheck].value;
//alert(currentValue);

if (condition == 'NisDat'){
	if(!isDate(currentValue)){
		returnErrorMessage = ' must be in dd/mm/yyyy format';
	}
}

//* Compare two field values *//
if (condition =='compar'){
	var compareValue = document.forms[formReference].elements[range].value;
	if(currentValue != compareValue){
		returnErrorMessage = ' must be equal';
	}
}

if (condition =='strlen'){
	if(currentValue.length > range){
		returnErrorMessage = ' must be less than ' + range + ' characters';
	}
}

// * validate numbers (may or may not have a range)* //
if (condition == 'NisNum' || condition == 'RisNum'){
	// * numeric with range parameter * //
	if (range != ''){
		var divider = range.indexOf("-");
		var lowRange = range.substring(0,divider);
		var highRange = range.substring(divider+1,range.length);
			if ((currentValue <= lowRange) || (currentValue >= highRange)){
				returnErrorMessage = 'must be a number between '+ lowRange + ' and ' + highRange + ' it is currently ' + currentValue;
			}
			// * numeric without range parameter * //
			}else{
				if (isNaN(document.forms[formReference].elements[fieldToCheck].value)){
					returnErrorMessage = 'must be a number'
				} // end numeric sub check
		} // end range check
	} //end numeric check
	
// * Email address * //	
if (condition == 'NisEml' || condition == 'RisEml'){
	emailOK = emailCheck(currentValue);
	//alert(emailOK);
	if(!emailOK){
		returnErrorMessage = 'must be a valid email address'
	}
	
	/*punctuation = 'no';
	var invalidPunc = "!£$%^&*(#)+={[}]:;|<,>?/`\"";
	for (i = 0; i < currentValue.length; i++) {
		charPos = invalidPunc.indexOf(currentValue.charAt(i));
		if (charPos > 0) {
			punctuation = 'yes';
		} // end check for positive response 
	}// end of punctuation loop
	
	if (punctuation == 'yes' || currentValue.indexOf("@")==-1 || currentValue.indexOf(".")==-1 || currentValue.indexOf(" ")!=-1 || currentValue.length<6){
		returnErrorMessage = 'must be a valid email address';
		}//end valid email checker
		*/
		
	}//end is email
// * No Punctuation * //	
if (condition == 'NnoPun' || condition == 'RnoPun'){
	 var invalidPunc = "!@£$%^&*(#)_-+={[}]:;|<,>.?/~`\'\"\\";
		for (i = 0; i < currentValue.length; i++) {
			charPos = invalidPunc.indexOf(currentValue.charAt(i));
			if (charPos > 0) {
				returnErrorMessage = 'must not contain any punctuation';
			} // end check for positive response 
		}// end of punctuation loop
	}//end no punctuation
	
// Now regardless return an error message (Which may be blank)
return returnErrorMessage;
}

/* 1.1.4: Fixed a bug where upper ASCII characters (i.e. accented letters
	international characters) were allowed.
	
	1.1.3: Added the restriction to only accept addresses ending in two
	letters (interpreted to be a country code) or one of the known
	TLDs (com, net, org, edu, int, mil, gov, arpa), including the
	new ones (biz, aero, name, coop, info, pro, museum).  One can
	easily update the list (if ICANN adds even more TLDs in the
	future) by updating the knownDomsPat variable near the
	top of the function.  Also, I added a variable at the top
	of the function that determines whether or not TLDs should be
	checked at all.  This is good if you are using this function
	internally (i.e. intranet site) where hostnames don't have to 
	conform to W3C standards and thus internal organization e-mail
	addresses don't have to either.
	Changed some of the logic so that the function will work properly
	with Netscape 6.
	
	1.1.2: Fixed a bug where trailing . in e-mail address was passing
	(the bug is actually in the weak regexp engine of the browser; I
	simplified the regexps to make it work).
	
	1.1.1: Removed restriction that countries must be preceded by a domain,
	so abc@host.uk is now legal.  However, there's still the 
	restriction that an address must end in a two or three letter
	word.
	
	1.1: Rewrote most of the function to conform more closely to RFC 822.
	
	1.0: Original  */
	// -->
	
	// Begin
	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)$/;
	
	/* 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;
	}

///////////////////////////////////////////////////////////
/// ** functions added to do proper date validation  ** ///
/// ** dd/mm/yyyy format                             ** ///
///////////////////////////////////////////////////////////
var dtCh= "/";
var minYear=1900;
var maxYear=2100;

function isInteger(s){
	var i;
    for (i = 0; i < s.length; i++){   
        // Check that current character is number.
        var c = s.charAt(i);
        if (((c < "0") || (c > "9"))) return false;
    }
    // All characters are numbers.
    return true;
}

function stripCharsInBag(s, bag){
	var i;
    var returnString = "";
    // Search through string's characters one by one.
    // If character is not in bag, append to returnString.
    for (i = 0; i < s.length; i++){   
        var c = s.charAt(i);
        if (bag.indexOf(c) == -1) returnString += c;
    }
    return returnString;
}

function daysInFebruary (year){
	// February has 29 days in any year evenly divisible by four,
    // EXCEPT for centurial years which are not also divisible by 400.
    return (((year % 4 == 0) && ( (!(year % 100 == 0)) || (year % 400 == 0))) ? 29 : 28 );
}
function DaysArray(n) {
	for (var i = 1; i <= n; i++) {
		this[i] = 31
		if (i==4 || i==6 || i==9 || i==11) {this[i] = 30}
		if (i==2) {this[i] = 29}
   } 
   return this
}

function isDate(dtStr){
	var daysInMonth = DaysArray(12)
	var pos1=dtStr.indexOf(dtCh)
	var pos2=dtStr.indexOf(dtCh,pos1+1)
	var strDay=dtStr.substring(0,pos1)
	var strMonth=dtStr.substring(pos1+1,pos2)
	var strYear=dtStr.substring(pos2+1)
	strYr=strYear
	if (strDay.charAt(0)=="0" && strDay.length>1) strDay=strDay.substring(1)
	if (strMonth.charAt(0)=="0" && strMonth.length>1) strMonth=strMonth.substring(1)
	for (var i = 1; i <= 3; i++) {
		if (strYr.charAt(0)=="0" && strYr.length>1) strYr=strYr.substring(1)
	}
	month=parseInt(strMonth)
	day=parseInt(strDay)
	year=parseInt(strYr)
	if (pos1==-1 || pos2==-1){
		return false
	}
	if (strMonth.length<1 || month<1 || month>12){
		return false
	}
	if (strDay.length<1 || day<1 || day>31 || (month==2 && day>daysInFebruary(year)) || day > daysInMonth[month]){
		return false
	}
	if (strYear.length != 4 || year==0 || year<minYear || year>maxYear){
		return false
	}
	if (dtStr.indexOf(dtCh,pos2+1)!=-1 || isInteger(stripCharsInBag(dtStr, dtCh))==false){
		return false
	}
return true
}
	
	
	
	//  End -->
	
	
