// %%%%%%%%%% ARRAY PROTOTYPE ADDITION %%%%%%%%

Array.prototype.inArray = function(theVal) {
	var i=0;
	var indexFound = -1;
	
	while ((i < this.length) && (indexFound == -1)) {
		if (this[i] == theVal)
			indexFound = i;
		i++;
		}
	return indexFound;
	}

Array.prototype.removeAt = function(index) {
	var i = index;
	while (i < this.length-1) {
		this[i] = this[i+1];
		i++;
		}
	this.length--;
	}
	
Array.prototype.push = function(obj) {
	this[this.length] = obj;
	}



// %%%%%%%%%% ERROR COLLECTION %%%%%%%%%%%%%%%

function ErrorObject(objField, errorMessage, includeFieldNameInMessage) {
	this.objField = objField;
	this.errorMessage = errorMessage;
	this.includeFieldNameInMessage = includeFieldNameInMessage;
	}


function ErrorCollection() {
	this.init();
	}
	
ErrorCollection.prototype.init = function() {
	this.arrItems = [];

	if (this.getErrorBox())
		this.getErrorBox().style.display = 'none';
	}

ErrorCollection.prototype.add = function(objField, errorMessage, includeFieldNameInMessage) {
	var objError = new ErrorObject(objField, errorMessage, includeFieldNameInMessage);
	this.arrItems.push(objError);
	}

// function flushes errors to either the HTML container passed into the function, or if none specified,
// 	the error HTML container defined on the page, or if none is present, alert() the error(s)
//  - returns true if there were any errors present, false otherwise
ErrorCollection.prototype.flush = function(objDiv) {
	var errorToDisplay = '';
	var objErrorBox = (objDiv ? objDiv : this.getErrorBox());
	var lineSeparator = objErrorBox ? '<br>' : '\n';
	

	for (var i=0; i < this.arrItems.length; i++) {
		var errorText = '';
		if (this.arrItems[i].objField && this.arrItems[i].objField.title && this.arrItems[i].includeFieldNameInMessage)
			errorText = this.arrItems[i].objField.title + ' ';
			
		errorText = errorText + this.arrItems[i].errorMessage;
		
		errorToDisplay += '- ' + errorText + lineSeparator;
		}

	this.init();

	if (errorToDisplay.length > 0) {
		if (objErrorBox) {
			objErrorBox.innerHTML = errorToDisplay;
			objErrorBox.style.display = 'block';
			
			if (objErrorBox == this.getErrorBox()) {
				var newUrl = new String(document.location);
				var poundPosition = newUrl.indexOf('#');
			
				if (poundPosition > -1)
					newUrl = newUrl.substring(0, poundPosition);

				document.location = newUrl + '#';
				}
			} // if this.getErrorBox()
		else
			alert(errorToDisplay);

		return true;
		}
	else 
		return false;
	}

ErrorCollection.prototype.getErrorBox = function() {
	return document.getElementById('errorBox');
	}

var g_objErrors = new ErrorCollection();


// %%%%%%%%%%% CONVENIENCE CLASS FOR WORKING WITH TABLES %%%%%%%%%%%%%% */

function Table (objTable) {
	this.objTable = objTable;
	
	if (this.objTable.tBodies[0])
		this.objTable = this.objTable.tBodies[0];
	}
	
Table.prototype.newRow = function() {
	return document.createElement('tr');
	}
	
Table.prototype.newCell = function() {
	return document.createElement('td');
	}
	
Table.prototype.appendRow = function() {
	var objTr = this.newRow();
	this.objTable.appendChild(objTr);
	return objTr;
	}
	
Table.prototype.appendCell = function(objTr) {
	var objTd = this.newCell();

	// if no row was passed, add to the last row in the table
	if (!objTr) {
		var arrRows = this.objTable.getElementsByTagName('tr');
		var objTr = arrRows[arrRows.length-1];
		}
	
	objTr.appendChild(objTd);
	return objTd;
	}




// %%%%%%%%%%%% VALIDATION FUNCTIONS %%%%%%%%%%%%%%%%

function validateField(objField, theDataType, isRequired, minValue, maxValue, trimWhiteSpace) {

	var isValid = true;
	var fieldType = '';
	var isFieldText = false;
	
	if (objField && !objField.disabled) {
		if (objField.type)
			fieldType = objField.type;

		isFieldText = (fieldType == 'text') || (fieldType == 'password') || (fieldType == 'hidden') || (fieldType == 'textarea');
	
	
		if (trimWhiteSpace && isFieldText)
			objField.value=((new String(objField.value)).replace(/^(\s*)([\W\w]*)(\b\s*$)/, '$2').replace(/^\s+$/, ''));
				
		if (isRequired) {
			if (isFieldText) {
				if (objField.value.length == 0) {
					g_objErrors.add(objField, 'is required', true);
					isValid = false;
					}
				else if (minValue && objField.value.length < minValue) {
					g_objErrors.add(objField, 'must be at least ' + minValue + ' characters', true);
					isValid = false;
					}
				else if (maxValue && objField.value.length > maxValue) {
					g_objErrors.add(objField, 'may not exceed ' + maxValue + ' characters', true);
					isValid = false;
					}
				} // if (isFieldText)
			else if (theDataType == 'radio') {
				var isValid = false;
				
				if (objField[1]) {
					for (var i=0; i < objField.length; i++) {
						if (objField[i].checked) {
							isValid=true;
							break;
							} // if (objField[i].checked)
						} // for i = 0 to objField.length

					if (!isValid)
						g_objErrors.add(objField[0], 'is required', true);
					} // if (objField[1])
				else {
					isValid = objField.checked;

					if (!isValid)
						g_objErrors.add(objField, 'is required', true);
					} // else

				} // if (theDataType == 'radio')
			else if (theDataType == 'select') {
				var isSelected = (objField.selectedIndex > -1);
				if (isSelected)
					isSelected = (objField.options[objField.selectedIndex].value != '');
				
				if (!isSelected) {
					g_objErrors.add(objField, 'is required', true);
					isValid = false;
					} // if (!isSelected)
				} // if theDataType == 'select'
			} // if (isRequired)

		// required test has passed, now check content
		if (isValid && objField.type && (objField.type == 'text') && (objField.value.length > 0)) {
			var newValue = null;

			switch (theDataType) {
				case 'email':
					newValue = formatEmail(objField.value);
					if (!newValue) {
						g_objErrors.add(objField, 'requires a valid email address', true);
						isValid = false;
						}
					break;

				case 'phone':
					newValue = formatPhone(objField.value);
					if (newValue)
						objField.value = newValue;
					else {
						g_objErrors.add(objField, 'requires a valid phone number', true);
						isValid = false;
						}
					break;

				case 'zip':
					newValue = formatZip(objField.value);
					if (newValue)
						objField.value = newValue;
					else {
						g_objErrors.add(objField, 'requires a valid numeric zip code', true);
						isValid = false;
						}
					break;
					
				case 'date':
					newValue = formatDate(objField.value);

					if (!newValue) {
						g_objErrors.add(objField, 'requires a valid date in the form mm/dd/yyyy', true);
						isValid = false;
						}
					
					else {
						msEnteredDate = Date.parse(newValue);
						msMinDate = Date.parse(minValue);
						msMaxDate = Date.parse(maxValue);
					
						// if the date entered is valid
						if (!isNaN(msEnteredDate)) {
							if (!isNaN(msMinDate) && !isNaN(msMaxDate)) {
								if ((msEnteredDate < msMinDate) || (msEnteredDate > msMaxDate)) {
									g_objErrors.add(objField, 'requires a date between ' + formatDate(minValue) + ' and ' + formatDate(maxValue), true);
									isValid = false;
									}
								}

							else if (!isNaN(msMinDate)) {
								if (msEnteredDate < msMinDate) {
									g_objErrors.add(objField, 'requires a date after ' + formatDate(minValue), true);
									isValid = false;
									}
								}
								
							else if (!isNaN(msMaxDate)) {
								if (msEnteredDate > msMaxDate) {
									g_objErrors.add(objField, 'requires a date prior to ' + formatDate(maxValue), true);
									}
								}

							} // if (!isNaN(msEnteredDate)
						} // else
						
					if (newValue && isValid)
						objField.value = newValue;
					break;
				} // switch (theDataType)
			} // if (isValid)

		} // if (!objField.disabled)

		return isValid;
	}
	
	
// %%%%%%%%%% FORMAT FUNCTIONS %%%%%%%%%%%%%

g_zipInvalidRegexMask = /[^0-9]*/gi;
g_zip9ValidRegexMask = /([0-9]{5})([0-9]{4})/gi;
g_zip9ReplaceRegexMask = '$1-$2';

function formatZip(textToFormat) {
	var workingText = textToFormat.replace(g_zipInvalidRegexMask, '');
	var formattedText = null;
	
	if (!isNaN(workingText)) {
		if (workingText.length == 9)
			formattedText = workingText.replace(g_zip9ValidRegexMask, g_zip9ReplaceRegexMask);
		else if (workingText.length == 5)
			formattedText = workingText;
		} // if (!isNaN(workingText))

	return formattedText;
	}

g_phoneInvalidRegexMask = /[^0-9]*/gi;
g_phoneValidRegexMask = /([0-9]{3})([0-9]{3})([0-9]{4})/gi;
g_phoneReplaceRegexMask = '($1) $2-$3';

function formatPhone(textToFormat) {
	var workingText = textToFormat.replace(g_phoneInvalidRegexMask, '');
	var formattedText = null;
	
	if (!isNaN(workingText) && (workingText.length == 10)) 
		formattedText = workingText.replace(g_phoneValidRegexMask, g_phoneReplaceRegexMask);
	return formattedText;
	}

g_emailValidRegexMask = /([a-z0-9]+[\.\+\_\-a-z0-9]*@[a-z0-9]+[\.\+\_\-a-z0-9]*\.[a-z]{2,6})/gi;

function formatEmail(textToFormat) {
	var workingText = textToFormat;
	var formattedText = null;
	
	if (workingText.replace(g_emailValidRegexMask, '__blah__') == '__blah__')
		formattedText = workingText;
	
	return formattedText;
	}

function formatDate(textToFormat) {
	var formattedText = null;
	var msDate = null;
	var theYear = -1;
	var theMonth = -1;
	var theDay = -1;
	
	var dateMask = textToFormat.replace(/[0-9]/gi, 'x');
	dateMask = dateMask.replace(/[^x]/gi, '/');

	var isValidDateMask = true;
	
	switch (dateMask) {
		case 'xxxxxx':
			theMonth = textToFormat.substr(0, 2);
			theDay = textToFormat.substr(2, 2);
			theYear = textToFormat.substr(4, 2);
			break;

		case 'xxxxxxxx':
			theMonth = textToFormat.substr(0, 2);
			theDay = textToFormat.substr(2, 2);
			theYear = textToFormat.substr(4, 4);
			break;
		
		case 'x/x/x':
			theMonth = textToFormat.substr(0, 1);
			theDay = textToFormat.substr(2, 1);
			theYear = textToFormat.substr(4, 1);
			break;

		case 'xx/x/x':
			theMonth = textToFormat.substr(0, 2);
			theDay = textToFormat.substr(3, 1);
			theYear = textToFormat.substr(5, 1);
			break;

		case 'x/xx/x':
			theMonth = textToFormat.substr(0, 1);
			theDay = textToFormat.substr(2, 2);
			theYear = textToFormat.substr(5, 1);
			break;

		case 'xx/xx/x':
			theMonth = textToFormat.substr(0, 2);
			theDay = textToFormat.substr(3, 2);
			theYear = textToFormat.substr(6, 1);
			break;

		case 'x/x/xx':
			theMonth = textToFormat.substr(0, 1);
			theDay = textToFormat.substr(2, 1);
			theYear = textToFormat.substr(4, 2);
			break;

		case 'xx/x/xx':
			theMonth = textToFormat.substr(0, 2);
			theDay = textToFormat.substr(3, 1);
			theYear = textToFormat.substr(5, 2);
			break;

		case 'x/xx/xx':
			theMonth = textToFormat.substr(0, 1);
			theDay = textToFormat.substr(2, 2);
			theYear = textToFormat.substr(5, 2);
			break;

		case 'xx/xx/xx':
			theMonth = textToFormat.substr(0, 2);
			theDay = textToFormat.substr(3, 2);
			theYear = textToFormat.substr(6, 2);
			break;

		case 'x/x/xxxx':
			theMonth = textToFormat.substr(0, 1);
			theDay = textToFormat.substr(2, 1);
			theYear = textToFormat.substr(4, 4);
			break;

		case 'xx/x/xxxx':
			theMonth = textToFormat.substr(0, 2);
			theDay = textToFormat.substr(3, 1);
			theYear = textToFormat.substr(5, 4);
			break;

		case 'x/xx/xxxx':
			theMonth = textToFormat.substr(0, 1);
			theDay = textToFormat.substr(2, 2);
			theYear = textToFormat.substr(5, 4);
			break;

		case 'xx/xx/xxxx':
			theMonth = textToFormat.substr(0, 2);
			theDay = textToFormat.substr(3, 2);
			theYear = textToFormat.substr(6, 4);
			break;
			
		default:
			isValidDateMask = false;
			break;
		}

	if (isValidDateMask) {
		if (theYear < 100) {
			if (theYear < 30)
				theYear = '20' + theYear;
			else
				theYear = '19' + theYear;
			}

		var formattedDate = new String(theMonth + '/' + theDay + '/' + theYear);
		msDate = Date.parse(formattedDate);

		if (theMonth > 12)
			msDate = null;
	
		else {
			switch (theMonth) {
				case '9':
				case '4':
				case '6':
				case '11':
					if (theDay > 30)
						msDate = null;
					break;
		
				case '2':
					if (theDay > 29)
						msDate = null;
					break;
			
				default:
					if (theDay > 31)
						msDate = null;
					break;
				}
			}

		if (msDate && !isNaN(msDate)) {	
			var objDate = new Date();
			objDate.setTime(msDate);

			formattedText = (objDate.getMonth()+1) + '/' + objDate.getDate() + '/' + objDate.getFullYear();
			}
		} // if(isValidDateMask)
	return formattedText;
	}


function htmlEditFormat(textToFormat) {
	var formattedText = new String(textToFormat);
	
	formattedText = formattedText.replace(/\"/gi, '&quot;');
	formattedText = formattedText.replace(/\</gi, '&lt;');
	formattedText = formattedText.replace(/\>/gi, '&gt;');
	
	return formattedText;
	}



/* %%%%%%%%% UTILITY FUNCTIONS %%%%%%%%%%%%%%%%%% */
function $(id, adderId) {
	return document.getElementById(id + (adderId ? '_' + adderId : ''));
	}
	
function $id(id, adderId) {
	return document.getElementById(id + (adderId ? '_' + adderId : ''));
	}
	
function getSelectValue(objSelect) {
	var theValue = null;
	
	if (objSelect.selectedIndex >= 0)
		theValue = objSelect.options[objSelect.selectedIndex].value;

	return theValue;
	}

function setSelectToValue(objSelect, theValue) {	
	var foundIndex = null;
	var selectedIndex = 0;
	
	while (!foundIndex && (selectedIndex < objSelect.options.length)) {
		if (objSelect.options[selectedIndex].value == theValue) 
			foundIndex = selectedIndex;
		
		selectedIndex++;
		}

	if (foundIndex)
		objSelect.selectedIndex = foundIndex;
	}

function getRadioCheckedValue(objRadio) {
	var returnedValue = null;
	
	if (objRadio[1]) {
		var radioIndex = 0;
		while (!returnedValue && (radioIndex < objRadio.length)) {
			if (objRadio[radioIndex].checked)
				returnedValue = objRadio[radioIndex].value;
			
			radioIndex++;
			} // while
		} // if (objRadio[1])

	else if (objRadio.checked)
		returnedValue = objRadio.value;
		
	return returnedValue;
	}

/* %%%%%%%% GLOBAL IDENTIFIER CODE %%%%%%%%%%% */
function GlobalId(seedValue) {
	this.id = seedValue ? seedValue : 0;
	this.arrItems = new Array();
	}

GlobalId.prototype.nextVal = function(obj) {
	this.id++;
	this.arrItems[this.id] = obj;
	return this.id;
	}

GlobalId.prototype.currentVal = function() {
	return this.id;
	}

GlobalId.prototype.get = function(id) {
	return this.arrItems[id];
	}
	


