/*==============================================================================================
// Title = 			FormValidator.js 	
// Version =		2005-10-07					
// Author =			Jon Toribio			
//
// HISTORY:
// 2006-08-21:
//  - tweaked embedded error messaging for field groups
// 2006-07-14:
//  - added capabilities to show error messages withing form. Looks for <div class="ValidationError" name="<fieldname>ValdiationError">
// 2005-10-07:
//  - modified getValue method to properly return list for multiple 'text' type fields that have 
//    the same name. Similar to how checkboxes are handled
// 2004-12-16:
//	- added a submit function to submit the assigned form (should have been created in the first place)
//  - added getForm method that returns the assigned form object
// 2004-12-15:
// - added three utility functions: parseDate, displayDate, parsePostalCode and parsePhoneNumber
// 2004-10-21:
// - added createFieldGroup and addFieldGroupMember methods
// 2004-09-16: 
// - updated setAsValidPhoneExtension to allow 1-5 digits
// - changed IsANumber method name to setAsValidNumeric
// - added setMinValue and setMaxValue methods
// - added setMinDate and setMaxDate methods
//==============================================================================================
*/
var FormValidator_debug = false;

function FormValidator(form_name) {
	this.f = form_name;
	this.requiredItems = new Array();
	this.itemConstraints = new Array();
	this.anchors = new Array();
	this.fieldGroups = new Array();
	return this;
}


p = FormValidator.prototype;
p.isValidForm = FV_isValidForm;
p.submit = FV_submit;
p.getForm = FV_getForm;
p.hasValue = FV_hasValue;
p.getValue = FV_getValue;
p.setAnchor = FV_setAnchor;
p.addRequiredItem = FV_addRequiredItem;
p.removeRequiredItem = FV_removeRequiredItem;
p.createFieldGroup = FV_createFieldGroup;
p.addFieldGroupMember = FV_addFieldGroupMember
p.setMINLength = FV_setMINLength;
p.setMAXLength = FV_setMAXLength;
p.setValidPattern = FV_setValidPattern;
p.setAsValidEmail = FV_setAsValidEmail;
p.setAsValidPostalCode = FV_setAsValidPostalCode;
p.setAsValidZipCode = FV_setAsValidZipCode;
p.setAsMatchingFields = FV_setAsMatchingFields;
p.setInvalidValue = FV_setInvalidValue;
p.setMaxValue = FV_setMaxValue;
p.setMinValue = FV_setMinValue;
p.setAsValidPhoneNumber = FV_setAsValidPhoneNumber;
p.setAsValidPhoneExtension = FV_setAsValidPhoneExtension;
p.setAsValidNumeric = FV_setAsValidNumeric;
p.setAsValidEightNumbers = FV_setAsValidEightNumbers;
p.setAsValidDate = FV_setAsValidDate;
p.setMinDate = FV_setMinDate;
p.setMaxDate = FV_setMaxDate;
p.setAsValidMod10 = FV_setAsValidMod10;
p.setAsValidMod11 = FV_setAsValidMod11;




function FV_isValidForm() {
	var frm = eval(this.f);
	var itm_is_fieldGroup;
	var errorCount = 0;
	
	// check required fields
	if (FormValidator_debug) alert("LOOPING THROUGH REQUIRED ITEMS");
	for (itm in this.requiredItems)	{
		var errorDiv = document.getElementById(itm + "ValidationError");
		// reset the errorDiv to empty
		if (errorDiv) {
			errorDiv.innerHTML = "";
		}

		if (FormValidator_debug) alert("required item: " + itm);
		itm_is_fieldGroup = false;
		if (typeof frm.elements[itm] == "undefined") {
			//ok the item isn't in the form, lets check if a field group was defined
			//if it's not defined as a field group then complain
			if (typeof this.fieldGroups[itm] == "undefined") {
				alert("FormValidator error:\nElement '" + itm + "' doesn't exist.");
				return false;
			}
			else {
				itm_is_fieldGroup = true;
			}
			
		}

		// check if required field has input
		if ( itm_is_fieldGroup ) {
			if (FormValidator_debug) alert("checking field group:" + itm);
			var fld_grp = this.fieldGroups[itm].fields;
			var min_choices = Math.min(this.fieldGroups[itm].min_choices,fld_grp.length);
			var max_choices = (this.fieldGroups[itm].max_choices) ? Math.max(min_choices, Math.min(this.fieldGroups[itm].max_choices,fld_grp.length)) : fld_grp.length;

			if (FormValidator_debug) alert("group length:" + fld_grp.length);
			if (FormValidator_debug) alert("min_choices:" + min_choices);
			if (FormValidator_debug) alert("max_choices:" + max_choices);
			
			var choice_count = 0;
			var group_error_msg = "";
			
			for (i = 0 ; i < fld_grp.length ; i++) {
				if (FormValidator_debug) alert("checking field group item:" + i);
				if (typeof frm.elements[fld_grp[i]] == "undefined") {
					alert("FormValidator error:\nElement '" + fld_grp[i] + "' doesn't exist.");
					return false;
				}

				if (FormValidator_debug) alert("item " + fld_grp[i] + " has input: " + _hasInput(frm.elements[fld_grp[i]]));
				if ( _hasInput(frm.elements[fld_grp[i]]) ) {
					choice_count++;
					// check if input is valid
					if ( _isValidInput(frm.elements[fld_grp[i]], this.itemConstraints, frm, errorDiv) ) {
					} else {
						// complain about invalid input
						errorCount++;
						if (! errorDiv) {
							_focusItem(frm.elements[fld_grp[i]],this.anchors);
							return false;
						}
					}
				}
				else {
					if (this.itemConstraints[fld_grp[i]]) this.itemConstraints[fld_grp[i]]["WAS_CHECKED"] = true;
				}
				
			}

			if (FormValidator_debug) alert("choice count: " + choice_count);

			if ((choice_count < min_choices) || (choice_count > max_choices)) {
				errorCount++;
				if (errorDiv) {
					errorDiv.innerHTML = this.requiredItems[itm].errmsg;
				}
				else {
					alert(this.requiredItems[itm].errmsg);
					_focusItem(frm.elements[fld_grp[0]],this.anchors);
					return false;
				}
			}			
		}
		else if ( _hasInput(frm.elements[itm]) ) {

			if (FormValidator_debug) alert("item has input");
			// check if input is valid
			if ( _isValidInput(frm.elements[itm], this.itemConstraints, frm, errorDiv) ) {
			} else {
				// complain about invalid input
				errorCount++;
				if (! errorDiv) {
					_focusItem(frm.elements[itm],this.anchors);
					return false;
				}
			}
		} else {
			// complain about required field
			errorCount++;
			if (this.itemConstraints[itm]) this.itemConstraints[itm]["WAS_CHECKED"] = true;
			if (errorDiv) {
				errorDiv.innerHTML = this.requiredItems[itm].errmsg;
			}
			else {
				alert(this.requiredItems[itm].errmsg);
				_focusItem(frm.elements[itm],this.anchors);
				return false;
			}
		}
	}
	
	if (FormValidator_debug) alert("LOOPING THROUGH ITEMS WITH CONSTRAINTS");
	for (itm in this.itemConstraints) {
		if (FormValidator_debug) {
				var alertmsg = "itemConstraints[" + itm + "]\n";
				for (subitm in this.itemConstraints[itm]) {
					alertmsg += subitm + "\n";
				}
				alert(alertmsg);
		}
		if (this.itemConstraints[itm] && this.itemConstraints[itm]["WAS_CHECKED"]) continue;
		if (FormValidator_debug) alert("optional item: " + itm);
		var errorDiv = document.getElementById(itm + "ValidationError");
		if (typeof frm.elements[itm] == "undefined") {
			alert("FormValidator error:\nElement '" + itm + "' doesn't exist.");
			return false;
		}
		

		if ( _hasInput(frm.elements[itm]) ) {
			// check if input is valid
			if ( _isValidInput(frm.elements[itm], this.itemConstraints, frm, errorDiv) ) {
				if (errorDiv) {
					errorDiv.innerHTML = "";
				}
			} else {
				// complain about invalid input
				errorCount++;
				if (! errorDiv) {
					_focusItem(frm.elements[itm],this.anchors);
					return false;
				}
			}
		}
	}
	// check non-required fields
	if (errorCount > 0) return false;

	return true;
}

function FV_submit() {
	var frm = eval(this.f);
	frm.submit();
}

function FV_getForm() {
	return eval(this.f);
}

function FV_hasValue(element_name) {
	var frm = eval(this.f);
	var form_element = frm.elements[element_name];
	return _hasInput(form_element);
}

function FV_getValue(element_name) {
	var frm = eval(this.f);
	var form_element = frm.elements[element_name];
	return _elem_value(form_element);
}

function FV_setAnchor(element_name, anchor_name) {
	this.anchors[element_name] = anchor_name;
}

function FV_addRequiredItem(element_name, errmsg) {
	var newobj = new Object();
	newobj.errmsg = errmsg;
	this.requiredItems[element_name] = newobj;
}

function FV_removeRequiredItem(element_name) {
	delete this.requiredItems[element_name];
}

function FV_createFieldGroup(group_name) {
	args = FV_createFieldGroup.arguments;
	var newobj = new Object();
	newobj.min_choices = (args[1]) ? Math.max(parseInt(args[1]),1) : 1;
	newobj.max_choices = (args[2]) ? Math.max(parseInt(args[2]),newobj.min_choices) : false; 
	newobj.fields = new Array();
	this.fieldGroups[group_name] = newobj;
}

function FV_addFieldGroupMember(group_name, element_name) {
	var idx = this.fieldGroups[group_name].fields.length;
	this.fieldGroups[group_name].fields[idx] = element_name;
}

function FV_setMINLength(element_name, val, errmsg) {
	var newobj = new Object();
	
	if (typeof this.itemConstraints[element_name] == "undefined") {
		this.itemConstraints[element_name] = new Array();
	}
	newobj.value = val;
	newobj.errmsg = errmsg;
	this.itemConstraints[element_name]["MIN_LENGTH"] = newobj;
}

function FV_setMAXLength(element_name, val, errmsg) {
	var newobj = new Object();
	
	if (typeof this.itemConstraints[element_name] == "undefined") {
		this.itemConstraints[element_name] = new Array();
	}
	newobj.value = val;
	newobj.errmsg = errmsg;
	this.itemConstraints[element_name]["MAX_LENGTH"] = newobj;
}

function FV_setValidPattern(element_name, reg_exp, errmsg) {
	var newobj = new Object();
	
	if (typeof this.itemConstraints[element_name] == "undefined") {
		this.itemConstraints[element_name] = new Array();
	}
	newobj.regexp = reg_exp;
	newobj.errmsg = errmsg;
	this.itemConstraints[element_name]["VALID_REGEXP"] = newobj;
}


function FV_setAsValidEmail(element_name, errmsg) {
	var newobj = new Object();
	
	if (typeof this.itemConstraints[element_name] == "undefined") {
		this.itemConstraints[element_name] = new Array();
	}
	newobj.regexp = /^[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)*@([a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)*\.[a-zA-Z]{2,3}|([0-9]|[1-9][0-9]{1}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.([0-9]|[1-9][0-9]{1}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.([0-9]|[1-9][0-9]{1}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.([0-9]|[1-9][0-9]{1}|1[0-9]{2}|2[0-4][0-9]|25[0-5]))$/;
	newobj.errmsg = errmsg;
	this.itemConstraints[element_name]["VALID_REGEXP"] = newobj;
}

function FV_setAsValidPostalCode(element_name, errmsg) {
	var newobj = new Object();
	
	if (typeof this.itemConstraints[element_name] == "undefined") {
		this.itemConstraints[element_name] = new Array();
	}
	newobj.regexp = /^(([a-zA-Z][0-9]){3}|([a-zA-Z][0-9][a-zA-Z] [0-9][a-zA-Z][0-9]))$/;
	newobj.errmsg = errmsg;
	this.itemConstraints[element_name]["VALID_REGEXP"] = newobj;
}

function FV_setAsValidZipCode(element_name, errmsg) {
	var newobj = new Object();
	
	if (typeof this.itemConstraints[element_name] == "undefined") {
		this.itemConstraints[element_name] = new Array();
	}
	newobj.regexp = /^[0-9]{5}$/;
	newobj.errmsg = errmsg;
	this.itemConstraints[element_name]["VALID_REGEXP"] = newobj;
}

function FV_setAsValidPhoneNumber(area_code_field, phone_exchange_field, phone_number_field, errmsg) {
	var three_digit = new Object();
	var four_digit = new Object();
	
	if (typeof this.itemConstraints[area_code_field] == "undefined") {
		this.itemConstraints[area_code_field] = new Array();
	}
	if (typeof this.itemConstraints[phone_exchange_field] == "undefined") {
		this.itemConstraints[phone_exchange_field] = new Array();
	}
	if (typeof this.itemConstraints[phone_number_field] == "undefined") {
		this.itemConstraints[phone_number_field] = new Array();
	}

	three_digit.regexp = /^[0-9]{3}$/;
	three_digit.errmsg = errmsg;

	four_digit.regexp = /^[0-9]{4}$/;
	four_digit.errmsg = errmsg;

	this.itemConstraints[area_code_field]["VALID_REGEXP"] = three_digit;
	this.itemConstraints[phone_exchange_field]["VALID_REGEXP"] = three_digit;
	this.itemConstraints[phone_number_field]["VALID_REGEXP"] = four_digit;
}

function FV_setAsValidPhoneExtension(element_name, errmsg) {
	var newobj = new Object();
	
	if (typeof this.itemConstraints[element_name] == "undefined") {
		this.itemConstraints[element_name] = new Array();
	}
	newobj.regexp = /^[0-9]{1,5}$/;
	newobj.errmsg = errmsg;
	this.itemConstraints[element_name]["VALID_REGEXP"] = newobj;
}


function FV_setAsValidNumeric(element_name, errmsg) {
	var newobj = new Object();
	
	if (typeof this.itemConstraints[element_name] == "undefined") {
		this.itemConstraints[element_name] = new Array();
	}
	newobj.regexp = /^\d+$/;
	newobj.errmsg = errmsg;
	this.itemConstraints[element_name]["VALID_REGEXP"] = newobj;
}

function FV_setAsValidEightNumbers(element_name, errmsg) {
	var newobj = new Object();
	
	if (typeof this.itemConstraints[element_name] == "undefined") {
		this.itemConstraints[element_name] = new Array();
	}
	newobj.regexp = /^[0-9]{8}$/;
	newobj.errmsg = errmsg;
	this.itemConstraints[element_name]["VALID_REGEXP"] = newobj;
}


function FV_setAsMatchingFields(element_name, tgt_element_name, errmsg) {
	var newobj = new Object();
	
	if (typeof this.itemConstraints[element_name] == "undefined") {
		this.itemConstraints[element_name] = new Array();
	}
	newobj.target = tgt_element_name;
	newobj.errmsg = errmsg;
	this.itemConstraints[element_name]["MATCHING_FIELDS"] = newobj;
}

function FV_setInvalidValue(element_name, val, errmsg) {
	var newobj = new Object();
	
	if (typeof this.itemConstraints[element_name] == "undefined") {
		this.itemConstraints[element_name] = new Array();
	}
	newobj.value = val;
	newobj.errmsg = errmsg;
	this.itemConstraints[element_name]["INVALID_VALUE"] = newobj;
}

function FV_setMaxValue(element_name, val, errmsg) {
	var newobj = new Object();
	
	if (typeof this.itemConstraints[element_name] == "undefined") {
		this.itemConstraints[element_name] = new Array();
	}
	newobj.value = val;
	newobj.errmsg = errmsg;
	this.itemConstraints[element_name]["MAX_VALUE"] = newobj;
}

function FV_setMinValue(element_name, val, errmsg) {
	var newobj = new Object();
	
	if (typeof this.itemConstraints[element_name] == "undefined") {
		this.itemConstraints[element_name] = new Array();
	}
	newobj.value = val;
	newobj.errmsg = errmsg;
	this.itemConstraints[element_name]["MIN_VALUE"] = newobj;
}

function FV_setAsValidDate(day_element_name, month_element_name, year_element_name, day_errmsg, month_errmsg, year_errmsg) {
	var newobj;
	var reobj;
	
	if (typeof this.itemConstraints[day_element_name] == "undefined") {
		this.itemConstraints[day_element_name] = new Array();
	}
	if (typeof this.itemConstraints[month_element_name] == "undefined") {
		this.itemConstraints[month_element_name] = new Array();
	}
	if (typeof this.itemConstraints[year_element_name] == "undefined") {
		this.itemConstraints[year_element_name] = new Array();
	}
	
	var day_ptrn = /^([1-9]|0[1-9]|[12][0-9]|3[01])$/;
	reobj = new Object();
	reobj.regexp = day_ptrn;
	reobj.errmsg = day_errmsg;
	this.itemConstraints[day_element_name]["VALID_REGEXP"] = reobj;

	var month_ptrn = /^([1-9]|0[1-9]|1[0-2])$/;
	reobj = new Object();
	reobj.regexp = month_ptrn;
	reobj.errmsg = month_errmsg;
	this.itemConstraints[month_element_name]["VALID_REGEXP"] = reobj;

	var year_ptrn = /^[0-9]{1,4}$/;
	reobj = new Object();
	reobj.regexp = year_ptrn;
	reobj.errmsg = year_errmsg;
	this.itemConstraints[year_element_name]["VALID_REGEXP"] = reobj;
	
	newobj = new Object();
	newobj.day_elem = day_element_name;
	newobj.month_elem = month_element_name;
	newobj.year_elem = year_element_name;
	newobj.errmsg = day_errmsg;
	this.itemConstraints[day_element_name]["VALID_DAY"] = newobj;
}

function FV_setMinDate(day_element_name, month_element_name, year_element_name, date_obj, day_errmsg, month_errmsg, year_errmsg) {
	var newobj;
	var reobj;
	
	if (typeof this.itemConstraints[day_element_name] == "undefined") {
		this.itemConstraints[day_element_name] = new Array();
	}
	if (typeof this.itemConstraints[month_element_name] == "undefined") {
		this.itemConstraints[month_element_name] = new Array();
	}
	if (typeof this.itemConstraints[year_element_name] == "undefined") {
		this.itemConstraints[year_element_name] = new Array();
	}
	
	newobj = new Object();
	newobj.day_elem = day_element_name;
	newobj.month_elem = month_element_name;
	newobj.year_elem = year_element_name;
	newobj.tgt_date = date_obj
	newobj.errmsg = year_errmsg;
	this.itemConstraints[year_element_name]["MIN_DATE"] = newobj;

	newobj = new Object();
	newobj.day_elem = day_element_name;
	newobj.month_elem = month_element_name;
	newobj.year_elem = year_element_name;
	newobj.tgt_date = date_obj
	newobj.errmsg = month_errmsg;
	this.itemConstraints[month_element_name]["MIN_DATE"] = newobj;

	newobj = new Object();
	newobj.day_elem = day_element_name;
	newobj.month_elem = month_element_name;
	newobj.year_elem = year_element_name;
	newobj.tgt_date = date_obj
	newobj.errmsg = day_errmsg;
	this.itemConstraints[day_element_name]["MIN_DATE"] = newobj;
}

function FV_setMaxDate(year_element_name, month_element_name, day_element_name, hour_element_name, minute_element_name, second_element_name,  date_obj, errmsg) {
	var newobj;
	var reobj;
	
	if (typeof this.itemConstraints[day_element_name] == "undefined") {
		this.itemConstraints[day_element_name] = new Array();
	}
	if (typeof this.itemConstraints[month_element_name] == "undefined") {
		this.itemConstraints[month_element_name] = new Array();
	}
	if (typeof this.itemConstraints[year_element_name] == "undefined") {
		this.itemConstraints[year_element_name] = new Array();
	}
	if (typeof this.itemConstraints[hour_element_name] == "undefined") {
		this.itemConstraints[hour_element_name] = new Array();
	}
	if (typeof this.itemConstraints[minute_element_name] == "undefined") {
		this.itemConstraints[minute_element_name] = new Array();
	}
	if (typeof this.itemConstraints[second_element_name] == "undefined") {
		this.itemConstraints[second_element_name] = new Array();
	}
	
	newobj = new Object();
	newobj.day_elem = day_element_name;
	newobj.month_elem = month_element_name;
	newobj.year_elem = year_element_name;
	newobj.hour_elem = hour_element_name;
	newobj.minute_elem = minute_element_name;
	newobj.second_elem = second_element_name;
	newobj.tgt_date = date_obj
	newobj.errmsg = errmsg;
	this.itemConstraints[year_element_name]["MAX_DATE"] = newobj;

	newobj = new Object();
	newobj.day_elem = day_element_name;
	newobj.month_elem = month_element_name;
	newobj.year_elem = year_element_name;
	newobj.hour_elem = hour_element_name;
	newobj.minute_elem = minute_element_name;
	newobj.second_elem = second_element_name;
	newobj.tgt_date = date_obj
	newobj.errmsg = errmsg;
	this.itemConstraints[month_element_name]["MAX_DATE"] = newobj;

	newobj = new Object();
	newobj.day_elem = day_element_name;
	newobj.month_elem = month_element_name;
	newobj.year_elem = year_element_name;
	newobj.hour_elem = hour_element_name;
	newobj.minute_elem = minute_element_name;
	newobj.second_elem = second_element_name;
	newobj.tgt_date = date_obj
	newobj.errmsg = errmsg;
	this.itemConstraints[day_element_name]["MAX_DATE"] = newobj;

	newobj = new Object();
	newobj.day_elem = day_element_name;
	newobj.month_elem = month_element_name;
	newobj.year_elem = year_element_name;
	newobj.hour_elem = hour_element_name;
	newobj.minute_elem = minute_element_name;
	newobj.second_elem = second_element_name;
	newobj.tgt_date = date_obj
	newobj.errmsg = errmsg;
	this.itemConstraints[hour_element_name]["MAX_DATE"] = newobj;

	newobj = new Object();
	newobj.day_elem = day_element_name;
	newobj.month_elem = month_element_name;
	newobj.year_elem = year_element_name;
	newobj.hour_elem = hour_element_name;
	newobj.minute_elem = minute_element_name;
	newobj.second_elem = second_element_name;
	newobj.tgt_date = date_obj
	newobj.errmsg = errmsg;
	this.itemConstraints[minute_element_name]["MAX_DATE"] = newobj;

	newobj = new Object();
	newobj.day_elem = day_element_name;
	newobj.month_elem = month_element_name;
	newobj.year_elem = year_element_name;
	newobj.hour_elem = hour_element_name;
	newobj.minute_elem = minute_element_name;
	newobj.second_elem = second_element_name;
	newobj.tgt_date = date_obj
	newobj.errmsg = errmsg;
	this.itemConstraints[second_element_name]["MAX_DATE"] = newobj;

}

function FV_setAsValidMod10(element_name, errmsg) {
	var newobj = new Object();
	if (typeof this.itemConstraints[element_name] == "undefined") {
		this.itemConstraints[element_name] = new Array();
	}
	newobj.errmsg = errmsg;
	this.itemConstraints[element_name]["VALID_MOD10"] = newobj;
}

function FV_setAsValidMod11(element_name, errmsg) {
	var newobj = new Object();
	if (typeof this.itemConstraints[element_name] == "undefined") {
		this.itemConstraints[element_name] = new Array();
	}
	newobj.errmsg = errmsg;
	this.itemConstraints[element_name]["VALID_MOD11"] = newobj;
}

function FV_setMINListSize(element_name, val, errmsg) {
	var newobj = new Object();
	
	if (typeof this.itemConstraints[element_name] == "undefined") {
		this.itemConstraints[element_name] = new Array();
	}
	newobj.value = val;
	newobj.errmsg = errmsg;
	this.itemConstraints[element_name]["MIN_LISTSIZE"] = newobj;
}


// helper functions

function _trim(str) {
	var ptrn_ws = /(^\s+)|(\s+$)/g;
	return str.replace(ptrn_ws,"");
}


function _hasInput(form_element) {

	switch(_elem_type(form_element)) {
		case "text":
		case "textarea":
		case "password":
		case "hidden":
		case "file":
			form_element.value = _trim(form_element.value);
			return (form_element.value.length > 0);
			break;
		case "checkbox":
			if (typeof(form_element.checked) != "boolean") 
			{
				var rtrnval = false;
				for ( i = 0 ; i < form_element.length ; i++ ) {
					var fe = form_element[i];
					if (fe.checked) 
						rtrnval = true;
				}
				return rtrnval;
			}
			else	
				return form_element.checked;
			break;
		case "radio":
			return _isRadioSelected(form_element);
			break;
		case "select-one":
		case "select-multiple":
			return _isOptionSelected(form_element);
			break;
		default:
			break;
	}
	return true;
}

function _isValidInput(form_element, rules, frm, errorDiv) {
	var fe_name;
	var itm;

	fe_name = _elem_name(form_element);
	if (rules[fe_name]) rules[fe_name]["WAS_CHECKED"] = true;

	for (itm in rules[fe_name]) {
		if (FormValidator_debug) alert("checking validations rule:" + itm);
		switch(itm) {
			case 'MIN_LENGTH':
				if (_elem_value(form_element).length < rules[fe_name]["MIN_LENGTH"].value) {
					if (errorDiv) {
							errorDiv.innerHTML = rules[fe_name]["MIN_LENGTH"].errmsg;
					}
					else {
						alert(rules[fe_name]["MIN_LENGTH"].errmsg);
					}
					return false;
				}
				break;
			case 'MAX_LENGTH':
				if (_elem_value(form_element).length > rules[fe_name]["MAX_LENGTH"].value) {
					if (errorDiv) {
							errorDiv.innerHTML = rules[fe_name]["MAX_LENGTH"].errmsg;
					}
					else {
						alert(rules[fe_name]["MAX_LENGTH"].errmsg);
					}
					return false;
				}
				break;
			case 'VALID_REGEXP':
				if ( _elem_value(form_element).search(rules[fe_name]["VALID_REGEXP"].regexp) == -1 ) {
					if (errorDiv) {
							errorDiv.innerHTML = rules[fe_name]["VALID_REGEXP"].errmsg;
					}
					else {
						alert(rules[fe_name]["VALID_REGEXP"].errmsg);
					}
					return false;
				}
				break;
			case 'VALID_MOD10':
				if ( ! _isValidMod10(_elem_value(form_element)) ) {
					if (errorDiv) {
							errorDiv.innerHTML = rules[fe_name]["VALID_MOD10"].errmsg;
					}
					else {
						alert(rules[fe_name]["VALID_MOD10"].errmsg);
					}
					return false;
				}
				break;
			case 'VALID_MOD11':
				if ( ! _isValidMod11(_elem_value(form_element)) ) {
					if (errorDiv) {
							errorDiv.innerHTML = rules[fe_name]["VALID_MOD11"].errmsg;
					}
					else {
						alert(rules[fe_name]["VALID_MOD11"].errmsg);
					}
					return false;
				}
				break;
			case 'MATCHING_FIELDS':
				var tgt_elem = frm.elements[rules[fe_name]["MATCHING_FIELDS"].target];
				if ( _elem_value(form_element) != _elem_value(tgt_elem) ) {
					if (errorDiv) {
							errorDiv.innerHTML = rules[fe_name]["MATCHING_FIELDS"].errmsg;
					}
					else {
						alert(rules[fe_name]["MATCHING_FIELDS"].errmsg);
					}
					return false;
				}
				break;
			case 'INVALID_VALUE':
				if ( _elem_value(form_element) == rules[fe_name]["INVALID_VALUE"].value ) {
					if (errorDiv) {
							errorDiv.innerHTML = rules[fe_name]["INVALID_VALUE"].errmsg;
					}
					else {
						alert(rules[fe_name]["INVALID_VALUE"].errmsg);
					}
					return false;
				}
				break;
			case 'MAX_VALUE':
				if ( parseInt(_elem_value(form_element)) > parseInt(rules[fe_name]["MAX_VALUE"].value) ) {
					if (errorDiv) {
							errorDiv.innerHTML = rules[fe_name]["MAX_VALUE"].errmsg;
					}
					else {
						alert(rules[fe_name]["MAX_VALUE"].errmsg);
					}
					return false;
				}
				break;
			case 'MIN_VALUE':
				if ( parseInt(_elem_value(form_element)) < parseInt(rules[fe_name]["MIN_VALUE"].value) ) {
					if (errorDiv) {
							errorDiv.innerHTML = rules[fe_name]["MIN_VALUE"].errmsg;
					}
					else {
						alert(rules[fe_name]["MIN_VALUE"].errmsg);
					}
					return false;
				}
				break;
			case 'VALID_DAY':
				var day_elem = frm.elements[rules[fe_name]["VALID_DAY"].day_elem];
				var month_elem = frm.elements[rules[fe_name]["VALID_DAY"].month_elem];
				var year_elem = frm.elements[rules[fe_name]["VALID_DAY"].year_elem];
				
				if (_isValidDateValues(_elem_value(form_element), _elem_value(month_elem), _elem_value(year_elem)) ) {
					var tmp_date = new Date(_elem_value(year_elem),_elem_value(month_elem) - 1,_elem_value(form_element));
					if (tmp_date.getDate() != parseInt(_elem_value(form_element))) {
						if (errorDiv) {
								errorDiv.innerHTML = rules[fe_name]["VALID_DAY"].errmsg;
						}
						else {
							alert(rules[fe_name]["VALID_DAY"].errmsg);
						}
						return false;
					}
				}
				break;
			case 'MAX_DATE':
				// 1. retrieve date elements from the form
				var day_elem = frm.elements[rules[fe_name]["MAX_DATE"].day_elem];
				var month_elem = frm.elements[rules[fe_name]["MAX_DATE"].month_elem];
				var year_elem = frm.elements[rules[fe_name]["MAX_DATE"].year_elem];
				var hour_elem = frm.elements[rules[fe_name]["MAX_DATE"].hour_elem];
				var minute_elem = frm.elements[rules[fe_name]["MAX_DATE"].minute_elem];
				var second_elem = frm.elements[rules[fe_name]["MAX_DATE"].second_elem];
				// 2. get our target date object
				var tgt_date = rules[fe_name]["MAX_DATE"].tgt_date;
				var tgt_year = tgt_date.getFullYear();
				var tgt_month = tgt_date.getMonth() + 1;
				var tgt_day = tgt_date.getDate();
				var tgt_hour = tgt_date.getHours();
				var tgt_minute = tgt_date.getMinutes();
				var tgt_second = tgt_date.getSeconds();
				
				var throw_error = false;
				
				if (parseInt(_elem_value(year_elem)) > tgt_year) {
					if (fe_name == _elem_name(year_elem)) throw_error = true;
				}
				// don't forget equal year conditions
				else if ((parseInt(_elem_value(year_elem)) == tgt_year) && 
					(parseInt(_elem_value(month_elem)) > tgt_month) ) 
				{
					if (fe_name == _elem_name(month_elem)) throw_error = true;
				}
				else if ((parseInt(_elem_value(year_elem)) == tgt_year) && 
					(parseInt(_elem_value(month_elem)) == tgt_month) && 
					(parseInt(_elem_value(day_elem)) > tgt_day) ) 
				{
					if (fe_name == _elem_name(day_elem)) throw_error = true;
				}
				else if ((parseInt(_elem_value(year_elem)) == tgt_year) && 
					(parseInt(_elem_value(month_elem)) == tgt_month) && 
					(parseInt(_elem_value(day_elem)) == tgt_day) &&
					(parseInt(_elem_value(hour_elem)) > tgt_hour) ) 
				{
					if (fe_name == _elem_name(hour_elem)) throw_error = true;
				}
				else if ((parseInt(_elem_value(year_elem)) == tgt_year) && 
					(parseInt(_elem_value(month_elem)) == tgt_month) && 
					(parseInt(_elem_value(day_elem)) == tgt_day) &&
					(parseInt(_elem_value(hour_elem)) == tgt_hour) &&
					(parseInt(_elem_value(minute_elem)) > tgt_minute) ) 
				{
					if (fe_name == _elem_name(minute_elem)) throw_error = true;
				}
				else if ((parseInt(_elem_value(year_elem)) == tgt_year) && 
					(parseInt(_elem_value(month_elem)) == tgt_month) && 
					(parseInt(_elem_value(day_elem)) == tgt_day) &&
					(parseInt(_elem_value(hour_elem)) == tgt_hour) &&
					(parseInt(_elem_value(minute_elem)) == tgt_minute) && 
					(parseInt(_elem_value(second_elem)) > tgt_second) ) 
				{
					if (fe_name == _elem_name(second_elem)) throw_error = true;
				}

				if (throw_error) {
					alert(rules[fe_name]["MAX_DATE"].errmsg);
					return false;
				}

				break;
			case 'MIN_DATE':
				// 1. retrieve date elements from the form
				var day_elem = frm.elements[rules[fe_name]["MIN_DATE"].day_elem];
				var month_elem = frm.elements[rules[fe_name]["MIN_DATE"].month_elem];
				var year_elem = frm.elements[rules[fe_name]["MIN_DATE"].year_elem];
				// 2. get our target date object
				var tgt_date = rules[fe_name]["MIN_DATE"].tgt_date;
				var tgt_year = tgt_date.getFullYear();
				var tgt_month = tgt_date.getMonth() + 1;
				var tgt_day = tgt_date.getDate();
				
				var throw_error = false;
				
				if (parseInt(_elem_value(year_elem)) < tgt_year) {
					if (fe_name == _elem_name(year_elem)) throw_error = true;
				}
				// don't forget equal year conditions
				else if ((parseInt(_elem_value(year_elem)) == tgt_year) && (parseInt(_elem_value(month_elem)) < tgt_month) ) {
					if (fe_name == _elem_name(month_elem)) throw_error = true;
				}
				else if ((parseInt(_elem_value(year_elem)) == tgt_year) && (parseInt(_elem_value(month_elem)) == tgt_month) && (parseInt(_elem_value(day_elem)) < tgt_day) ) {
					if (fe_name == _elem_name(day_elem)) throw_error = true;
				}

				if (throw_error) {
					if (errorDiv) {
							errorDiv.innerHTML = rules[fe_name]["MIN_DATE"].errmsg;
					}
					else {
						alert(rules[fe_name]["MIN_DATE"].errmsg);
					}
					return false;
				}

				break;
			default:
		}
	}

	return true;
}

function _focusItem(form_element, anchors) {
	
	if ( typeof anchors[_elem_name(form_element)] != "undefined" ) {
		document.location = anchors[_elem_name(form_element)];
	}
	
	switch(_elem_type(form_element)) {
		case "text":
		case "textarea":
		case "password":
		case "file":
			form_element.focus();
			form_element.select();
			break;
		case "checkbox":
			if (typeof form_element[0] == "undefined")
				form_element.focus();
			else
				form_element[0].focus();
			break;			
		case "select-one":
		case "select-multiple":
			form_element.focus();
			break;
		case "radio":
			form_element[0].focus();
			break;
		case "hidden":
		default:
			break;
	}
}

function _isRadioSelected(form_element) {
	for(var i = 0; i < form_element.length ; i++) {
		if (form_element[i].checked) return true;
	}
	return false;
}

function _isOptionSelected(form_element) {
	for(var i = 0; i < form_element.options.length ; i++ ) {
		if (form_element.options[i].selected) return true;
	}
	return false;
}

function _isValidDateValues(day_val, month_val, year_val) {
	var day_ptrn = /^([1-9]|[12][0-9]|3[01])$/;
	var month_ptrn = /^([1-9]|1[0-2])$/;
	var year_ptrn = /^[0-9]{1,4}$/;

	return (day_val.match(day_ptrn) && month_val.match(month_ptrn) && year_val.match(year_ptrn));	
}

function _isValidMod10(val) {
	var sum = 0;
	var num, num0;
	var mult = 1;

	for ( var i = val.length - 1 ; i >= 0 ; i-- )  {
		num = new Number(val.substr(i, 1));
		num = num * mult;
		num = (num > 9) ? num - 9 : num;
		sum += num;
		mult = 3 - mult;
	}
	return (sum % 10 == 0);
}

function _isValidMod11(val) {
	var sum = 0;
	var num, num0;
	var mult = 1;

	for ( var i = val.length - 1 ; i >= 0 ; i-- )  {
		num = new Number(val.substr(i, 1));
		num = num * mult;
		sum += num;
		mult += 1;
	}
	return (sum % 11 == 0);
}

function _elem_type(form_element) {
	
	if(form_element.type) 			return form_element.type;
	else if (form_element[0].type) 	return form_element[0].type;
	else							return "unknown";	
}

function _elem_name(form_element) {
	if(form_element.name) 			return form_element.name;
	else if (form_element[0].name) 	return form_element[0].name;
	else							return "unknown";	

}

function _elem_value(form_element) {

	switch(_elem_type(form_element)) {
		case "text":
		case "textarea":
		case "password":
		case "file":
		case "hidden":
			if(form_element.value)	
				return form_element.value;
			else if (form_element[0].value) 
			{
				var elemlist = new Array();
				for ( i = 0 ; i < form_element.length ; i++ ) {
					var fe = form_element[i];
					elemlist[elemlist.length] = fe.value;
				}
				return elemlist.join(",");
			}
			else	
				return "unknown";
			break;
		case "checkbox":
			if(form_element.value)	
				return form_element.value;
			else if (form_element[0].value) 
			{
				var chkboxlist = new Array();
				for ( i = 0 ; i < form_element.length ; i++ ) {
					var fe = form_element[i];
					if (fe.checked) 
						chkboxlist[chkboxlist.length] = fe.value;
				}
				return chkboxlist.join(",");
			}
			else	
				return "unknown";
			break;
		case "select-one":
			return form_element.options[form_element.selectedIndex].value;
			break;
		case "select-multiple":
			var tmparr = new Array();
			for (var i = 0 ; i < form_element.options.length ; i++ ) {
				var _o = form_element.options[i];
				if ( _o.selected ) {
					tmparr[tmparr.length] = _o.value;
				}
			}
			return tmparr.join(",");
			break;
		case "radio":
			for(var i = 0; i < form_element.length ; i++) {
				if (form_element[i].checked) return form_element[i].value;
			}
			return null;
			break;
		default:
			return null;
	}
	
}

// utility functions
function parseDate(str)
{
	var dt = new Date(str);
	return (str == "") ? "" : displayDate(dt);
}

function displayDate(dt)
{
	var returnStr = String(dt);
	var monArr = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
	
	if (returnStr != "Invalid Date") {
		returnStr = monArr[dt.getMonth()] + " ";
		returnStr += String(dt.getDate()) + ", ";
		returnStr += String(dt.getFullYear()) + "  ";
		var hrs = dt.getHours() % 12;
		hrs = (hrs == 0) ? 12 : hrs;
		returnStr += String(hrs) + ":";
		returnStr += ( (dt.getMinutes() < 10) ? "0" + String(dt.getMinutes()) : String(dt.getMinutes()) );
		if (dt.getSeconds() > 0) {
			returnStr += ":" + ( (dt.getSeconds() < 10) ? "0" + String(dt.getSeconds()) : String(dt.getSeconds()) );
		}
		returnStr += (dt.getHours() >= 12) ? " PM" : " AM";
	}
	
	return returnStr;
	
}

function parsePostalCode(str)
{
	var new_str = _trim(String(str).toUpperCase());
	var return_str = "Invalid";
	var ptrn_postal_code_7 = /^([A-Z][0-9][A-Z] [0-9][A-Z][0-9])$/;
	var prtn_postal_code_6 = /^([A-Z][0-9]){3}$/;;
	
	if ( (new_str == "") || new_str.match(ptrn_postal_code_7) )
		return_str = new_str;
	else if (new_str.match(prtn_postal_code_6))
	{
		return_str = new_str.substring(0,3) + " " + new_str.substring(3);
	}
		
	return return_str;
}

function parsePhoneNumber(str)
{
	var new_str = _trim(String(str).toUpperCase());
	var alphaMap = new Array();
	
	new_str = new_str.replace(/[ABC]/g,"2");
	new_str = new_str.replace(/[DEF]/g,"3");
	new_str = new_str.replace(/[GHI]/g,"4");
	new_str = new_str.replace(/[JKL]/g,"5");
	new_str = new_str.replace(/[MNO]/g,"6");
	new_str = new_str.replace(/[PQRS]/g,"7");
	new_str = new_str.replace(/[TUV]/g,"8");
	new_str = new_str.replace(/[WXYZ]/g,"9");
	new_str = new_str.replace(/[^0-9]/g,"");

	var return_str = "Invalid";
	var ptrn_phone_0 = /^[0-9]{10}$/;
	var ptrn_phone_1 = /^[0-9]{3}-[0-9]{3}-[0-9]{4}$/;
	
	if ( (new_str == "") || new_str.match(ptrn_phone_1) )
		return_str = new_str;
	else if (new_str.match(ptrn_phone_0))
		return_str = new_str.substring(0,3) + "-" + new_str.substring(3,6) + "-" + new_str.substring(6);
		
	return return_str;
}


// custom definitions
var ptrn_sys_name = /^[a-zA-Z_0-9]+$/;

Object.prototype.toString = function()
{
	var returnStr = "[Object: ";
	for( var itm in this ) {
		if (typeof this[itm] != "function") {
			returnStr += itm + ": " + this[itm] + "\n";
		}
	}
	returnStr += "]";
	return returnStr;
}
