/***********************************************************************************
 * 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) {
	//alert(date1.getFullYear)
	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;
}

// 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) {
	if(!checkItem(item, field))
		return false;
	
	var length = trim(item.value).length;
	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);
	return true;
}



// Check if the first item is selected
function checkDropdown(item, field) {
	if(!checkItem(item, field))
		return false;

	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;

	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 for a valid number from character set
function checkNumberCharSet(item, field, required, charSet) {
	if(!checkItem(item, field))
		return false;

	var number = item.value;
	
	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;
	
	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) {
	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;
	
	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) {
	return checkLetterNumberCharSet(item, field, required, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzfSOZsozYÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ' \t\r\n\f");
}

// Check for a valid number
function checkNumber(item, field, required) {
	return checkNumberCharSet(item, field, required, "0123456789.,' '");
}

// Check for a valid currency number
function checkCurrency(item, field, required) {
	if (!checkNumberCharSet(item, field, required, "0123456789.,")) 
		return false;
}

// Check for a valid phone number
function checkPhone(item, field, required) {
	return checkNumberCharSet(item, field, required, "0123456789/-+ ");
}

// Check for a valid phone number
function checkAlphaNum(item, field, required) {
	if(!checkItem(item, field))
		return false;

	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;

	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);
}

// 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;

	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) {
	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;
}

	function validateDates(fromYear, toYear, fromMonth, toMonth, dateSet){
		if(fromYear == toYear){
			//Check Months
			month1 = getMonthNumber(fromMonth)
			month2 = getMonthNumber(toMonth)
			monthDiff = month2 - month1
			if(monthDiff < 0)
			{
				addError("Please enter valid dates in the " + dateSet + " Date From - Date To fields.")
			}
		}
		else
		{
			//Check Years
			yearDiff = toYear - fromYear
			if(yearDiff < 0)
			{
				addError("Please enter valid dates in the " + dateSet + " Date From - Date To fields.")
			}
		}
		
	}
	
	function getMonthNumber(month){
		switch (month)
		{
			case "January":
				return 1
				break
			case "February":
				return 2
				break
			case "March":
				return 3
				break
			case "April":
				return 4
				break
			case "May":
				return 5
				break
			case "June":
				return 6
				break
			case "July":
				return 7
				break
			case "August":
				return 8
				break
			case "September":
				return 9
				break
			case "October":
				return 10
				break
			case "November":
				return 11
				break
			default:
				return 12
		}
	}









function CheckBoxGroup() {
	this.controlBox=null;
	this.controlBoxChecked=null;
	this.maxAllowed=null;
	this.maxAllowedMessage=null;
	this.masterBehavior=null;
	this.formRef=null;
	this.checkboxWildcardNames=new Array();
	this.checkboxNames=new Array();
	this.totalBoxes=0;
	this.totalSelected=0;
	// Public methods
	this.setControlBox=CBG_setControlBox;
	this.setMaxAllowed=CBG_setMaxAllowed;
	this.setMasterBehavior=CBG_setMasterBehavior;	// all, some
	this.addToGroup=CBG_addToGroup;
	// Private methods
	this.expandWildcards=CBG_expandWildcards;
	this.addWildcardCheckboxes=CBG_addWildcardCheckboxes;
	this.addArrayCheckboxes=CBG_addArrayCheckboxes;
	this.addSingleCheckbox=CBG_addSingleCheckbox;
	this.check=CBG_check;
	}

// Set the master control checkbox name
function CBG_setControlBox(name) { this.controlBox=name; }

// Set the maximum number of checked boxes in the set, and optionally
// the message to popup when the max is reached.
function CBG_setMaxAllowed(num,msg) {
	this.maxAllowed=num;
	if (msg!=null&&msg!="") { this.maxAllowedMessage=msg; }
	}

// Set the behavior for the checkbox group master checkbox
//	All: all boxes must be checked for the master to be checked
//	Some: one or more of the boxes can be checked for the master to be checked
function CBG_setMasterBehavior(b) { this.masterBehavior = b.toLowerCase(); }

// Add checkbox wildcards to the checkboxes array
function CBG_addToGroup() {
	if (arguments.length>0) {
		for (var i=0;i<arguments.length;i++) {
			this.checkboxWildcardNames[this.checkboxWildcardNames.length]=arguments[i];
			}
		}
	}

// Expand the wildcard checkbox names given in the addToGroup method
function CBG_expandWildcards() {
	if (this.formRef==null) {alert("ERROR: No form element has been passed.  Cannot extract form name!"); return false; }
	for (var i=0; i<this.checkboxWildcardNames.length;i++) {
		var n = this.checkboxWildcardNames[i];
		var el = this.formRef[n];
		if (n.indexOf("*")!=-1) { this.addWildcardCheckboxes(n); }
		else if(CBG_nameIsArray(el)) { this.addArrayCheckboxes(n); }
		else { this.addSingleCheckbox(el); }
		}
	}


// Add checkboxes to the group which match a pattern
function CBG_addWildcardCheckboxes(name) {
	var i=name.indexOf("*");
	if ((i==0) || (i==name.length-1)) {
		searchString= (i)?name.substring(0,name.length-1):name.substring(1,name.length);
		for (var j=0;j<this.formRef.length;j++) {
			currentElement = this.formRef.elements[j];
			currentElementName=currentElement.name;
			var partialName = (i)?currentElementName.substring(0,searchString.length) : currentElementName.substring(currentElementName.length-searchString.length,currentElementName.length);
			if (partialName==searchString) {
				if(CBG_nameIsArray(currentElement)) this.addArrayCheckboxes(currentElement);
				else this.addSingleCheckbox(currentElement);
				}
			}
		}
	}

// Add checkboxes to the group which all have the same name
function CBG_addArrayCheckboxes(name) {
	if((CBG_nameIsArray(this.formRef[name])) && (this.formRef[name].length>0)) {
		for (var i=0; i<this.formRef[name].length; i++) { this.addSingleCheckbox(this.formRef[name][i]); }
		}
	}

function CBG_addSingleCheckbox(obj) {
	if (obj != this.formRef[this.controlBox]) {
		this.checkboxNames[this.checkboxNames.length]=obj;
		this.totalBoxes++;
		if (obj.checked) {
			this.totalSelected++;
			}
		}
	}

// Runs whenever a checkbox in the group is clicked
function CBG_check(obj) {
	var checked=obj.checked;
	if (this.formRef==null) {
		this.formRef=obj.form;
		this.expandWildcards();
		if (this.controlBox==null || obj.name!=this.controlBox) {
			this.totalSelected += (checked)?-1:1;
			}
		}
	if (this.controlBox!=null&&obj.name==this.controlBox) {
		if (this.masterBehavior=="all") {
			for (i=0;i<this.checkboxNames.length;i++) { this.checkboxNames[i].checked=checked; }
			this.totalSelected=(checked)?this.checkboxNames.length:0;
			}
		else {
			if (!checked) {
				obj.checked = (this.totalSelected>0)?true:false;
				obj.blur();
				}
			}
		}
	else {
		if (this.masterBehavior=="all") {
			if (!checked) {
				this.formRef[this.controlBox].checked=false;
				this.totalSelected--;
				}
			else { this.totalSelected++; }
			if (this.controlBox!=null) {
				this.formRef[this.controlBox].checked=(this.totalSelected==this.totalBoxes)?true:false;
				}
			}
		else {
			if (!obj.checked) { this.totalSelected--; }	
			else { this.totalSelected++; }
			if (this.controlBox!=null) {
				this.formRef[this.controlBox].checked=(this.totalSelected>0)?true:false;
				}
			if (this.maxAllowed!=null) {
				if (this.totalSelected>this.maxAllowed) {
					obj.checked=false;
					this.totalSelected--;
					if (this.maxAllowedMessage!=null) { alert(this.maxAllowedMessage); }
					return false;
					}
				}
			}
		}
	}

function CBG_nameIsArray(obj) {
	return ((typeof obj.type!="string")&&(obj.length>0)&&(obj[0]!=null)&&(obj[0].type=="checkbox"));
	}















/***********************************************************************************/
