/* GENERALISED FORM VALIDATION ROUTINES FOR BOTH FORM AND FIELD VALIDATION OPF TEXT AND TEXTAREA USING REGULAR EXPRESSIONS
USE - The general format of a FORM VALIDATE routine (referenced from the onSubmit clause of the form, possibly as: "return validate(this);") 
			which uses this package must be as follows:
				function validate(frm){
				prologue();
				msg=noMatch(frm.control1, type1, msg, optional);
				msg=noMatch(frm.control2, type2, msg);
				msg=noMatch(frm.control3, type3, msg, optional);
				msg=noMatch(frm.controlN, typeN, msg);
				return epilogue();
				}//function
	where control1..controlN are the objects on the form to be validated, 
				type1...typeN are the type of pattern matching to be performed.  
				optional is any string of characters.  If it is present it means that the field is optional, but if data
								 is entered, it must be validated. 
								 If optional contains the string Case, the control will be checked for both upper and lower case letters
	Notes:
		1) The following types have been defined: Email, Name, Phone, Password.......
		2) prologue, epilogue and msg must be exactly as shown.
		3) The variables: errorWindow, written, msg, problems, highlight, clear, 
											errorColour, patterns, errMsg, CheckFlag
			 are used by this package and should not be used elsewhere
			 
USE - for individual field validation highlighting, you should code the following for each textarea or input type:
				onFocus="Enter(this);" onBlur="Leave(this,'type');"
			where the second argument, type, is optional.  If it is given, it must be one of the types defined above.  
			If the second argument is omitted, no pattern matching is done, but the current field will be highlighted.
			Highlighting can be used with all controls on a form, not only text and textarea. 
	
*/
var errorWindow; var msg="";var problems=0;var CheckFlag=false; var msgBox=""; //var SubmitErrorWindow=null
var highlight='rgb(255, 255, 192)'; var clear='white'; var errorColour='rgb(255,200,200)'; var lastMsg='';var firstError
var markChanged='rgb(192, 255, 192)'; var leaveColour; var lastBad=false; var allMessages = ''; var field, msg1, msgBox1;  var bd = new BrowserDetector();
var browser=bd.browser
if (browser=="Netscape" && bd.majorver == 4) browser = 'Netscape4'
var patterns=new Array();
var errMsg=new Array();
patterns['Name']='^[a-z][a-z \\-\']*[a-z]$';
errMsg['Name']='The first character of a name must be a letter which can be followed by another letter, a space or a -.  Names must be at least 2 characters long.  Either upper case of lower case letters may be used.  The last character of a name must be a letter.  Do not include full stops.'
patterns['Initials']='^[A-Z]*[A-Z]$';
errMsg['Initials']='Initials must consist of one or more UPPER case letters.'
patterns['Email']='^[a-z][a-z_0-9\\.\\-]*@[a-z_0-9\\.\\-]+\\.[a-z]{2,3}$';
errMsg['Email']='The first character of an email address must be a letter which can be followed by a letters or digits or points.  The name must be followed by an @ followed by a domain name, where a domain name consists of groups of letters or digits separated by points.  The last group must be either 2 or 3 letters (not digits).'
patterns['Phone']='^\\+[0-9]+ [0-9]+ [0-9]+$';
errMsg['Phone']="A 'phone number must consist of a + followed by the international code, regional code and local number with single spaces between the codes and the local number.";
patterns['Title']='^[a-z]+$'
errMsg['Title']='Your title must be selected from the list.'
patterns['Select']='^[a-z ]+$'
errMsg['Select']='You must select an item from the list.'
patterns['1k text']='^(.|\n){1,1024}$'
errMsg['1k text']='Text may not be blank. The maximum allowable length of text is 1024 characters'
patterns['255 text']='^(.|\n){1,255}$'
errMsg['255 text']='Text may not be blank. The maximum allowable length of text is 255 characters'
patterns['2k text']='^(.|\n){1,2200}$'
errMsg['2k text']='Text may not be blank. The maximum allowable length of text is 2048 characters'
patterns['Any']='^(.){1,}$'
errMsg['Any']='Text may not be blank'
patterns['ZeroToNine']='^[0-9]$'
errMsg['ZeroToNine']='Only a single digit in the range 0 to 9 is allowable'
patterns['NOT11']='^[^1][^1]$'
errMsg['NOT11']='You must select an item from the list'

var msgCase; var ctlValue; var submitWindow; var header
function noMatch (ctl,type,msg0,optional){//alert('noMatch |' + ctl.name + '|\n value |' + ctl.value + '|\n Type |' + type + '|\n Optional |' + optional + '|') // called for each field in FORM validation, the Leave function does its own pattern matching for indivudual fields
msg1="";	msgCase=""; msgBox1="";
if (typeof ctl == 'undefined'){
	msg1="Logic error, control is undefined (does not exist?) for: Type-> " + type + " Optional-> " + optional + " msg0-> " + msg0
	msg0 += "<br>"+msg1
	return msg0
}
if ( browser == 'Netscape4' && ctl.type == 'select-one'){ 
	ctlValue = ctl.options[ctl.selectedIndex].value
}else{
	ctlValue=ctl.value
}
while (ctlValue.charAt(ctlValue.length-1) == ' '){ ctlValue=ctlValue.substring(0, ctlValue.length-1) } // trim trailing blanks
if ((typeof optional != 'undefined'  && ctlValue=='' && optional != 'Case') || typeof type == 'undefined' ){ // optional blank field or no RegExp defined - must be OK
}else{ 
	var rePattern = patterns[type];
	if (typeof rePattern == 'undefined'){
		alert('BUG! - No pattern has been defined for ' +type);
		return 'BUG! - No pattern has been defined for ' +type//false;
	}
	var re = new RegExp( rePattern, "ig" );
	if ((typeof optional != 'undefined') && (optional.indexOf('Case') != -1) && (ctlValue != '') && (ctlValue == ctlValue.toUpperCase() || ctlValue == ctlValue.toLowerCase()))	msgCase = 'It must contain both Upper and Lower Case letters.';
	if (ctlValue.match(re)==null){ msg1 = errMsg[type]; }
	if (browser == 'Opera' && type.indexOf('text',0) >=0 && msg1 != '' && ctlValue.length >0 ) 		msg1 = ''
	msgBox1 = msg1
	if (browser != 'Netscape4')	{ ctl.style.backgroundColor = markChanged }
	if (msgCase + msg1 != ""){
		if (firstError == null ) firstError = ctl //ready to fix the first problem   - cannot just ctl.focus() due to Opera bug
		problems++;
		if (msg1 == '' ){
			msg1 = msgCase;
			msgBox1 = msgCase
		}else if (msgCase != ''){
			msg1 += "<br>" + msgCase;
			msgBox1 += "\n" + msgCase
		}		
		if ((browser=="Netscape4") || ctl.title == '' ){ // these guys don't recognise the title attribute || browser=="Opera" 
			field=ctl.name
			field=field.replace(/_/,' ');
		}else{
			field=ctl.title
			ctl.style.backgroundColor = errorColour
		}
		if (type == 'NOT11'){ctlValue=''}
		ctlValue=ctlValue.replace(/</g, '&lt;'); //    ensure no confusion from a quasi html tag
		var crlf="\n"; // NB can't use pattern matching to replace a CRLF
		var i=ctlValue.indexOf(crlf);
		while (i >= 0 ){
			ctlValue=ctlValue.substr(0,i-1) + "<br>" +ctlValue.substr(i+1);
			i=ctlValue.indexOf(crlf);
		}	
		if (ctlValue.length <=60){
			msg0 += "<p>"+problems+") '"+ctlValue+"' in <strong>"+field+"</strong> is not acceptable.<br>"+msg1+'</p>';
			msgBox += "\n" + problems + ") '" + ctlValue + "' in "+field+" is not acceptable.\n" + msgBox1 + '\n';
		}else{
			msg0 += "<p>"+problems+") '"+ctlValue+"'<br>in <strong>"+field+"</strong> is not acceptable.<br>" + msg1 + '</p>';
			msgBox += "\n" + problems + ") '" + ctlValue + "'\nin " + field + " is not acceptable.\n" + msgBox1 + '\n';
		}//if 																	(ctlValue.length <=60)
	}//if 																		(ctlValue=='Required field')
}//if                                 (optional !=undefined && ctlValue=="")
if (NoPopUps){
	return msgBox
}else{
	return msg0;
}
}//function noMatch

function leavePhone(ctl,optional){ 
	if (ctl.value.charAt(0) != '+' && ctl.value.length > 0){
		ctl.value='+' + ctl.value
	}
	if (typeof optional != 'undefined'){
		Leave(ctl,'Phone',optional)
	}else{
		Leave(ctl,'Phone')
	}
	return
}

function Leave(ctl,type,optional){//;alert('leave |' + ctl.name + '|\n value |' + ctl.value + '|\n Type |' + type + '|\n Optional |' + optional   + '|\nLastBad |' + lastBad +'|') // IF the field is invalid, returns false and writes to the error window ELSE returns true
var rePattern, re
if (lastBad && browser != 'Opera' && ! NoPopUps ){ // && browser != 'Gecko' 
	lastBad=false
	return
}
lastBad=false
if ( browser == 'Netscape4' && ctl.type == 'select-one'){ 
		ctlValue = ctl.options[ctl.selectedIndex].value
}else{
		ctlValue=ctl.value
}
while (ctlValue.charAt(ctlValue.length-1) == ' '){ ctlValue=ctlValue.substring(0, ctlValue.length-1) } // trim trailing blanks
if ((typeof optional != 'undefined'  && ctlValue == '' && optional != 'Case') || typeof type == 'undefined' ){ // optional blank field or no RegExp defined - must be OK
	if (browser != 'Netscape4')	ctl.style.backgroundColor=leaveColour;
	return 
}//if 																			(optional !=undefined && ctlValue=="")
if (CheckFlag){ // has there been an Enter field processing since the last Leave field processing??
	if (browser != 'Netscape4') ctl.style.backgroundColor=errorColour;
	rePattern=patterns[type];
	if (typeof rePattern == 'undefined'){
		alert('BUG! - No pattern has been defined for ' +type);
		return //false;
	}
	msg="";	msgCase="", msgBox="";
	if ((typeof optional != 'undefined') && (optional.indexOf('Case') != -1) && (ctlValue != '') && (ctlValue == ctlValue.toUpperCase() || ctlValue == ctlValue.toLowerCase()))	msgCase = 'It must contain both Upper and Lower Case letters.';
	re = new RegExp( rePattern, "ig" );
	if (ctlValue.match(re)==null ) msg = errMsg[type];
	// if (browser == 'Opera' && ctl.type.indexOf('text',0) >=0 && msg != '' && ctlValue.length >0) { 		msg = ''	}	
	msgBox = msg;
	if ((msg + msgCase ) != ""){  
		if (msg == '' ){
			msg = msgCase;
			msgBox = msgCase;
		}else if (msgCase != ''){
			msg += "<br>" + msgCase;
			msgBox += "\n" + msgCase;
		}
		if ((browser=="Netscape4")  || ctl.title == ""){//|| browser=="Opera"
			field=ctl.name
			field=field.replace(/_/,' ');
		}else{
			field=ctl.title
		}
		if (type == 'NOT11'){ctlValue=''}		
		ctlValue=ctlValue.replace(/</g, '&lt;'); //    ensure no confusion from a quasi html tag
		var crlf="\n"; // NB can't use pattern matching to replace a CRLF
		var i=ctlValue.indexOf(crlf);
		while (i >= 0 ){
			ctlValue=ctlValue.substr(0,i-1) + "<br>" +ctlValue.substr(i+1);
			i=ctlValue.indexOf(crlf);
		}	
		if (ctlValue.length >60){
			msg = "'" + ctlValue + "'<br>is not acceptable for <b>"+field+"</b><br>" + msg + '</p>';
			msgBox = "'" + ctlValue + "'\nis not acceptable for " + field + "\n" + msgBox + '\n\n';
		}else{
			msg = "'" + ctlValue+"' is not acceptable for <b>"+field+"</b><br>" + msg + '</p>';
			msgBox="'" + ctlValue + "' is not acceptable for "+field+"\n" + msgBox + '\n\n';
		}//if 								(ctlValue.length >60)
		CheckFlag=false // i.e. don't process the next exit from a field as it will be to the errorWindow
		if ( msg == lastMsg ) return // required for Netscape 4!
		lastMsg=msg
		problems++;
		msg="<p>" + problems + ") " + msg
		allMessages += msg
		
		lastBad=true
		if (NoPopUps){
			alert(msgBox)
		}else{
			setTimeout('WriteErrorWindow()',50) // get round window creation timing problems
		}
		return //false
	}//if																							msg !="")
	if (browser != 'Netscape4') ctl.style.backgroundColor=leaveColour;
}//if																								(CheckFlag)	
return //true;
}//function

function WriteErrorWindow(){ // for Leave function
	if (Submitted){
		msg=''
		return // don't write to the error listing as the overall listing will pick up the problem anyway and this prevents confusing messages in the errorWindow
	}
	if ( typeof submitWindow =='object' && browser=="Opera" ){
		//alert('closing submitWindow')
		submitWindow.close()
	}
	if (errorWindow == null || errorWindow.closed || browser=="Opera" ){ 
		var height=window.screen.height*0.26
		if (browser == "IE") height=window.screen.height * 0.21
		height=height / 1.1
		errorWindow=window.open('','FieldErrors','resizable,status,scrollbars,top=0,left=0,height='+height+',width=700')	
		header='<link href="' + CSS + '" rel="stylesheet" type="text/css" ><title>Field error messages</title></head><body class="errors"><h1>Errors</h1>'
		errorWindow.document.write(header);
		if (browser == 'Opera') { // as Opera does not scroll the error Window!
			errorWindow.document.write(msg + "<p><i>You must click the form before you attempt to fix errors.</i></p>");
		}else{
			errorWindow.document.write(allMessages + "<p><i>You must click the form before you attempt to fix errors.</i></p>");
		}
	}else{ // append to open errorWindow
		errorWindow.document.write(msg + "<p><i>You must click the form before you attempt to fix errors.</i></p>");
	}// if (errorWindow == null || errorWindow.closed())
	setTimeout('errorWindow.focus();',150); // bring error window to the front (oherwise visitor would not see it!
	for (var i=0; i<=9; i++){
		errorWindow.scrollBy(0, 900);	//  keep the end of the document in view
	}
}

var Submitted=false; var submissionMsg; var submissionMsgBox
function prologue(){ //for FORM validation   (typeof errorWIndow)
	Submitted = true
	submissionMsg="";problems=0,submissionMsgBox=""; firstError = null; msg=''; msgBox=''
}//function

function epilogue(){ // for FORM validation
Submitted = false
var status = true;
if (submissionMsg!=""){
	if (NoPopUps){
		if (problems==1){
			submissionMsgBox="You must fix the following problem before this data will be accepted\n" + msgBox
		}else{
			submissionMsgBox = "You must fix the following "+problems+" problems before this data will be accepted:\n" + msgBox
		}//if																					(problems==1)
		alert(submissionMsgBox);	
	}else{
		submissionMsg += "<p><i>You must click the form before you attempt to fix errors.</i></p>" 
		if ( typeof submitWindow =='object'){
			//alert('closing submitWindow')
			submitWindow.close()
		}
		if ( typeof errorWindow =='object'){
			if ( ! errorWindow.closed ){
				//alert('closing errorWindow')
				errorWindow.close()
			}
		}
		setTimeout('WriteToWindow()',200) // this is required to get around an Opera timing problem which occurs if there was an error on the field that has just been left!
	}
	status=false;
}//if																		(submissionMsg!="")
return status;
}//function

function WriteToWindow(){ // on form submission if there is an error NB must not use variable msg, rather submissionMsg to circumvent an Opera bug
	var height=window.screen.height*0.26
	if (browser == "IE") height=window.screen.height * 0.21
	height=height * problems
	submitWindow=window.open('','SubmitErrors','resizable,status,scrollbars,top=0,left=0,height='+height+',width=700')	
	header='<link href="' + CSS + '" rel="stylesheet" type="text/css" ><title>Submission error messages</title></head><body class="errors"><h1>Errors</h1>'
	submitWindow.document.write(header)
	if (problems==1){
		submitWindow.document.write("<b>You must fix the following problem before this data will be accepted:</b><br><i>You must click the form before you attempt to fix errors.</i><br><br>")
		submitWindow.document.write("<p>"+submissionMsg.substring(6,submissionMsg.length))
	}else{
		submitWindow.document.write("<b>You must fix the following "+problems+" problems before this data will be accepted :</b><br><i>You must click the form before you attempt to fix errors.</i><br><br>")
		submitWindow.document.write(submissionMsg)
	}//if																					(problems==1)
	submitWindow.document.write("</body></html>")
	submitWindow.document.close()
	setTimeout('submitWindow.focus();',150)
	problems=0
	CheckFlag=true
	//if (firstError) firstError.focus()
}// function WriteToWIndow

function Enter(ctl){// for FIELD validation
leaveColour='white';
if (browser != 'Netscape4'){
	ctl.style.backgroundColor=highlight;
	ctl.style.color='black';
}
CheckFlag=true;
//changed=false
}//function 													Enter()


/*
var changed=false
function Updated(){ 
leaveColour = markChanged
changed = true
return
}//	function Updated
*/
