///////////////////////////////////////////////////////////////
// File Name: 	library.js
///////////////////////////////////////////////////////////////

/////////////////////////////////////
// Note that ModernCF automatically sets the following javascript variables to make
// them available to functions:
// MCFResourcesPath
/////////////////////////////////////

/////////////////////////////////////
// popupWindow: To provide consistency in the way popup select windows appear.
/////////////////////////////////////
function popupWindow(windowName,width,height) {
	eval("var " + windowName + " = window.open('','" + windowName + "','width=" + width + ",height=" + height + ",resizable=1,scrollbars=1')");
	eval(windowName + ".focus()");
	return eval(windowName);
}
function popupWindow2(windowName,options) {
	eval("var " + windowName + " = window.open('','" + windowName + "','" + options + "')");
	eval(windowName + ".focus()");
	return eval(windowName);
}

function popupFull(windowName,options) {
	if (options == null) options = "scrollbars=yes,resizable=yes, statusbar=yes,toolbar=yes,menubar=yes,location=yes";
	var top = 0;
	var left = 0;
	var height = screen.availHeight - 100;
	var width = screen.availWidth - 20;
	if (height > 768) {
		height = 768;
	}
	if (width > 1024) {
		width = 1024;
	}
	options = "height=" + height + ",width=" + width + ",top=" + top + ",left=" + left + "," + options;
	return popupWindow2(windowName,options);
}

function popupDialog(windowName,width,height,options) {
	if (options == null) options = "status=no,toolbar=no,menubar=no,location=no";
	var top = (screen.availHeight - height) / 2;
	var left = (screen.availWidth - width) / 2;
	options = "height=" + height + ",width=" + width + ",top=" + top + ",left=" + left + "," + options;
	return popupWindow2(windowName,options);
}

function upperCase(fieldObj) {
	fieldObj.value = fieldObj.value.toUpperCase();
}

function lowerCase(fieldObj) {
	fieldObj.value = fieldObj.value.toLowerCase();
}

/////////////////////////////////////
// titleCase
/////////////////////////////////////
function titleCase(fieldObj) {
	words = fieldObj.value.split(" ");
	// List of words that remain lower case in titles
	exceptions = ",a,an,the,and,but,or,nor,so,to,as,at,by,for,from,in,into,of,on,onto,to,with,";
	for (var i = 0; i < words.length; i ++) {
		if (i == 0 || exceptions.indexOf("," + words[i].toLowerCase() + ",") == -1) {
			// Get index of first letter
			firstLetterIndex = words[i].search(/\w/);
			words[i] = words[i].substring(0,firstLetterIndex+1).toUpperCase() + words[i].substring(firstLetterIndex+1,words[i].length).toLowerCase()
		} else {
			words[i] = words[i].toLowerCase();
		}
	}
	fieldObj.value = words.join(" ");
}


/////////////////////////////////////
// stripHTML: remove all html tags from a string.
/////////////////////////////////////
function stripHTML(s) {
	s = s.replace(/<[^>]*>/g," ");
	s = s.replace(/&nbsp;/g," ");
	s = trim(s);
	return s;
}

/////////////////////////////////////
// trim: remove leading and trailing white space.
/////////////////////////////////////
function trim(s) {
	s = s.replace(/(^\s|\s$)/g,"");
	return s;
}


/////////////////////////////////////
// setChecked: set multiple checkboxes to checked or unchecked
//   checked = true or false
//   pattern = all checkboxes with ids that match this regular expression will be affected.
//             if omitted all checkboxes will be affected
/////////////////////////////////////
function setChecked(formObj,checked,pattern) {
	if (pattern != null) re = new RegExp("^" + pattern + "$","i");
	var e = formObj.elements;
	for (var i = 0; i < e.length; i ++) {
		if (e[i].type == "checkbox") {
			if (pattern == null || e[i].id.search(re) != -1) {
				e[i].checked = checked;
			}
		}
	}
}




/////////////////////////////////////
// showHide: toggle visibility for an object
/////////////////////////////////////
var zIndex = 1;
function showHide(obj,sh) {
	if (sh == null) {
		if (obj.style.visibility == "hidden") {
			sh = "show";
		} else {
			sh = "hide";
		}
	}
	if (sh == "show") {
		_setSelectVisibility("hidden",obj);
		zIndex ++;
		obj.style.zIndex = zIndex;
		obj.style.visibility = "visible";
	} else {
		_setSelectVisibility("visible",obj);
		obj.style.visibility = "hidden";
	}
}

/////////////////////////////////////
// toggleDisplay: toggle display for an object
/////////////////////////////////////
function toggleDisplay(obj,sh,type) {
	if (sh == null) {
		if (obj.style.display != "none") {
			sh = "hide";
		} else {
			sh = "show";
		}
	}
	if (type == null) {
		type = "inline";
	}
	if (sh == "show") {
		obj.style.display = "inline";
	} else {
		obj.style.display = "none";
	}
}

/////////////////////
//// Initialize 2D array of select objects and positions.  Used by _setSelectVisibility
//// Select objects are windowed and therefore don't obey the zIndex (at least at the time of this writing)
//// Therefore, they need to be hidden if they are in the way of an object.
var _selectObjects = new Array();
function _setSelectObjects() {
	var x = 0;
	if (document.forms) {
		for (var i = 0; i < document.forms.length; i ++) {
			for (var n = 0; n < document.forms[i].elements.length; n ++) {
				element = document.forms[i].elements[n];
				// If select object and may overlap menu, hide it.
				if (element.type == "select-multiple" || element.type == "select-one") {
					var _eTop = _totalOffsetTop(element);
					var _eLeft = _totalOffsetLeft(element);
					var _eBottom = _eTop + element.offsetHeight;
					var _eRight = _eLeft + element.offsetWidth;
					_selectObjects[x] = new Array(element,_eTop,_eLeft,_eBottom,_eRight);
					x ++;
				}
			}
		}
	}
}
// The following should be set in the templates that need them
//window.onload = _setSelectObjects;
//window.onresize = _setSelectObjects;
////////////////////

/////////////////////
//// Get total offsetTop
function _totalOffsetTop(element) {
	var object = element;
	var totalOffset = object.offsetTop;
	while (object.offsetParent) {
		object = object.offsetParent;
		totalOffset += object.offsetTop;
	}
	return totalOffset;
}
////////////////////

/////////////////////
//// Get total offsetLeft
function _totalOffsetLeft(element) {
	var object = element;
	var totalOffset = object.offsetLeft;
	while (object.offsetParent) {
		object = object.offsetParent;
		totalOffset += object.offsetLeft;
	}
	return totalOffset;
}
////////////////////

/////////////////////
//// Hide select objects
function _setSelectVisibility(visibility,obj) {
	if (visibility == "hidden") {
		var menuTop = _totalOffsetTop(obj);
		var menuLeft = _totalOffsetLeft(obj);
		var menuBottom = menuTop + obj.offsetHeight;
		var menuRight = menuLeft + obj.offsetWidth;
		for (var i = 0; i < _selectObjects.length; i ++) {
			_eTop = _selectObjects[i][1];
			_eLeft = _selectObjects[i][2];
			_eBottom = _selectObjects[i][3];
			_eRight = _selectObjects[i][4];
			// If select object overlaps menu, hide it.
			if (((menuTop < _eTop && _eTop < menuBottom) || (menuTop < _eBottom && _eBottom < menuBottom) || (_eTop < menuTop && _eBottom > menuBottom) || (_eTop > menuTop && _eBottom < menuBottom))
			&& ((menuLeft < _eLeft && _eLeft < menuRight) || (menuLeft < _eRight && _eRight < menuRight) || (_eLeft < menuLeft && _eRight > menuRight) || (_eLeft > menuLeft && _eRight < menuRight))) {
				_selectObjects[i][0].style.visibility = "hidden";
			}
		}
	} else {
		for (var i = 0; i < _selectObjects.length; i ++) {
			_selectObjects[i][0].style.visibility = "visible";
		}
	}
}
////////////////////



///////////////////////////////////////////////////////////////
// Functions to swap sibling objects
///////////////////////////////////////////////////////////////
function moveObjUp(o) {
	if (o.previousSibling != null) {
		var p = o.parentNode;
		var s = o.previousSibling;
		var c = p.removeChild(o);
		p.insertBefore(c,s);
	}
}
function moveObjDown(o) {
	if (o.nextSibling != null) {
		var p = o.parentNode;
		var s = p.removeChild(o.nextSibling);
		p.insertBefore(s,o);
	}
}


///////////////////////////////////////////////////////////////
// Functions for select objects
///////////////////////////////////////////////////////////////

// Move selected options up, if there is room
function moveUp(obj) {
	// For Netscape 6, keep array of selected options to select afterwards
	selectedArray = new Array();
	for (i = 1; i < obj.length; i ++) {
		if (obj[i].selected && !obj[i-1].selected) {
			scrollTop = obj[i].scrollTop;
			moveObjUp(obj[i]);
			obj[i].scrollTop = scrollTop - obj[i].offsetHeight;
			selectedArray.push(i-1);
		}
	}
	for (n = 0; n < selectedArray.length; n ++) {
		obj[selectedArray[n]].selected = true;
	}
}
// Move selected options down, if there is room
function moveDown(obj) {
	// For Netscape 6, keep array of selected options to select afterwards
	selectedArray = new Array();
	for (i = obj.length - 2; i > -1; i --) {
		if (obj[i].selected && !obj[i+1].selected) {
			scrollTop = obj[i].scrollTop;
			moveObjDown(obj[i]);
			obj[i].scrollTop = scrollTop + obj[i].offsetHeight;
			selectedArray.push(i+1);
		}
	}
	for (n = 0; n < selectedArray.length; n ++) {
		obj[selectedArray[n]].selected = true;
	}
}
function selectAll (selectObj) {
	for (i=0; i < selectObj.length; i++) {
		selectObj.options[i].selected = true;
	}
}



///////////////////////////////////////////////////////////////
// Form Validation
// Author: 	David Hammond, based on Netscape library
// Description: General form validation functions
///////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////
// VARIABLE DECLARATIONS
///////////////////////////////////////////////////////////////

// regualar expression definitions
var reWhitespace = /^\s+$/
var reEmail = /^.+\@.+\..+$/
var reFloat = /^((\d+(\.\d*)?)|((\d*\.)?\d+))$/

// prompts for "missing" information
var mPrefix = "You did not enter a value into the \""
var mSuffix = "\" field. This is a required field. Please enter it now."
var mPrefix2 = "You did not select a value for \""
var mSuffix2 = "\". This information is required. Please select a value now."

// prompts for "invalid" information
var iEmail = "We have detected an invalid e-mail address. Please review the e-mail address you've entered and try again."


///////////////////////////////////////////////////////////////
// BASIC DATA VALIDATION FUNCTIONS
///////////////////////////////////////////////////////////////

// Check whether string s is empty.
function isEmpty(s) {
	return ((s == null) || (s.length == 0))
}

// Returns true if string s is empty or
// whitespace characters only.
function isWhitespace (s) {
    return (isEmpty(s) || reWhitespace.test(s));
}

// isEmail (STRING s)
function isEmail (s) {
	return reEmail.test(s)
}

// general purpose function to see if a suspected numeric input
// is not empty and is a positive integer
function isNumber(s) {
	return reFloat.test(s)
}



///////////////////////////////////////////////////////////////
// FUNCTIONS TO PROMPT USER
///////////////////////////////////////////////////////////////

// Notify user that required field fieldObj is empty.
// String s describes expected contents of fieldObj.value.
// Put focus in fieldObj and return false.
function warnEmpty (fieldObj, s) {
	if (fieldObj.type != "hidden") {
		fieldObj.focus();
	}
    alert(mPrefix + s + mSuffix);
    return false
}

// Notify user that contents of field fieldObj are invalid.
// String s describes expected contents of fieldObj.value.
// Put select fieldObj, pu focus in it, and return false.
function warnInvalid (fieldObj, s) {
	if (fieldObj.type != "hidden") {
		fieldObj.focus();
	    fieldObj.select()
	}
    alert(s)
    return false
}


///////////////////////////////////////////////////////////////
// FUNCTIONS TO INTERACTIVELY CHECK FIELD CONTENTS
///////////////////////////////////////////////////////////////

// checkText (TEXTFIELD fieldObj, STRING s)
//
// Check that string fieldObj.value is not all whitespace.
function checkText (fieldObj, s) {
	if (isWhitespace(fieldObj.value)) return warnEmpty (fieldObj, s);
    else return true;
}


// checkLength (TEXTAREA fieldObj, INT maxlength, STRING s)
//
// Check length of string fieldObj.value
function checkLength(fieldObj,maxLength,s) {
	if (fieldObj.value.length > maxLength) {
		return warnInvalid (fieldObj, "The value in the \"" + s + "\" field cannot have more than " + maxLength + " characters.\nIt currently has " + fieldObj.value.length + " characters");
	} else {
		return true;
	}
}


// checkChecked (RADIO|CHECKBOX fieldObj, STRING s)
//
// Check that at least one radio or checkbox is checked
function checkChecked (fieldObj, s) {
	if (fieldObj.length) {
		for (i=0; i < fieldObj.length; i++) {
			if (fieldObj[i].checked) return true;
		}
		fieldObj[0].focus();
	} else {
		if (fieldObj.checked) return true;
		fieldObj.focus();
	}
	alert(mPrefix2 + s + mSuffix2);
	return false;
}

// checkSelected (SELECT fieldObj, STRING s)
//
// Check that at least one option has been selected, and it has a value
function checkSelected (fieldObj, s) {
	for (i=0; i < fieldObj.length; i++) {
		if (fieldObj.options[i].selected && fieldObj.options[i].value.length > 0)	return true;
	}
	fieldObj.focus();
	alert(mPrefix2 + s + mSuffix2);
	return false;
}


// checkEmail (TEXTFIELD fieldObj)
//
// Check that string fieldObj.value is a valid Email.
// It is assumed that empty is okay. Run checkText first if this is required
function checkEmail (fieldObj) {
	if (fieldObj.value != "") {
		if (!isEmail(fieldObj.value)) return warnInvalid (fieldObj, iEmail);
	}
	return true;
}


// checkNumber (TEXTFIELD fieldObj)
//
// Check that string fieldObj.value is a valid number.
// It is assumed that empty is okay. Run checkText first if this is required
function checkNumber(fieldObj, s) {
	// Strip legitimate characters that will cause SQL problems
	var value = fieldObj.value;
	value = value.replace(/[$,]/g,"");
	if (value == "") {
		fieldObj.value = value;
		return true;
	}
	if (!isNumber(value)) {
		return warnInvalid (fieldObj, "The value in field " + s + " must be a number.");
	} else {
		fieldObj.value = value;
		return true;
	}
}


// checkDate (TEXTFIELD fieldObj)
//
// This function accepts a string variable and verifies if it is a
// proper date or not. It validates format matching either
// mm-dd-yyyy or mm/dd/yyyy. Then it checks to make sure the month
// has the proper number of days, based on which month it is.
//
// It is assumed that empty is okay. Run checkText first if this is required
function checkDate(fieldObj, s) {
	dateStr = fieldObj.value;
	if (isEmpty(dateStr)) return true;

	var datePat = /^(\d{1,2})(\/|-)(\d{1,2})(\/|-)((\d{2}|\d{4}))$/;
	var matchArray = dateStr.match(datePat); // is the format ok?
	if (matchArray == null) {
		return warnInvalid (fieldObj,"Value in field " + s + " must be in the form of mm/dd/yyyy.");
	}
	month = matchArray[1]; // parse date into variables
	day = matchArray[3];
	year = matchArray[5];
	if (month < 1 || month > 12) { // check month range
		return warnInvalid (fieldObj,"Month must be between 1 and 12 for field " + s + ".");
	}
	if (day < 1 || day > 31) {
		return warnInvalid (fieldObj,"Day must be between 1 and 31 for field " + s + ".");
	}
	if ((month==4 || month==6 || month==9 || month==11) && day==31) {
		return warnInvalid (fieldObj,"Month "+month+" doesn't have 31 days for field " + s + ".")
	}
	if (month == 2) { // check for february 29th
		var isleap = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
		if (day > 29 || (day==29 && !isleap)) {
			return warnInvalid (fieldObj,"February " + year + " doesn't have " + day + " days for field " + s + ".");
		}
	}
	return true; // date is valid
}

// checkPhone (TEXTFIELD fieldObj)
//
// Check that string fieldObj.value is a valid phone number.
// It is assumed that empty is okay. Run checkText first if this is required
function checkPhone(fieldObj, s) {
	// Strip legitimate characters that will cause SQL problems
	var value = fieldObj.value;
	if (value == "") {
		return true;
	}
	value = value.replace(/\(/g,"");
	value = value.replace(/\)/g,"");
	value = value.replace(/[\s.x-]/g,"");
	if (!isNumber(value)) {
		return warnInvalid (fieldObj, "The value in field " + s + " must be a valid phone number.");
	}
	if (value.length < 10) {
		return warnInvalid (fieldObj, "The value in field " + s + " must be a valid phone number.");
	}
	return true;
}


///////////////////////////////////////////////////////////////
// OTHER UTILITY FUNCTIONS
///////////////////////////////////////////////////////////////


// Get value of checked radio button or checkbox if multiple are present
function getCheckedValue (fieldObj) {
	for (var i = 0; i < fieldObj.length; i++) {
		if (fieldObj[i].checked) { break }
    }
    return fieldObj[i].value
}

// Get value of selected option
function getSelectedValue (fieldObj) {
	for (var i = 0; i < fieldObj.length; i++) {
		if (fieldObj[i].selected) {
			return fieldObj[i].value
		}
    }
    return "";
}


// Simple non-re replace function
function replace(s,subexpr,replacestring) {
	var i = s.indexOf(subexpr);
	if (i > -1) {
		s = s.substring(0,i) + s.substring(i + subexpr.length, s.length)
	}
	return s;
}




function getScrollWidth(win) {
	if (win == null) win = window;
	var w = win.pageXOffset || win.document.body.scrollLeft || win.document.documentElement.scrollLeft;
	return w ? w : 0;
}
function getScrollHeight(win) {
	if (win == null) win = window;
	var h = win.pageYOffset || win.document.body.scrollTop || win.document.documentElement.scrollTop;
	return h ? h : 0;
}
