// <[CDATA[
/**
 * JavaScript validation functions for sitewide use
 * Copyright © 2002 Cillay Limited, London, UK
 *
 * @author		Ian Cillay
 * @version     0.91, 23 July 2002
 * @see			<http://www.cillay.com/>
 */

//-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------

// Real-time validation by modifying form element values?
var INPUTMASK = false;
var errorOutput = "";

var LANG = "en"; // this line checked the dir path to see if we were inside the german or english dir, and set the translations accordingly - not required here, so short-circuited.

//-----------------------------------------------------------------------------
// Final validation functions (to be called by ONSUBMIT="return validate(this)"
//-----------------------------------------------------------------------------

// Validate function executes on submit, checking entire form
function validate(form)
{

	var error = "";
	var blank = "";
	var resetPassword = false;
	var wordSearch;
	
	var doNothing = false;
	
	for (var i = 0; i < form.elements.length; i++) {

		var element = form.elements[i];
		
		doNothing = false;
		
		if (i > 0) {
			var repeated = false;
			for (var j = i - 1; j >= 0; j--) {
				if (form.elements[i].name == form.elements[j].name) {
					repeated = true;
					break;
				}
			}
			if (repeated) continue;
		}
		
		var field = false;
		var name
		var value = "";
		// Determine what type of field it is
		for (var check in validation) {
			for (var c in validation[check]) {
				if (validation[check][c] && validation[check][c].name == form.elements[i].name) {
					name = c;
					field = validation[check][c];
					break;
				}
			}
		}
		if (!field || field == null) continue;
		
		if (self.pageCount && field.lastPageOnly && (Number(form.page.value) < Number(pageCount))) continue;
		
		var value = (element.options && element.type.charAt(0)=="s") ? element.options[element.selectedIndex].value : element.value;
		if (value == "" && element.options && element.selectedIndex > 0) {
			value = element.options[element.selectedIndex].text;
		}
		
		if (element.type == "checkbox" || element.type == "radio") {
			value = (atLeastOneChecked(element)) ? element.type : "";
		}
		
		// Required fields cannot be left blank
		if (field.required && value == "" && !form.lenient) {
			blank += " " + name.replace(/_/g, " ") + ",";
			var msg  = res[LANG]["the"] + " " + name.replace(/_/g, " ") + " " + res[LANG]["field"] + " ";
			msg += res[LANG]["nonblank"];
			prohibit(element, msg);
			continue;
		}
		//else prohibit(element, null);
		
		if (!field.type) continue;
		
		// Perform pattern matches on fields with required validity checks
		switch (field.type.toUpperCase()) {
			//-----------------------------------------------------------------
			case "AN":
				// Alphanumeric (spaces allowed)
				var re = /^[A-Z0-9\-\s]+$/i;
				var str = element.value;
				if (!re.test(str) && element.value != "") {
					error  = res[LANG]["the"] + "" + name + " " + res[LANG]["field"] + " ";
					error += (!(/^[A-Z\d]+$/i).test(str)) ? res[LANG]["badchars"] : res[LANG]["invalid"];
					prohibit(element, error);
				}
				break;
			//-----------------------------------------------------------------
			case "FN":
				// Full name - alphanumeric (spaces, apostrophes, and full stops allowed)
				var re = /^[A-Z0-9\s\'\.]+$/i;
				var str = element.value;
				if (!re.test(str) && element.value != "") {
					error  = "The " + name + " field ";
					error += (!(/^[A-Z\d]+$/i).test(str)) ? res[LANG]["badchars"] : res[LANG]["invalid"];
					prohibit(element, error);
				}
				break;
			//-----------------------------------------------------------------
			case "IN":
				// Initial - strict alphabetic, up to 6 characters
				var re = /^[A-Z\s]{1,6}$/i;
				var str = element.value;
				if (!re.test(str) && element.value != "") {
					error  = "The " + name + " field ";
					error += (!(/^[A-Z\d]+$/i).test(str)) ? res[LANG]["badchars"] : res[LANG]["invalid"];
					prohibit(element, error);
				}
				break;
			//-----------------------------------------------------------------
			case "AD":
				// Address - alphanumeric plus other likely characters
				var re = /^[A-Z0-9\s\#\.\,\/\&\(\)\:\-\']+$/i;
				var str = element.value;
				if (!re.test(str) && element.value != "") {
					error  = "The " + name + " field ";
					error += (!(/^[A-Z\d]+$/i).test(str)) ? res[LANG]["badchars"] : res[LANG]["invalid"];
					prohibit(element, error);
				}
				break;
			//-----------------------------------------------------------------
			case "NUM":
				// Numeric - numerals and mathemtical signs only
				var re = /^[\d\-\+\,\.]+$/i;
				var str = element.value;
				if (!re.test(str) && element.value != "") {
					error  = "The " + name + " field ";
					error += (!(/^[A-Z\d]+$/i).test(str)) ? res[LANG]["badchars"] : res[LANG]["invalid"];
					prohibit(element, error);
				}
				break;
			//-----------------------------------------------------------------
			case "UN":
				// Username - alphanumeric, between 6 and 31 characters in length
				var bounds = new Array(6,30);
				var re = new RegExp("^[A-Za-z0-9\\_\\.\\@\\-\\+\\&\\:\\;]{" + bounds[0] + "," + bounds[1] + "}$");
				var str = element.value;
				if (!re.test(str) && element.value != "") {
					error = "The " + name + " field ";
					if (str.length < bounds[0] || str.length > bounds[1]) {
						error += (str.length < bounds[0]) ? "must contain at least " + bounds[0] + " characters" : "cannot be longer than " + bounds[1] + " characters";
					}
					else {
						var re = /^[A-Z\d]+$/i;
						error += (!re.test(str)) ? res[LANG]["badchars"] : res[LANG]["invalid"];
					}
					prohibit(element, error);
				}
				break;
			//-----------------------------------------------------------------
			case "PW":
				// Passwords - alphanumeric, between 6 and 16 characters in length
				var bounds = new Array(6,16);
				var re = new RegExp("^[A-Za-z0-9]{" + bounds[0] + "," + bounds[1] + "}$");
				var str = element.value;
				
				if (!re.test(str) && element.value != "") {
					error = "The " + name + " field ";
					if (str.length < bounds[0] || str.length > bounds[1]) {
						error += (str.length < bounds[0]) ? "must contain at least " + bounds[0] + " characters" : "cannot be longer than " + bounds[1] + " characters";
					}
					else {
						error += (!re.test(str)) ? res[LANG]["badchars"] : res[LANG]["invalid"];
					}
					prohibit(element, error);
					break;
				}
			//-----------------------------------------------------------------
			case "AL":
				// Alias - Alphanumeric (spaces allowed)
				var re = /^[A-Z0-9\s]+$/i;
				var str = element.value;
				if (!re.test(str) && element.value != "") {
					error  = "The " + name + " field ";
					error += (!(/^[A-Z\d]+$/i).test(str)) ? res[LANG]["badchars"] : res[LANG]["invalid"];
					prohibit(element, error);
				alert('You can not use sybols (e.g. & or /) here.')
				return false;
				}
			
			//-----------------------------------------------------------------
				
				// If there's a password confirmation field, make sure the passwords match!
				if (i < form.elements.length - 1) {   //if the password field is not at the end of the form
					var cnt = new Array();
					for (var k = i; k < form.elements.length; k++) {
					if(form.elements[k].type == "password"){cnt[cnt.length] = form.elements[k]}
					}
					if(cnt.length > 2){break;}
					for (var j = 1; j <= 2; j++) {
						if ((form.elements[i + j].name.substring(0, name.length) == name) || (form.elements[i + j].type == "password" && form.elements[i + j].name.indexOf("ver") != -1)) {
							if (element.value != form.elements[i + j].value) {
								//element.onfocus = form.elements[i + j].onfocus = new Function("this.value=''");
								//element.onblur  = form.elements[i + j].onblur  = new Function("this.onfocus=null");
								element.value = "";
								form.elements[i + j].value ="";
								resetPassword = true;
								error = "These passwords do not match";
								prohibit(element, error);
								prohibit(form.elements[i + j], error);

								// Change the error message again for the alert box
								error  = "Sorry, the two passwords you\n";
								error += "have entered do not match";
							}
							break;break;
						}
					}
				}
				break;
			//-----------------------------------------------------------------
			case "PC":
				// Postcode validation based upon that of QAS QuickAddress 3
				var re = /^[A-Z]{1,2}(\d{1,3}|\d[A-Z]\d)[ABDEFGHJLNPQRSTUWXYZ]{2}$/;
				var str = element.value.replace(/\s/g, "").toUpperCase();
				if (!re.test(str) && element.value != "") {
					error = "The " + name + " field ";
					error += (!(/^[A-Z\d]+$/i).test(str)) ? res[LANG]["badchars"] : res[LANG]["invalid"];
					prohibit(element, error);
				}
				break;
			//-----------------------------------------------------------------
			case "EM":
				// Email address check based on RFC 821 and RFC 822
				var re = /^[\w\.\_\-]+[A-Z0-9]\@[A-Z0-9][A-Z0-9\-]*[A-Z0-9]+\.[A-Z0-9\.]+[A-Z]$/i;
				if (!re.test(element.value) && element.value != "") {
					error = "The " + name + " field ";
					error += (!(/^[\w\.\@\_]+$/).test(element.value)) ? res[LANG]["badchars"] : res[LANG]["invalid"];
					prohibit(element, error);
				}
				break;
			//-----------------------------------------------------------------
			case "PH":
				// Telephone numbers just a simple numerals-only check
				// Allowable superfluous characters: " ()-+"
				var re = /^\d+$/i;
				var str = element.value.replace(/[ \s\(\)\-\+]/g, "");
				if (!re.test(str) && element.value != "") {
					error = "The " + name + " field ";
					error += (!((/^\d+$/).test(str))) ? res[LANG]["badchars"] : res[LANG]["invalid"];
					prohibit(element, error);
				}
				break;
			//-----------------------------------------------------------------
			case "DS":
				// Split date
				if (!checkDate(element) && element.value != "") {
					error = "The " + name + " field contains an invalid date";
					prohibit(element, error);
				}
				break;
			//-----------------------------------------------------------------
			case "DY":
				if (!validateDate(element.value) && element.value != "") {
					error = "This date is invalid";
					prohibit(element, error);
				}
				break;				
			//-----------------------------------------------------------------
			case "CC":
				// Credit card - numeric, between 12 and 19 characters in length
				var bounds = new Array(12,19);
				var re = new RegExp("^\\d{" + bounds[0] + "," + bounds[1] + "}$");
				element.value = element.value.replace(/[\s]/g, "");
				var str = element.value
				if (!re.test(str) && element.value != "") {
					error = "The " + name + " field ";
					if (str.length < bounds[0] || str.length > bounds[1]) {
						error += (str.length < bounds[0]) ? "must contain at least " + bounds[0] + " characters" : "cannot be longer than " + bounds[1] + " characters";
					}
					else {
						error += (!re.test(str)) ? res[LANG]["badchars"] : res[LANG]["invalid"];
					}
					prohibit(element, error);
				}
				break;
			//-----------------------------------------------------------------
		}
	}
	
	// If nothing here we're supposed to check then get the hell out of Dodge!
	if (doNothing) return true;
	
	// Report all blank fields on a single line
	if (blank != "") {
		blank = blank.substring(0, blank.length - 1);	// Remove trailing comma
		var plural = "";
		if (blank.indexOf(",") != -1) {
			blank = blank.substring(0,blank.lastIndexOf(",", blank.length)) + " and" + blank.substring(blank.lastIndexOf(",") + 1, blank.length);
			plural = "s";
		}
	}
	
	// If an error exists
	var pass = true;
	if (error != "" || blank != "") {
		// Report the error via alert box and return false
		//var warning = "Please ensure that all fields marked\n";
		//warning += "with a " + String.fromCharCode(8216) + "*" + String.fromCharCode(8217);
		//warning += " have been filled in and that\n";
		//warning += "all fields have been entered correctly";
		
		var warning = "";
		warning += res[LANG]["title"];
		warning += errorOutput;

		if (blank == "" && field.type == "PW") {warning = error;resetPassword.value = "";}

		(typeof window.vbAlert != "undefined") ? vbAlert(warning, 16, res[LANG]["the"] + " " + res[LANG]["form"] + " " + res[LANG]["incomplete"]) : alert(warning);
		errorOutput = " ";	
		pass = false;
	}
	return pass;
}

function checkDate(element, format)
{
	var format = (format) ? format : /(\d{1,2})(\/|-)(\d{1,2})(\/|-)(\d{4})/;
	var value = (element.value.length >= 8) ? element.value : "1/" + element.value;
	var valid = Boolean(format.test(value));
	value = value.replace(format, pad(RegExp.$1, 2) + "/" + pad(RegExp.$3, 2) + "/" + RegExp.$5);
	return (valid) ? validateDate(value) : false;
}

function validateDate(expr) {

	// Function to validate a date expression where day and month fields are 2-digit
	// and year field is 4-digit

	var calendar = "JanFebMarAprMayJunJulAugSepOctNovDec";
	
	var str = expr.replace(/\D/g,"");
	var D = Number(str.substring(0,2));
	var M = Number(str.substring(2,4)) - 1;
	var Y = Number(str.substring(4, str.length));
	var dateStr = calendar.substring((M * 3), ((M * 3) + 3)) + ' ' + D + ', ' + Y + ' 00:00:00';
	var uDate = (new Date(dateStr)).valueOf();
	var sDate = (new Date(Y, M, D, 0, 0, 0, 0)).valueOf();
	
	var passDate = (uDate == sDate);
	
	var daysInMonth = 31;
	switch (M + 1) {
		case 4:
		case 6:
		case 9:
		case 11:
			daysInMonth = 30;
			break;
		case 2:
			daysInMonth = ((Y % 4) == 0) ? 29 : 28;
	}
	
	var thisYear = (new Date()).getFullYear();
	passDate = (passDate && ( (sDate < (new Date(thisYear + 3, 1, 1)).valueOf() ) && (Y >= thisYear - 110) ));
	passDate = (passDate && (M < 12) && (D <= daysInMonth));
	return passDate;
}

function prohibit(element, violation)
{
	var name = element.name.substring(0, (element.name.indexOf("*") + element.name.indexOf("!") + 1));
	if (violation != null) errorOutput += '\n'+violation+'.';
}


// Takes a number num and pads it to n spaces using leading zeros
function pad(num, n)
{
	return ("0").repeat(n - String(num).length) + String(num);
}
String.prototype.repeat = function(n)
{
	chars = String(this);
	var str = new String();
	for (var i = 0; i < n; i++) {
		str += chars;
	}
	return str;
}

function require(name, type, lastPageOnly)
{
	return (new Field(name, type, true, lastPageOnly));
}
function verify(name, type)
{
	return (new Field(name, type, false));
}
function Field(name, type, required, lastPageOnly)
{
	this.name = name;
	this.type = type;
	this.required = required;
	this.lastPageOnly = lastPageOnly;
	return this;
}

function atLeastOneChecked(checkbox)
{
	// Return whether the number checked is at least 1
	return minChecked(checkbox, 1);
}

function minChecked(checkbox, minimum)
{
	// Let minimum be optional and default to 1
	minimum = (!minimum) ? 1 : Number(minimum);
	
	// If passed an array rather than an element (IE), convert it
	if (typeof checkbox.length == "number") checkbox = checkbox[0];
	
	// Set a counter to track the number of checked elements
	var numChecked = 0;
	
	// Step through each of the elements in the form
	for (var i = 0; i < checkbox.form.elements.length; i++) {
		
		// Check to see if element is in same group by having same name
		var inGroup = (checkbox.form.elements[i].name == checkbox.name);
		
		// And if it's the same type
		inGroup &= (checkbox.form.elements[i].type == checkbox.type);
		
		// If the elements is in the same group and it is checked
		if (inGroup && checkbox.form.elements[i].checked) {
		
			// Increment the counter
			numChecked++;
		}
	}
	
	// Return whether the number checked is at least the minimum
	return (numChecked >= minimum);
}

if (document.all && window.clientInformation && window.clientInformation.platform == "Win32") {
	document.writeln('<script language="VBScript">');
	document.writeln('Function vbAlert(p, b, m)');
	document.writeln('  vbAlert = MsgBox(p, b, m)');
	document.writeln('End Function');
	document.writeln('</script>');
}

//-------------------------------------------------------------------------------------

/* KEY

AN: Alphanumeric (spaces allowed)
FN: Full name - alphanumeric (spaces, apostrophes, and full stops allowed)
IN: Initial - strict alphabetic, up to 6 characters
AD: Address - alphanumeric plus other likely characters
NUM: Numeric - numerals and mathemtical signs only
UN: Username - alphanumeric, between 6 and 31 characters in length
PW: Passwords - alphanumeric, between 6 and 16 characters in length
AL: Alias - Alphanumeric (spaces allowed)
PC: Postcode validation based upon that of QAS QuickAddress 3
EM: Email address check based on RFC 821 and RFC 822
PH: Telephone numbers just a simple numerals-only check. Allowable superfluous characters: " ()-+"
DS: Split date
DY: ?
CC: Credit card - numeric, between 12 and 19 characters in length

below: first instant of e.g. "title" is the text which appears on the alert, and can be anything. Second instance is the name attribute of the form field, and should be the same as the form.

*/

var res = {
	"en": {
		"the"        : "The",
		"form"       : "form",
		"field"      : "field",
		"title"      : "Sorry, you have not completed the form correctly:",
		"incomplete" : "is incomplete",
		"nonblank"   : "cannot be left blank",
		"minlength"  : "must contain at least n characters",
		"maxlength"  : "cannot contain more than n characters",
		"badchars"   : "contains invalid characters",
		"invalid"    : "is invalid",
		"baddate"    : "contains an invalid date"
	}
}

var validation;

if (LANG == "en") {
	validation = {
		"details": {
			"e-mail address" : require("email", "em"),
			"name" : require("name", "fn"),
			"telephone number" : require("telephone", "ph"),
			"address" : require("address", "ad"),
			"message" : require("message"),
			"price list" : require("pricelist")
		},
		"quote": {
			"e-mail address" : require("email", "em"),
			"name" : require("name", "fn"),
			"telephone number" : require("telephone", "ph"),
			"address" : require("address", "ad"),
			"message" : require("message"),
			"company name" : require("company")
		}
	}
}
