/***********************************************************************************
 * File: form_validation.js
 * Description:
 *   Validation functions for forms
 *   Example of usage:
 *
 *   function validate(form) {
 *     // Field name, Caption
 *     checkString(form.firstName, "First Name");
 *     // Field name, Caption, Required (true | false)
 *     checkEmail(form.email, "Email", true);
 *     // Field name, Caption, Required (true | false)
 *     checkDate(form.address3, "Date Of Birth", true);
 *
 *     // Displays error and returns false if an error occurred
 *     return checkError();
 *   }
 *
 *   ...
 *
 *   <form .... onsubmit="return validate(this);">
 *
 ***********************************************************************************/

/***********************************************************************************
 * Get browser version
 ***********************************************************************************/
 
	var br_dom = (document.getElementById) ? true : false;
   var br_ns4 = (document.layers) ? true : false;
   var br_ie = (document.all) ? true : false;
   var br_ie4 = br_ie && !br_dom;
   var br_mac = (navigator.appVersion.indexOf("Mac") != -1);
	var br_ie4Mac = br_ie4 && br_mac;
	var br_opera = (navigator.userAgent.indexOf("Opera")!=-1);
	var br_konqueror = (navigator.userAgent.indexOf("Konqueror")!=-1);

/***********************************************************************************
 * Helper functions
 ***********************************************************************************/

// Check if item is valid
function checkItem(item, field) {
	if(item == null) {
		addError("Script error: " + field + " item is invalid", null);
		return false;
	}
	return true;
}

// Check if item contains only valid characters
function checkCharSet(string, charSet) {
	var i = 0;
	while(i < string.length && charSet.indexOf(string.charAt(i)) >= 0)
		i++;
	
	return (i == string.length);
}

// Get item value (check if dropdown or text field)
function getItemValue(item) {
	if(!checkItem(item))
		return null;

	if(item.type == "select")
		return item.options[item.selectedIndex].value;
	else
		return item.value;
}

// Return difference in years between two dates
function dateYearDiff(date1, date2, range) {
	if(date1 == null || date2 == null)
		return null;

	// Get differences
	var diffYears = parseInt(date2.getFullYear() - date1.getFullYear());
	var diffMonths = parseInt(date2.getMonth() - date1.getMonth());
	var diffDays = parseInt(date2.getDate() - date1.getDate());
	
	// Return difference
	return (diffMonths < 0 || (diffMonths == 0 && diffDays < 0)) ? diffYears - 1 : diffYears;
}


// Return difference in years between two dates
function dateDaysDiff(date1, date2, range) {
	if(date1 == null || date2 == null)
		return null;

	//var daysInMonth = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
	
	// Get differences
	var diffMili = parseInt(date2.valueOf() - date1.valueOf());
	
	// Return difference
	return parseInt(diffMili / (1000 * 60 * 60 * 24));
}

// Return difference between two dates (l=mili, s=sec, n=min, h=hours, d=days (default), m=months, y=years)
function dateDiff(date1, date2, range) {
	if(date1 == null || date2 == null)
		return null;

	//var daysInMonth = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
	
	// Get differences
	var diffYears = parseInt(date2.getFullYear() - date1.getFullYear());
	var diffMonths = parseInt(date2.getMonth() - date1.getMonth());
	var diffDays = parseInt(date2.getDate() - date1.getDate());
	var diffMili = parseInt(date2.valueOf() - date1.valueOf());
	
	if(range == null)
		range = "d";
		
	// Return difference
	var div = 1;
	switch(range) {
	case "s":
		div = 1000;
	case "n":
		div *= 60;
	case "h":
		div *= 60;
	case "d":
		div *= 24;
	case "l":
		return parseInt(diffMili / div);
	case "m":
		// Not implemented yet
		return 0;
	case "y":
		return (diffMonths < 0 || (diffMonths == 0 && diffDays < 0)) ? diffYears - 1 : diffYears;
	}
	return null;
}

//Returns true or false depending on whether the end date is before the startdate
function validDateRange(startDate, endDate, field) {
var one_day=1000*60*60*24;
field = field.replace(":", "");
field = field.replace("?", "");
	if ((endDate - startDate)/(one_day) < 0) {
		return addError(field + " should be after the Start date");
	} 
	return true;
}

// Checks for a valid date
function isDate(date) {
	var valid = true;
	
	var i = date.indexOf('/');
	var i2 = date.indexOf('/', i + 1);
	
	day = date.substring(0, i);				// day
	month = date.substring(i + 1, i2);		// month
	year = date.substring(i2 + 1);			// year
	
	if(	isNaN(day) || isNaN(month) || isNaN(year) ||
			day < 1 || day > 31 || day.length > 2 || day.length < 1 ||
			month < 1 || month > 12 || month.length > 2 || month.length < 1 ||
			year < 0 || year.length > 4 || year.length < 2)
		return false;

	var mon = parseInt(month, 10);
	
	// April, June, September, November only 30 days
	if(mon == 4 || mon == 6 || mon == 9 || mon == 11) {
		if(parseInt(day, 10) > 30)
			valid = false;
	}
	else if(mon == 2) {
		if(parseInt(day, 10) > (28 + (parseInt(year, 10) % 4 == 0 && parseInt(year, 10) % 400 != 0 ? 1 : 0)) )
			valid = false;
	}
	else if(parseInt(day, 10) > 31)
		valid = false;
	
	return valid;
}

// Returns true if year is a leap year
function isLeapYear(year) {
	return (year % 4 == 0 && year % 400 != 0);
}

// Converts an item group to a date object
function itemGroupToDate(form, itemPrefix) {
	var day = getItemValue(form.elements[itemPrefix + "_day"]);
	var month = getItemValue(form.elements[itemPrefix + "_month"]);
	var year = getItemValue(form.elements[itemPrefix + "_year"]);

	if(day == null || month == null || year == null || !isDate(day + "/" + month + "/" + year))
		return null;

	return new Date(year, month - 1, day);
}

// Trim a string
function trim(str)
{
	var i = 0, j = str.length - 1;
	while(i < j && str.charAt(i) == ' ')
		i++;
	while(j > i && str.charAt(j) == ' ')
		j--;
	
	return str.substring(i, j + 1);
}

/***********************************************************************************
 * Error functions
 ***********************************************************************************/

// Global validation variable
var validationErrorArray = null;

// Create an error array
function createErrorArray() {
	return new Array();
}

// Add an error
function addError(errorMsg, item, errorArray, skip) {
	if(skip)
		return false;
	
	if(errorArray == null) {
		if(validationErrorArray == null)
			validationErrorArray = createErrorArray();
		
		errorArray = validationErrorArray;
	}

	var i = errorArray.length;
	errorArray.length += 2;
	errorArray[i] = errorMsg;
	errorArray[i + 1] = item;
	
	return false;
}

// Clear any errors
function clearErrors(errorArray) {
	if(errorArray == null)
		validationErrorArray = null;
	else {
		if(validationErrorArray == errorArray)
			validationErrorArray = null;
		errorArray = null;
	}
}

// Returns number of errors
function getErrorCount(errorArray) {
	if(errorArray == null)
		errorArray = validationErrorArray;
	
	if(errorArray == null)
		return 0;
		
	return errorArray.length;
}

// Check and display error if any
function checkError(errorArray) {
	if(errorArray == null)
		errorArray = validationErrorArray;

	if(errorArray != null && errorArray.length > 0) {
		var i, focus,
		msg = "Some fields were not entered correctly:\n\n";
		
		// Add each error to output
		for(i = 0; i < errorArray.length; i += 2) {
			msg += errorArray[i] + "\n";
			
			if(focus == null && errorArray[i + 1] != null)
				focus = errorArray[i + 1];
		}

		clearErrors(errorArray);

		alert(msg);
		//if(focus != null)
			//focus.focus();
		return false;
	}
	return true;
}

/***********************************************************************************
 * Field validation functions
 ***********************************************************************************/

// Author:			MM
// Date:				Feb 2003
// Description:	Check for apostrophes in a filename
function checkFileName(item, field, min, max) {
	if(!checkString(item, field, min, max))
		return false;

	var length = trim(item.value).length;
	
	// Check for apostrophes in the filename
	if (item.value.indexOf("'") != -1) {
		return addError(field + " must not contain apostrophes.", item, null, field == null);
	}
}


// Check if a field is empty
function checkString(item, field, min, max, prefill) {
	if(!checkItem(item, field))
		return false;
			
	var length = trim(item.value).length;
	field = field.replace(":", "");
	field = field.replace("?", "");
	if(min == null) 
		min = 1;
	if(length < min && min == 1 && max == null)
		return addError(field + " is required.", item, null, field == null);
	else if(length < min && max == null)
		return addError(field + " must be at least " + min + " characters long.", item, null, field == null);
	else if(length < min || (max != null && length > max))
		return addError(field + " must be between " + min + " and " + max + " characters long.", item, null, field == null);
	else if(item.value == prefill && min == 1)
		return addError(field + " is required.", item, null, field == null);
	return true;
}



// Check if the first item is selected
function checkDropdown(item, field) {
	if(!checkItem(item, field))
		return false;
	field = field.replace(":", "");
	field = field.replace("?", "");
	if(item.selectedIndex == 0)
		return addError(field + " must be selected.", item, null, field == null);		
	return true;
}

// Check if at least min items are selected
function checkMultiDropdown(item, field, min, max) {
	if(!checkItem(item, field))
		return false;
	field = field.replace(":", "");
	field = field.replace("?", "");
	var count = 0;
	
	for(var i = 0; i < item.options.length; i++) {
		if(item.options[i].selected)
			count++;
	}
	
	if(count < min || (max != null && count > max))
		return addError(field + " must have at least " + min + " item" + (min > 1 ? "" : "s") + " selected", item, null, field == null);
	return true;
}

// Check that something has been added to a textbox thingy
function checkAdded(item, field){
	if(!checkItem(item,field))
		return false;
	field = field.replace(":", "");
	field = field.replace("?","");
	if (item.options.length ==1)
		return addError(field + " must have at least one number added", item, null, field==null);
	return true;
}

// Check for a valid number from character set
function checkNumberCharSet(item, field, required, charSet) {
	if(!checkItem(item, field))
		return false;

	var number = item.value;
	field = field.replace(":", "");
	field = field.replace("?", "");
	if(required && number == "")
		return addError(field + " is required.", item);
	else {
		if(!checkCharSet(number, charSet)) // || isNaN(number))
			return addError(field + " may only contain valid numbers.", item, null, field == null);
		return true;
	}
}


// Check for a valid number from character set
function checkLetterCharSet(item, field, required, charSet) {
	if(!checkItem(item, field))
		return false;

	var number = item.value;
	field = field.replace(":", "");
	field = field.replace("?", "");
	if(required && number == "")
		return addError(field + " is required.", item);
	else {
		if(!checkCharSet(number, charSet)) // || isNaN(number))
			return addError(field + " may only contain letters.", item, null, field == null);
		return true;
	}
}

//Check for letters only
function checkLetters(item, field, required) {
	field = field.replace(":", "");
	field = field.replace("?", "");
	return checkLetterCharSet(item, field, required, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzfSOZsozYÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ' \t\r\n\f");
}


// Check for a valid number from character set
function checkLetterNumberCharSet(item, field, required, charSet) {
	if(!checkItem(item, field))
		return false;

	var number = item.value;
	field = field.replace(":", "");
	field = field.replace("?", "");
	if(required && number == "")
		return addError(field + " is required.", item);
	else {
		if(!checkCharSet(number, charSet)) // || isNaN(number))
			return addError(field + " may only contain letters or numbers.", item, null, field == null);
		return true;
	}
}

//Check for letters and numbers only
function checkLettersAndNumbers(item, field, required) {
	field = field.replace(":", "");
	field = field.replace("?", "");
	return checkLetterNumberCharSet(item, field, required, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzfSOZsozYÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ' \t\r\n\f");
}

// Check for a valid number
function checkNumber(item, field, required) {
	field = field.replace(":", "");
	field = field.replace("?", "");
	return checkNumberCharSet(item, field, required, "0123456789.,");
}

//Check for a valid number and length
function checkNumberAndLength(item, field, required, length) {
	
	checkNumber(item, field, required);
	
	if (item.value.length!=length)
		return addError(field + " must contain " + length + " digits.");
	
}

//Check for a valid number and length
function checkLength(item, field, length) {
	if (item.value.length!=length)
		return addError(field + " must contain " + length + " characters.");
}

// Check for a valid currency number
function checkCurrency(item, field, required) {
	field = field.replace(":", "");
	field = field.replace("?", "");
	if (!checkNumberCharSet(item, field, required, "0123456789.,")) 
		return false;
}

// Check for a valid phone number
function checkPhone(item, field, required, other,prefill) {
	//alert(prefill + "---" + item.value);
	field = field.replace(":", "");
	field = field.replace("?", "");
	if(item.value == prefill && required)
		return addError(field + " is required.", item, null, field == null);
	else if (item.value == prefill && !required) 
		return true;
	else
		return checkNumberCharSet(item, field, required, "0123456789/-+ ");
	
}

// Check for a valid phone number
function checkAlphaNum(item, field, required) {
	if(!checkItem(item, field))
		return false;
	field = field.replace(":", "");
	field = field.replace("?", "");
	if(required && item.value == "")
		return addError(field + " is required.", item);
	
	if(checkCharSet(item.value, "0123456789"))
		return addError(field + " must contain letters.", item);
}

// Check for a valid email
function checkEmail(item, field, required) {
	if(!checkItem(item, field))
		return false;
	field = field.replace(":", "");
	field = field.replace("?", "");
	var email = trim(item.value);
	
	if(required && email == "")
		return addError(field + " is required.", item, null, field == null);
	else if(!required && email == "")
		return true;

	var reg1 = /(@.*@)|(\.\.)|(@\.)|(\.@)|(^\.)/; // not valid
	var reg2 = /^.+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,3}|[0-9]{1,3})(\]?)$/; // valid
	if (!reg1.test(email) && reg2.test(email))	// if syntax is valid	
		return true;

	return addError(field + " requires a valid e-mail address.", item, null, field == null);
}


function checkOrderNumber(number, field)
{//
	var reg1 = /^((\d){6})(([a-zA-Z]){1})$/;
	if (reg1.test(number.value))
		return true
	return addError(field + " requires an entry in the form '123456A'");
}


// Check for a valid web address
function checkWebsite(item, field, required) {
	if(!checkItem(item, field))
		return false;

	var website = trim(item.value);
	field = field.replace(":", "");
	field = field.replace("?", "");
	if(required && website == "")
		return addError(field + " is required.", item, null, field == null);
	else if(!required && website == "")
		return true;

	var reg1 = /(@.*@)|(\.\.)|(@\.)|(\.@)|(^\.)/; // not valid
	var reg2 = /^.+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,3}|[0-9]{1,3})(\]?)$/; // valid
	if (!reg1.test(website) && reg2.test(website))	// if syntax is valid	
		return true;

	return addError(field + " requires a valid e-mail address.", item, null, field == null);
}

// Check for a valid date
function checkDate(item, field, required) {
	if(!checkItem(item, field))
		return false;

	if(!required && item.value == "")
		return true;
		
	if(!isDate(item.value))
		return addError(field + " requires a valid date.", item, null, field == null);
	return true;
}

// Check for a valid date group (assumes each field have suffixes _day, _month, _year)
function checkDateGroup(form, itemPrefix, field, required) {
	return checkDateGroupSep(	
		form.elements[itemPrefix + "_day"], 
		form.elements[itemPrefix + "_month"], 
		form.elements[itemPrefix + "_year"], field, required);
}

// Check for a valid date group
function checkDateGroupSep(itemDay, itemMonth, itemYear, field, required) {
	if(!checkItem(itemDay, field) || !checkItem(itemMonth, field) || !checkItem(itemMonth, field))
		return false;
	
	var day = getItemValue(itemDay);
	var month = getItemValue(itemMonth);
	var year = getItemValue(itemYear);
	
	if(!required && day == "" && month == "" && year == "")
		return true;

	if(!isDate(day + "/" + month + "/" + year))
		return addError(field + " requires a valid date.", itemDay, null, field == null);
	return true;
}

// Check if a checkbox is selected
function checkCheckbox(item, field) {
	if(!checkItem(item, field))
		return false;
	field = field.replace(":", "");
	field = field.replace("?", "");
	if(!item.checked)
		return addError(field + " needs to be checked.", item, null, field == null);
	return true;
}


// Check if a checkbox is selected
function checkRadiobox(items, field) {
	field = field.replace(":", "");
	field = field.replace("?", "");
	if(checkRadioboxItem(items) == -1)
		return addError(field + " needs to be selected.", item, null, field == null);
	return true;
}

// Check if a checkbox is selected
function checkRadioboxItem(items) {
	if(!checkItem(items))
		return -1;

	var i = 0;
	while(i < items.length && !items[i].checked)
		i++;
	return (i == items.length) ? -1 : i;
}

//Checks if a field begins with one of the prefixes included in the prefix list
function checkPrefix(item, field, prefixList) {
	
	//Build error string
	var errorMsg = field + " must begin with ";		
	
	for (var i=0; i<prefixList.length; i++) {
			
		if (item.value.substring(0,3)==prefixList[i])
			return true;
			
		if (i==(prefixList.length-1))
			errorMsg = errorMsg + " or " + prefixList[i];
		
		else if (i==(prefixList.length-2)) 
			errorMsg = errorMsg + prefixList[i];
		
		else errorMsg = errorMsg + prefixList[i] + ", ";
		
	}
	
	return addError(errorMsg);
		
}

/***********************************************************************************/

// Check for a valid password
function checkPassword(item, field, required)
{
  var charSet = "";

  if(!checkItem(item, field))
    return false;

  if(required && item.value == "")
    return addError(field + " is required.", item);

  if(!checkCharSet(item.value, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.£$*@#"))
    return addError(field + " may only contain letters and numbers and valid special characters (£$*@#)", item);

  var hasNumbers = false;
  charSet = "0123456789";
  for(var i=0;i<item.value.length;i++)
    if(charSet.indexOf(item.value.charAt(i)) >= 0)
      hasNumbers = true;

  var hasLetters = false;
  charSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.£$*@#";
  for(var i=0;i<item.value.length;i++)
    if(charSet.indexOf(item.value.charAt(i)) >= 0)
      hasLetters = true;

  if(!hasNumbers || !hasLetters || item.value.length < 8)
    return addError(field + " must be a combination of letters and digits with at least 8 characters.", item);

  return true;
}


function checkUsername(item, field, required)
{
  var charSet = "";

  if(!checkItem(item, field))
    return false;

  if(required && item.value == "")
    return addError(field + " is required.", item);

  if(!checkCharSet(item.value, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.£$*@#"))
    return addError(field + " may only contain letters and numbers and valid special characters.", item);

  if(item.value.length < 8)
    return addError(field + " must be at least 8 characters.", item);
 
  return true;
}