/*************************************************************************/
/*  BEGIN OF onkeypress Event Handlers
/*************************************************************************/

// the following two functions help act as "input masks" on fields to prevent erroneous data entry
// just have them called during the onKeyPress event of the control.
function forceNumeric(){
	//allows numeric values and decimal points(01234567890.)
	if ( ((event.keyCode > 47) && (event.keyCode < 58)) || (event.keyCode == 46)) 
	  event.returnValue = true;
	else
	  event.returnValue = false;
}

function forceDate(){
	//allows numeric values (code=48 - code=57) and the forward slash (code=47) and dash (code=45)  (01234567890/)
	if ((event.keyCode > 46) && (event.keyCode < 58) || (event.keyCode == 45)) 
	  event.returnValue = true;
	else
	  event.returnValue = false;
}
function forceWholeNumber(){
	//allows numeric values and decimal points(01234567890)
	if ((event.keyCode > 47) && (event.keyCode < 58)) 
	  event.returnValue = true;
	else
	  event.returnValue = false;
}
/*************************************************************************/
/*  END OF onkeypress Event Handlers
/*************************************************************************/


/*************************************************************************/
/*  BEGIN OF onblur Event Handlers
/*************************************************************************/

function textFieldBlurHandler() {
	this.value = this.value.trim()
}


function timeFieldBlurHandler() {
	var t = new Time(this.value)
	if (!isNaN(t)) this.value = t.getHumanTimeString()
}

function phoneFieldBlurHandler() {
	var temp = this.value.stripNonDecimal()

	if (temp.length > 9 && temp.length < 26){
		if (temp.length == 10) {
			this.value = "(" + temp.substring(0,3) + ")" 
			this.value += temp.substring(3,6) + "-" + temp.substring(6,10)
		}
	}
}

function zipcodeFieldBlurHandler() {
	var temp = this.value.stripNonDecimal()

	if (temp.length == 5 || temp.length == 9) { 
		if (temp.length == 5) this.value = temp
		else this.value = temp.substring(0,5) + "-" + temp.substring(5,9)
	}
}


function floatFieldBlurHandler(){
	if(this.value.length){
		var thisValue = parseFloat(this.value);
		thisValue = fixFloat(thisValue,1,".");
		this.value = thisValue;
	}
}

function intFieldBlurHandler(){
	var tv = this.value;
	if(tv.length){
		tv = parseInt(tv);
	} else{
		tv = 0
	}

	if(isNaN(tv))
		tv = 0;
	this.value = tv;
}

function ssnFieldBlurHandler(){
  var val = this.value.stripNonDecimal();
  this.value= val.substring(0,3)+'-'+val.substring(3,5)+'-'+val.substring(5,12);
}

function dateFieldBlurHandler() {
		var d = new Date(this.value)
		if (!isNaN(d)) {
			// if the user didn't specify the century/millenium,
			// then assume the present.
			if (vStr.search(/\d{3}/) == -1) 
				d.setYear(Math.floor((new Date()).getFullYear() / 100) * 100 + d.getFullYear() % 100);

			this.value = d.getDateString();
		}
}

/*************************************************************************/
/*  BEGIN OF onblur Event Handlers
/*************************************************************************/





/*************************************************************************/
/*  BEGIN OF STRING METHODS
/*************************************************************************/

// Extensions to the String class:
// var myStr = "  yomomma.mpg "
// myStr.trim() -> myStr now contains "hotdogs!"
// myStr.hasFileExtension(".mpg") -> true


// like Trim( ) in vbscript. removes trailing and 
// leading whitespace from a string
String.prototype.trim = function() {
  return this.replace(/^\s*|\s*$/g, "")
}


// determines whether or not a filename has one of the specified extensions
String.prototype.endsWith = function() {
	var bOk = false
	for (var i = 0; i < arguments.length; i++) {
		if (this.indexOf(arguments[i]) == this.length - arguments[i].length) {
			bOk = true
			break
		}
	}
	return bOk
}

String.prototype.stripAlpha = function(b) {
	  return this.replace(/\a/g,'')
}
String.prototype.stripNonAlpha = function(b) {
	  return this.replace(/\A/g,'')
}
String.prototype.stripDecimal = function(b) {
	  return this.replace(/\d/g,'')
}
String.prototype.stripNonDecimal = function(b) {
	  return this.replace(/\D/g,'')
}
String.prototype.stripAlphaNumeric = function() {
	  return this.replace(/\w/g,'')
}
String.prototype.stripNonAlphaNumeric = function() {
	  return this.replace(/\W/g,'')
}

/*************************************************************************/
/*  END OF STRING METHODS
/*************************************************************************/



/*************************************************************************/
/*  BEGIN OF DATE METHODS
/*************************************************************************/

// Extensions to the Date class:
// var myDate = new Date();
// myDate.getMonthName(); -> "February"
// myDate.getHumanDateString(); -> "February 29, 2000"
// myDate.getHumanTimeString(); -> "4:00 pm"


// returns the name of the month
Date.prototype.getMonthName = function() {
	return ["January","February","March","April","May","June","July","August",
			"September","October","November","December"][this.getMonth()]
}

// returns the number of the month
Date.prototype.getMonthNumber = function() {
	return ["1","2","3","4","5","6","7","8",
			"9","10","11","12"][this.getMonth()]
}

// returns a nicely formatted date string
Date.prototype.getHumanDateString = function() {
return this.getMonthName() + " " + this.getDate() + ", " + this.getFullYear()
}

Date.prototype.getDateString = function() {
return this.getMonthNumber() + "/" + this.getDate() + "/" + this.getFullYear()
}

// returns a nicely formatted time string
Date.prototype.getHumanTimeString = function() {
	var h = this.getHours()
	var m = this.getMinutes()
	var t = h >= 12 ? "pm" : "am"

	if (h == 0) h = 24
	if (h > 12) h -= 12
	h = String(h)
	m = String(m)
	if (m.length == 1) m = "0" + m

	return h + ":"
}
// Time is a wrapper class for the Date object
// it accepts a wide variety of strings representing the time
// and returns a date object representing the current date with the
// specified time.
//
// var myTime = new Time('4p');
// myTime now contains a date object representing today at 4PM.
//
// accepted formats include 4p, 4:p, 4:1p, 4:10p, 4:10pm, 16:00, 
// and a bunch more...
/*
function Time(sTimeStr) {
	var a = sTimeStr.match(/(\d{1,2})\s*\x3A?\s*(\d{0,2})\s*(am|pm|a|p)?/i)
	if (a) {
		var d = new Date()
		var h = a[1]
		var m = a[2]
		var t = a[3]
		if (t && t.charAt(0).toLowerCase() == "p") h = h % 12 + 12
		d.setHours(h)
		d.setMinutes(m)
		return d
	}
	return null
}
*/
function Time(sTimeStr) {
	if (sTimeStr.trim() != "")
	{
		var a = sTimeStr.match(/\d{1,2}/g)
		var t = sTimeStr.match(/(am|pm|a|p)/ig)
		if (a) {
			var d = new Date()
			var h = a[0]
			var m = a[1] ? a[1] : 0;
			if (t) t = String(t[0]);
			if (t && t.charAt(0).toLowerCase() == "p") h = h % 12 + 12
			d.setHours(h)
			d.setMinutes(m)
			return d
		}
		return null
	}
}


/*************************************************************************/
/*  END OF DATE METHODS
/*************************************************************************/


/*************************************************************************/
/*  BEGIN OF REPLACEMENT OF THE ARRAY METHODS; PUSH, POP, SPLICE
/*************************************************************************/

/* 	
	since IE in all of its flavors does not fully support the JS array implementation
 	we are forced to expand the Array object by adding new methods.
*/

// here we add the PUSH method to the Array object
// first make sure any existing push methods are destroyed so we know
// we are always working with the same method regardless of browser
// viewing the page.
if(Array.prototype.push){
	Array.prototype.push = null;
}

if(!Array.prototype.push) {
	function ArrayPush(value){
		// simply add the element to the end of the array changing the arrays
		// length by +1
		this[this.length] = value;
	}
	// set the Arrays push method equal to our ArrayPush function
	Array.prototype.push = ArrayPush;
}	

// here we add the POP method to the Array object.


// first make sure any existing pop methods are destroyed so we know
// we are always working with the same method regardless of browser
// viewing the page.
if(Array.prototype.pop){
	Array.prototype.pop = null;
}

if(!Array.prototype.pop){
	// pop by default, without an index provided, removes the last element in the array
	// changing the arrays size by -1.  However, this verison of pop has been extended
	// so that an index can be provided and then the element at the given index will
	// be popped instead of the last element.  This alteration also alters the arrays
	// size by -1.
	function ArrayPop(index)	
		{
			// if the array is empty do nothing.
			if(this.length == 0) return;
			// no index is provided get the value of the last index
			// in the array.
			if(index == null) index = this.length - 1;
		
			//get the value of the element at the requested index.
			var elem = this[index];
		
			// loop over the array starting at the index point and going
			// till the last element in the array and change the value of
			// the current element to the value of the next element - thus
			// left shifting the array from the deletion point onward.
			for (var i = index; i < this.length - 1; i++) this[i] = this[i+1];
	 
	 		// set the final elements value = NULL thus destroying that element
			this[this.length - 1] = null;
			// change the length of the array to its old length - 1.
			this.length--;   
			// return the value that was removed from the array.
			return elem;
		}
	// set the arrays pop method equal to our defined ArrayPop function.
	Array.prototype.pop = ArrayPop;
}

// here we add the SPLICE method to the Array object.


// first make sure any existing splice methods are destroyed so we know
// we are always working with the same method regardless of browser
// viewing the page.
if(Array.prototype.splice)
    Array.prototype.splice = null;

if(!Array.prototype.splice) {

    function ArraySplice(index,count){

		// we use the slice method which is supported
		// across browsers to get the chunk of the array
		// we want to remove.
        removeArray = this.slice(index,index+count);
        endArray = this.slice(index+count);

		// we alter the length by setting it equal to the index
        this.length = index;

        for(var i=2;i<arguments.length;i++){
            this[this.length] = arguments[i];
        }

        for(var i=0;iendArray.length;i++){
            this[this.length] = endArray[i];
        }

        return removeArray;
    }

	// set the arrays slice method equal to our defined ArraySlice function.
    Array.prototype.splice = ArraySplice;

}

/*************************************************************************/
/*  END OF REPLACEMENT OF THE ARRAY METHODS; PUSH, POP, SPLICE
/*************************************************************************/




/*******************************************************************
	BEGIN GENERIC FORM VALIDATION FUNCTIONS
*******************************************************************/


// these arrays are used to build the formValidate function at the end of a document
// loading
var jsRequiredFields = new Array(0);
var jsRequiredTypes = new Array(0);
var jsRequiredDesc = new Array(0);

var errMsg = '';

function require(field,type,desc){
	/* field needs to be the ID of the object */
		// make sure the field being required isn't already required
		unrequire(field);
		// attempt to require the field
		jsRequiredFields.push(field);
		// attempt to add the fields type to the array
		jsRequiredTypes.push(type);
		// attempt to add the fields description to the array for display
		// to the user on fail of form validation
		jsRequiredDesc.push(desc);

		// make the field look required
			lookRequired(field);
}

function lookRequired(field){
	var vObj = getObjectRefByID(field);
	if(vObj && vObj.type != 'hidden'){
		var newSpan = document.createElement('SPAN');
		newSpan.className = 'required';
		newSpan.innerText = 'required';
		var tObj = vObj.nextSibling;
		if(vObj.readOnly){
			tObj = tObj.nextSibling;
		} else {
			vObj.style.background  = '#EEF';
		}
		tObj.parentNode.insertBefore(newSpan,tObj);
	}
}

function lookUnRequired(field){
	var vObj = getObjectRefByID(field);
	if(vObj){
			if(vObj.disabled)
				vObj.className = 'greyInput';
			else
				vObj.style.background  = '#FFF';
			vObj = vObj.nextSibling;
			if(vObj && vObj.className == 'required'){
				vObj.parentNode.removeChild(vObj);
			}

	}
}
function unrequire(field){
	// find the field and remove it from the array - then remove
	// the correlating type and discription.
	for (i=0; i < jsRequiredFields.length; i++){
		if (jsRequiredFields[i] == field) {
			jsRequiredFields.pop(i);
			jsRequiredTypes.pop(i);
			jsRequiredDesc.pop(i);
		}
	}

	// make the field look unrequired
		lookUnRequired(field);

}

function validateForm(){
	var Fields = jsRequiredFields;
	var Types = jsRequiredTypes;
	var Desc = jsRequiredDesc;

	var formgood = true;
	// make sure all of the required fields are supplied

	for (fieldcount=0; fieldcount < Fields.length; fieldcount++){
		if (Fields[fieldcount]) {
			var objField = getObjectRefByID(Fields[fieldcount]);
			if (!objField){
				BuildMsg('error occured when validating field ' + Fields[fieldcount]);
			}else {
				if(!hasValue(objField,Types[fieldcount])){
					BuildMsg(Desc[fieldcount]);
				}
			}
		}
	}


	// items havn't been supplied that are required
	if (errMsg.length) {
		dspMsg();
		formgood = false;
	}
	// all required items are available
	return formgood;
}

function BuildMsg(msg){
	errMsg = errMsg + msg + '\n';
}

function ClearMsg(){
	errMsg = '';
}

function dspMsg(){
		errMsg = 'This form requires the following:  \n \n' +
				 errMsg + '\n';
				 
		alert(errMsg);
		ClearMsg();
}


function isValidPhoneNumber(s) {
	return s.match(/^\(?\d{3}\)?\s|-\d{3}-\d{4}$/);
}

function isValidZipCode(s) {
	return s.match(/\d{5}(-\d{4})?/) != null;
}

function isValidSelectBox(o) {
	return (o.options[o.selectedIndex].value != "_none_" && 
			o.options[o.selectedIndex].value.trim() != "")
}

function isValidEmailAddress(s) {
	var temp = s.replace(/\s/g, "")
	return temp.match(/^.+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,3}|[0-9]{1,3})(\]?)$/);
}

function isValidDate(s){
	return s.match(/^\d{1,2}(\-|\/|\.)\d{1,2}\1\d{4}$/);
}

function isValidState(s,cc){
		// compare states
	if(cc == 'usa') {
		return s.match(/^(AK|AL|AR|AZ|CA|CO|CT|DC|DE|FL|GA|HI|IA|ID|IL|IN|KS|KY|LA|MA|MD|ME|MI|MN|MO|MS|MT|NB|NC|ND|NH|NJ|NM|NV|NY|OH|OK|OR|PA|RI|SC|SD|TN|TX|UT|VA|VT|WA|WI|WV|WY)$/i);
	}else if(cc == 'canada') {
		return s.match(/^(AB|BC|MB|NB|NL|NT|NS|NU|ON|PE|QC|SK|YT)$/i);	
	}
}

function isValidSSN(s){
	return s.match(/^\d{3}\-\d{2}\-\d{4}$/);
}

function isValidTime(s){
	return s.match(/^([1-9]|1[0-2]):[0-5]\d$/);
}
function isValidIPAddress(s){
	return s.match(/^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/);
}
function isValidCurrency(s){
	return s.match(/\$\d{1,3}(,\d{3})*\.\d{2}/);
}


function fixFloat(val,dec,sep)
{ // fixed decimal fields 
  var sign= ( val < 0 ? '-': '' );
  val= Number(Math.round(Math.abs(val)*Math.pow(10,dec))).toString();
  while(val.length < dec) val= '0'+val;
  var len= val.length;
  val= sign + ( len == dec ? '0' : val.substring(0,len-dec) ) + '.' + val.substring(len-dec,len+1);

  return val;
}

function hasValue(obj,obj_type){
	var goodValue;
		switch (obj_type.toUpperCase())
		{
		case 'TEXT':
			if (obj.value.trim().length == 0) 
				goodValue = false;
			else
				goodValue = true;
			break;
		case 'PASSWORD':
			if (obj.value.trim().length == 0) 
				goodValue = false;
			else
				goodValue = true;
			break;

		case 'DATE':
			goodValue = isValidDate(obj.value);
			break;

		case 'EMAIL':
			goodValue = isValidEmail(obj.value);
			break

		case 'SSN':
			goodValue = isValidSSN(obj.value);
			break
			
		case 'ZIPCODE':
			goodValue = isValidZipCode(obj.value);
			break;

		case 'SELECT':
			goodValue = false;
			for (i=0; i < obj.length; i++) {
				if (obj.options[i].selected && (obj.options[i].value != '' && obj.options[i].value != 0)) 
					goodValue = true;
			}
			break;

		case 'RADIO':
			goodValue = false;

			if (obj.length) {
				for (i=0; i < obj.length; i++) {
					if (obj[i].checked)
						goodValue = true;
				}
			}
			else {
				goodValue = obj.checked;
			}
			break;
		case 'CHECKBOX':
			goodValue = false;

			if (obj.length) {
				for (i=0; i < obj.length; i++) {
					if (obj[i].checked)
						goodValue = true;
				}
			}
			else {
				goodValue = obj.checked;
			}
			break;
			

		default:
			goodValue = false;
			break;
		
		}
		return goodValue
}
/*******************************************************************
	END GENERIC FORM VALIDATION FUNCTIONS
*******************************************************************/

/*******************************************************************
	BEGIN UTILITY FUNCTIONS
*******************************************************************/
function setFocus(){
	/* called with body.onload and sets the form focus to the first form field that can be found
	on the page, that isn't hidden or disabled.  If no form field can be found that matches this
	criteria then nothing happens.
	*/
	var aryElements;
	var elementIndex =0;
	var thisCtrl;

	if(document.forms[0]){
		aryElements = document.forms[0].elements;
		for(elementIndex=0; elementIndex<aryElements.length; elementIndex++){
			thisCtrl=aryElements[elementIndex];
			if(thisCtrl.type && thisCtrl.type != 'hidden' && thisCtrl.disabled != true){
				thisCtrl.focus();
				break;
			}
		}	
	}
}

function addEvent(elm, evType, fn, useCapture)
// addEvent and removeEvent
// cross-browser event handling for IE5+,  NS6 and Mozilla
// By Scott Andrew
{
  if (elm.addEventListener){
    elm.addEventListener(evType, fn, useCapture);
    return true;
  } else if (elm.attachEvent){
    var r = elm.attachEvent("on"+evType, fn);
    return r;
  } else {
    alert("Handler could not be removed");
  }
} 

function getObjectRefByID(objectId) {
    // cross-browser function to get an object given its id
    if(this.document.getElementById && this.document.getElementById(objectId)) {
		// W3C DOM
		return this.document.getElementById(objectId);
    } 
	else if (this.document.all && this.document.all(objectId)) {
		// MSIE 4 DOM
		return this.document.all(objectId);
    } 
	else if (this.document.layers && this.document.layers[objectId]) {
		// NN 4 DOM.. note: this won't find nested layers
		return this.document.layers[objectId];
    } 
	else {
		return false;
    }
} 


/*******************************************************************
	END UTILITY FUNCTIONS
*******************************************************************/