function valid_form(myForm) {
	var return_value = true;
	var error_message = '';
	required_fields = getElementsByClassName("required", "*", myForm);

	var length = required_fields.length;

	for (var i = 0; i < length; i++) {
		var label = required_fields[i].getElementsByTagName('label');
		var complete = false;
		var label_text = label[0].innerHTML;
		if (label[0].className == "complete") {
			complete = true;
		}

		var input_field = required_fields[i].getElementsByTagName('input');
		var input_length = input_field.length;
		for (j = 0; j < input_length; j++) {
			if (input_field[j].value == '' || in_array(input_field[j].value, masks)) {
				if (complete) {
					error_message += label_text + " \n";
				} else {
					error_message += label_text + " has not been entered \n";
				}
				return_value = false;
			}
		}
		var textarea_field = required_fields[i].getElementsByTagName('textarea');
		var textarea_length = textarea_field.length;
		for (j = 0; j < textarea_length; j++) {
			if (textarea_field[j].value == '') {
				if (complete) {
					error_message += label_text + " \n";
				} else {
					error_message += label_text + " has not been filled in \n";
				}
				return_value = false;
			}
		}
		var select_field = required_fields[i].getElementsByTagName('select');
		var select_length = select_field.length;
		for (j = 0; j < select_length; j++) {
			if (select_field[j].selectedIndex == -1 || (select_field[j].options.length != 0 && select_field[j].options[select_field[j].selectedIndex].value == "")) {
				if (complete) {
					error_message += label_text + " \n";
				} else {
					error_message += label_text + " has not been selected \n";
				}
				return_value = false;
			}
		}
	}

	if (return_value == false) {
		display_error(error_message);
	}
	return return_value;
}
function display_error(err_message) {
	var error_message = 'Please correct the following errors:\n';
	error_message += '-----------------------------------------\n';
	error_message += err_message;
	error_message += '-----------------------------------------\n\n';
	error_message += 'Please fill in the fields to continue.'
	alert(error_message);
}
function getElementsByClassName(className, tag, elm) {
	var testClass = new RegExp("(^|\\s)" + className + "(\\s|$)");
	var tag = tag || "*";
	var elm = elm || document;
	var elements = (tag == "*" && elm.all) ? elm.all : elm.getElementsByTagName(tag);
	var returnElements = [];
	var current;
	var length = elements.length;
	for (var i = 0; i < length; i++) {
		current = elements[i];
		if (testClass.test(current.className)) {
			returnElements.push(current);
		}
	}
	return returnElements;
}

function returnObjById(id) {
	if (document.getElementById)
		var returnVar = document.getElementById(id);
	else if (document.all)
		var returnVar = document.all[id];
	else if (document.layers)
		var returnVar = document.layers[id];
	return returnVar;
}
function in_array(needle, array) {
	var return_value = false;
	var length = array.length;
	for (var i = 0; i < length; i++) {
		if (array[i] == needle) {
			return_value = true;
			break;
		}
	}

	return return_value;
}
function Hash() {
	this.length = 0;
	this.items = new Array();
	for (var i = 0; i < arguments.length; i += 2) {
		if (typeof (arguments[i + 1]) != 'undefined') {
			this.items[arguments[i]] = arguments[i + 1];
			this.length++;
		}
	}

	this.removeItem = function(in_key) {
		var tmp_value;
		if (typeof (this.items[in_key]) != 'undefined') {
			this.length--;
			var tmp_value = this.items[in_key];
			delete this.items[in_key];
		}
		return tmp_value;
	}

	this.getItem = function(in_key) {
		return this.items[in_key];
	}

	this.setItem = function(in_key, in_value) {
		if (typeof (in_value) != 'undefined') {
			if (typeof (this.items[in_key]) == 'undefined') {
				this.length++;
			}
			this.items[in_key] = in_value;
		}
		return in_value;
	}

	this.hasItem = function(in_key) {
		return typeof (this.items[in_key]) != 'undefined';
	}
}

var masks = [];
masks[0] = '####'; // number mask
masks[1] = 'mm/dd/yyyy'; // data mask
masks[2] = 'xxx-xxx-xxxx'; // phone mask
masks[3] = 'abc@def.com'; // email mask
masks[4] = '###.##'; //decimal mask
masks[5] = 'xxx-xx-xxxx'; // social security mask
masks[6] = 'HH:MM AM|PM'; // time format
var inputFormatting = function() {
	// applied when the field is populated with the mask
	var maskedColor = "#AAAAAA";
	// applied when the field contains invalid input
	var invalidColor = "#E99";
	// applied when the field contains valid input
	var validColor = "#9E9";
	// number of seconds that validColor will remain
	var validSeconds = 5;
	// storage of elements
	var stack = {};

	var Util = {
		getNodesByClass: function(css) {
			var nodes = [];

			if (document.evaluate) {
				var xpath = "//input[contains(@class, '" + css + "') and @type = 'text']";
				var iterator = document.evaluate(xpath, document, null, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
				var thisNode = iterator.iterateNext();
				while (thisNode != null) {
					nodes.push(thisNode);
					thisNode = iterator.iterateNext();
				}
			}
			else {
				var elements = document.getElementsByTagName("input");
				var length = elements.length;
				while (length--) {
					if (elements[length].className.indexOf(css) > -1 && elements[length].type == "text") {
						nodes.push(elements[length]);
					}
				}
			}
			return nodes;
		}
		, createHook: function() {
			var hook = "__inputFormatting";
			for (var x = 0; x < 5; x++) {
				hook += String.fromCharCode(((Math.round(Math.random() * 100)) % 25) + 65);
			}
			return hook;
		}
	}

	/***********************************************************************************
	 * Name: dateInput.
	 * Performs input formatting and validation on
	 * <input type='text' class='dateinput'/> elements.
	 ***********************************************************************************/
	var dateInput = function() {
		var DateUtil = {
			// This formats a Date object into the following format
			//		mm/dd/yyyy
			toShortDateString: function(date) {
				var __leftPad = function(s, desiredLength) {
					if (typeof (s) == 'number') {
						s = new Number(s).toString();
					}

					while (s.length < desiredLength) {
						s = '0' + s;
					}
					return s;
				}
				if (!isNaN(date.getMonth(date.getMonth())) && !isNaN(date.getDate()) && !isNaN(date.getFullYear())) {
					return __leftPad(date.getMonth() + 1, 2)
							+ '/'
							+ __leftPad(date.getDate(), 2)
							+ '/'
							+ date.getFullYear();
				}
				else
					return 'Invalid Date';
			}
			// This function creates Date objects from formats that are
			// unsupported by the native Date constructor
			//		formats: 
			//			mm-dd-yy[yy]
			//			mm.dd.yy[yy]
			//			mm dd yy[yy]
			, coerceFormat: function(string) {
				var converters = [
					{
						regex: /^([0-9]{1,2})[- .]([0-9]{1,2})[- .]([0-9]{2,4})$/
						, repair: function(string, match) {
							return new Date(
								match[3]					// year
								, (parseInt(match[1]) - 1)	// month
								, match[2]					// day
							);
						}
					}
				];

				for (var x = 0; x < converters.length; x++) {
					var regex = converters[x].regex;
					var repair = converters[x].repair;

					var match = regex.exec(string);
					if (match) {
						var result = repair(string, match);
						if (!(result === null)) {
							return result;
						}
					}
				}
            }
		};

		var display_helper = masks[1];
		return function() {
			var nodes = Util.getNodesByClass("dateinput");

			for (var x = 0; x < nodes.length; x++) {
				nodes[x].onblur = function() {
					if (this.value == '') {
						this.value = display_helper;
						this.style.color = maskedColor;
						this.style.backgroundColor = '';
					}
					else if (this.value == display_helper) {
						this.style.color = maskedColor;
						this.style.backgroundColor = '';
					}
					else {
						var date = new Date(this.value);
						// attempt to repair formats that are not
						// recognized by the Date constructor
						if (date == "Invalid Date") {
							date = DateUtil.coerceFormat(this.value);
						}
						if (date != null && date != "Invalid Date" && !isNaN(date)) {
							this.value = DateUtil.toShortDateString(date);
							this.style.color = '';
							this.style.backgroundColor = validColor;

							var hook = Util.createHook();
							stack[hook] = this;
							window[hook] = function() {
								stack[hook].style.backgroundColor = '';
								stack[hook] = null;
								window[hook] = null;
							}
							window.setTimeout(hook + "()", validSeconds * 60);
						}
						else {
							// invalid input
							this.style.backgroundColor = invalidColor;
						}
					}
				};
				nodes[x].onfocus = function() {
					if (this.value == display_helper) {
						this.value = '';
						this.style.color = 'black';
						this.style.backgroundColor = null;
						this.style.cursor = 'text';
					}
				}

				nodes[x].onblur();
			}
		}
	} ();

	/***********************************************************************************
	 * Name: timeInput.
	 * Performs input formatting and validation on in 15 minutes increments with or without AM|PM
	 * <input type='text' class='timeinput'/> elements.
	 ***********************************************************************************/
	var timeInput = function() {
		var nodes = Util.getNodesByClass("timeinput");
		var display_helper = masks[6];
		for (var x = 0; x < nodes.length; x++) {
			nodes[x].onblur = function() {
				if (this.value == '') {
					this.value = display_helper;
					this.style.color = maskedColor;
					this.style.backgroundColor = '';
				} else if (this.value == display_helper) {
					this.style.color = maskedColor;
					this.style.backgroundColor = '';
				} else {
					var match = /^((([0]?[1-9]|1[0-2])(:|\.)(00|15|30|45)?( )?(AM|am|aM|Am|PM|pm|pM|Pm))|(([0]?[0-9]|1[0-9]|2[0-3])(:|\.)(00|15|30|45)?))$/.exec(this.value);
					if (match) {
						// remove the 'complete match'
						match.splice(0, 1);

					// if the first element is undefined ... remove it
						if (!match[0])
							match.splice(0, 1);
						this.style.backgroundColor = validColor;

						var hook = Util.createHook();
						stack[hook] = this;
						window[hook] = function() {
							stack[hook].style.backgroundColor = '';
							stack[hook] = null;
							window[hook] = null;
						}
						window.setTimeout(hook + "()", validSeconds * 60);
					} else {
						// invalid input
						this.style.backgroundColor = invalidColor;
					}
				}
			};
			nodes[x].onfocus = function() {
				if (this.value == display_helper) {
					this.value = '';
					this.style.color = 'black';
					this.style.backgroundColor = '';
				}
			}
			nodes[x].onblur();
		}
	};

	/***********************************************************************************
	 * Name: numberInput.
	 * Performs input formatting and validation on
	 * <input type='text' class='numberinput'/> elements.
	 ***********************************************************************************/
	var numberInput = function() {
		var nodes = Util.getNodesByClass("numberinput");
		var display_helper = masks[0];
		for (var x = 0; x < nodes.length; x++) {
			nodes[x].onblur = function() {
				if (this.value == '') {
					this.value = display_helper;
					this.style.color = maskedColor;
					this.style.backgroundColor = '';
				} else if (this.value == display_helper) {
					this.style.color = maskedColor;
					this.style.backgroundColor = '';
				} else {
					var match = /^[0-9.]+$/.exec(this.value);
					if (match) {
						// remove the 'complete match'
						match.splice(0, 1);

						// if the first element is undefined ... remove it
						if (!match[0])
							match.splice(0, 1);
						this.style.backgroundColor = validColor;

						var hook = Util.createHook();
						stack[hook] = this;
						window[hook] = function() {
							stack[hook].style.backgroundColor = '';
    						stack[hook] = null;
							window[hook] = null;
						}
						window.setTimeout(hook + "()", validSeconds * 60);
					} else {
						// invalid input
						this.style.backgroundColor = invalidColor;
					}
				}
			};
			nodes[x].onfocus = function() {
    			if (this.value == display_helper) {
					this.value = '';
					this.style.color = 'black';
					this.style.backgroundColor = '';
				}
			}
			nodes[x].onblur();
		}
	};

	/***********************************************************************************
	 * Name: decimalInput.
	 * Performs input formatting and validation on
	 * <input type='text' class='decimalInput'/> elements.
	 ***********************************************************************************/
	var decimalInput = function() {
		var nodes = Util.getNodesByClass("decimalinput");
		var display_helper = masks[4];
		for (var x = 0; x < nodes.length; x++) {
			nodes[x].onblur = function() {
				if (this.value == '') {
					this.value = display_helper;
					this.style.color = maskedColor;
					this.style.backgroundColor = '';
				} else if (this.value == display_helper) {
					this.style.color = maskedColor;
					this.style.backgroundColor = '';
				} else {
					var match = /^\d*\.?\d+$/.exec(this.value);
					if (match) {
						// remove the 'complete match'
						match.splice(0, 1);

						// if the first element is undefined ... remove it
						if (!match[0])
							match.splice(0, 1);
						this.style.backgroundColor = validColor;

						var hook = Util.createHook();
						stack[hook] = this;
						window[hook] = function() {
							stack[hook].style.backgroundColor = '';
							stack[hook] = null;
							window[hook] = null;
						}
						window.setTimeout(hook + "()", validSeconds * 60);
					} else {
						// invalid input
						this.style.backgroundColor = invalidColor;
					}
				}
			};
			nodes[x].onfocus = function() {
				if (this.value == display_helper) {
					this.value = '';
					this.style.color = 'black';
					this.style.backgroundColor = '';
				}
			}
			nodes[x].onblur();
		}
	};
	/***********************************************************************************
	 * Name: ssnInput.
	 * Performs input formatting and validation on
	 * <input type='text' class='decimalInput'/> elements.
	 ***********************************************************************************/
	var ssnInput = function() {
		var nodes = Util.getNodesByClass("ssninput");
		var display_helper = masks[5];
		for (var x = 0; x < nodes.length; x++) {
			nodes[x].onblur = function() {
				if (this.value == '') {
					this.value = display_helper;
					this.style.color = maskedColor;
					this.style.backgroundColor = '';
				} else if (this.value == display_helper) {
					this.style.color = maskedColor;
					this.style.backgroundColor = '';
				} else {
					if (this.value.length == 9) {
						this.value = this.value.substring(0, 3) + '-' + this.value.substring(3, 5) + '-' + this.value.substring(5);
					}
					var match = /^(?!000)([0-6]\d{2}|7([0-6]\d|7[012]))([ -]?)(?!00)\d\d\3(?!0000)\d{4}$/.exec(this.value);
					if (match) {
						// remove the 'complete match'
						match.splice(0, 1);

						// if the first element is undefined ... remove it
						if (!match[0])
							match.splice(0, 1);
						this.style.backgroundColor = validColor;

						var hook = Util.createHook();
						stack[hook] = this;
						window[hook] = function() {
							stack[hook].style.backgroundColor = '';
							stack[hook] = null;
							window[hook] = null;
						}
						window.setTimeout(hook + "()", validSeconds * 60);
					} else {
						// invalid input
						this.style.backgroundColor = invalidColor;
					}
				}
			};
			nodes[x].onfocus = function() {
				if (this.value == display_helper) {
					this.value = '';
					this.style.color = 'black';
					this.style.backgroundColor = '';
				}
			}
			nodes[x].onblur();
		}
	};
	/***********************************************************************************
	 * Name: emailInput.
	 * Performs input formatting and validation on
	 * <input type='text' class='emailinput'/> elements.
	 ***********************************************************************************/
	var emailInput = function() {
		var nodes = Util.getNodesByClass("emailinput");
		var display_helper = masks[3];
		for (var x = 0; x < nodes.length; x++) {
			nodes[x].onblur = function() {
				if (this.value == '') {
					this.value = display_helper;
					this.style.color = maskedColor;
					this.style.backgroundColor = '';
				} else if (this.value == display_helper) {
					this.style.color = maskedColor;
					this.style.backgroundColor = '';
				} else {
					var match = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/.exec(this.value);
					if (match) {
						// remove the 'complete match'
						match.splice(0, 1);

						// if the first element is undefined ... remove it
						if (!match[0])
							match.splice(0, 1);
						this.style.backgroundColor = validColor;

						var hook = Util.createHook();
						stack[hook] = this;
						window[hook] = function() {
							stack[hook].style.backgroundColor = '';
							stack[hook] = null;
							window[hook] = null;
						}
						window.setTimeout(hook + "()", validSeconds * 60);
					} else {
						// invalid input
						this.style.backgroundColor = invalidColor;
					}
				}
			};
			nodes[x].onfocus = function() {
				if (this.value == display_helper) {
					this.value = '';
					this.style.color = 'black';
					this.style.backgroundColor = '';
				}
			}
			nodes[x].onblur();
		}
	};

	/***********************************************************************************
	 * Name: phoneInput.
	 * Performs input formatting and validation on
	 * <input type='text' class='phoneinput'/> elements.
	 ***********************************************************************************/
	var phoneInput = function() {
		var nodes = Util.getNodesByClass("phoneinput");
		var display_helper = masks[2];

		for (var x = 0; x < nodes.length; x++) {
			nodes[x].onblur = function() {
				if (this.value == '') {
					this.value = display_helper;
					this.style.color = maskedColor;
					this.style.backgroundColor = '';
				}
				else if (this.value == display_helper) {
					this.style.color = maskedColor;
					this.style.backgroundColor = '';
				}
				else {
					var match = /^([0-9]{3})+[- .]+([0-9]{3})[- .]+([0-9]{4})$/.exec(this.value);
					var match_extension = /^([0-9]{3})+[- .]+([0-9]{3})[- .]+([0-9]{4})+[x]+([0-9_]{0,10})$/.exec(this.value);
					if (match) {
						// remove the 'complete match'
						match.splice(0, 1);

						// if the first element is undefined ... remove it
						if (!match[0])
							match.splice(0, 1);
						this.value = match.join('-');
						this.style.backgroundColor = validColor;

						var hook = Util.createHook();
						stack[hook] = this;
						window[hook] = function() {
							stack[hook].style.backgroundColor = '';
							stack[hook] = null;
							window[hook] = null;
						}
						window.setTimeout(hook + "()", validSeconds * 60);
					}
					else if (match_extension) {
						// remove the 'complete match'
						match_extension.splice(0, 1);

						// if the first element is undefined ... remove it
						if (!match_extension[0])
							match_extension.splice(0, 1);
						var fullNumber = match_extension.join('-');
						var phoneNumber = fullNumber.substr(0, 12);
						var phoneExten = fullNumber.substr(13);

						this.value = phoneNumber + 'x' + phoneExten;
						this.style.backgroundColor = validColor;

						var hook = Util.createHook();
						stack[hook] = this;
						window[hook] = function() {
							stack[hook].style.backgroundColor = '';
							stack[hook] = null;
							window[hook] = null;
						}
						window.setTimeout(hook + "()", validSeconds * 60);
					}
					else {
						// invalid input
						this.style.backgroundColor = invalidColor;
					}
				}
			};
			nodes[x].onfocus = function() {
				if (this.value == display_helper) {
					this.value = '';
					this.style.color = 'black';
					this.style.backgroundColor = '';
				}
			}
			nodes[x].onblur();
		}
	};

	var onload = function() {
		dateInput();
		phoneInput();
		numberInput();
		emailInput();
		decimalInput();
		ssnInput();
		timeInput();
	};

	return function() { onload() };
} ();



// <script defer doesnt work in mozilla
if (document.addEventListener) {
	document.addEventListener("DOMContentLoaded"
		, function() {
			inputFormatting();
		}, false
	);
}
else {
	// this will be after asp.net attached to onload because of <script defer
	window.__onload = window.onload;
	window.onload = function() {
		if (typeof window.__onload == 'function') {
			window.__onload();
		}
		inputFormatting();
	}
}
