document.write('<SCRIPT SRC="/_javascript/forms/index.js"></SCRIPT>')
if(!window.selectAllMenus)
	document.write('<SCRIPT SRC="/_javascript/forms/selectAllOptions.js"></SCRIPT>')

if(!window.formatCurrency)
	document.write('<SCRIPT SRC="/_javascript/format/formatCurrency.js"></SCRIPT>')

var noTrim = window.noTrim || false;
var noReplaceSpecialCharacters = window.noReplaceSpecialCharacters || false;
var maxErrorMsgs = window.maxErrorMsgs || 25;
var maxWordBuffer = window.maxWordBuffer || 100;

var dateMinYear=1900;
var dateMaxYear=2100;

/*************** ADDITIONAL ON SUBMIT ACTION ***************/
function _additionalOnSubmitAction(form){return true;}
if(!window.additionalOnSubmitAction)
	window.additionalOnSubmitAction = _additionalOnSubmitAction

/*************** VALIDATE AND SUBMIT FORM ***************/
function validateAndSubmitForm(form, submitOnce, visible){
	if( validate(form, submitOnce, visible) )
		form.submit()
}

/*************** VALIDATE FORM ***************/
function validate(form, submitOnce, visible){
	if(submitOnce && window._submittted){
		alert("Please wait...")
		return false
	}
			
	selectAll()

	// set look to see if element is visible (NOTE: this slows things)
	if(typeof visible == "undefined")
		visible = true;

	errorMSG = new Array();
	if(form.REQUIRED){
		var required_elements = form.REQUIRED.value.split(/\s*,\s*/)
		for(var i=0;i<required_elements.length;i++){
			if(!getValue(form, required_elements[i])){
				errorMSG[errorMSG.length] =  getValidationMessage(null, "required", required_elements[i]);
				setRequiredElement(form.elements[required_elements[i]])	
			}
		}
	}

	for(var i=0;i<form.length;i++){
		// trim element value
		trimElementValue(form.elements[i])
		replaceSpecialCharactersInElementValue(form.elements[i])

		// if not validation rules
		if(!form.elements[i].name) continue
		if(form.elements[i].type != "hidden" && form.elements[i].name.indexOf("_confirm") == -1 && form.elements[i].name.indexOf("_regexp") == -1 && form.elements[i].name.indexOf("_javascript") == -1)continue
		if(form.elements[i].name.indexOf("_") == -1) continue;

		// get validation rule, element name, message
		var rule = form.elements[i].name 
		if(rule.lastIndexOf("_") == rule.length-1) // remove extra underscore to bypass CF server-side validation
			rule = rule.substring(0, rule.lastIndexOf("_"))

		var name = rule.substring(0,rule.lastIndexOf("_"))
		var datatype = rule.substring(rule.lastIndexOf("_")+1,rule.length)

		var expr = trim(form.elements[i].value)
		var msg = form.elements[i].getAttribute("message") || expr
		var label = formatFormElementLabel(name)
		var inputType = (form.elements[name])?form.elements[name].type + '':''

		var isNext = (name == "_next")

		// no name
		if(name == "") continue

		// if not next element - check if element is visabled, disabled, or exists
		if(!isNext){
			// is element visible
			if(visible) if(!isFormElementVisible(form, name)) continue;
			// is element disabled
			if(isFormElementDisabled(form, name)) continue;
			// does element exist in form
			if(!form.elements[name]){
				if(datatype == "required")
					errorMSG[errorMSG.length] =  getValidationMessage(null, datatype, label);
				continue;
			}
		}

		// get element and value
		var element,value; 
		if(isNext){
			for(var j=i;j<form.length;j++){
				if(form.elements[j].type != "hidden"){
					element = form.elements[j];	break;
				}
			}
			if(!element) continue
			// is next element visible
			if(visible) if(!isFormElementVisible(element)) continue;
			// is next element disabled
			if(isFormElementDisabled(element)) continue;

			value = getValue(element)
		} else {
			element = form.elements[name]		
			value = getValue(form, name)
		}

		// format element value
		value = formatElementDateTypeValue(element, datatype, value)

		// standard validation - check for validate data
		if(checkDataType(datatype, value, expr)) {
			continue;
		}

		errorMSG[errorMSG.length] =  getValidationMessage(inputType, datatype, label, value, msg, expr);

		setRequiredElement(element, name)	
	}

	if(errorMSG.length != 0){
		var alertMSG = "";
		for(var i=0;i<errorMSG.length;i++) {
			alertMSG += errorMSG[i] + "\n";
			if(i > maxErrorMsgs) {
				alertMSG += "...\n";
				break;
			}
		}
		alert(alertMSG);
		return false;
	}
	else{

		if(!additionalOnSubmitAction(form)){
			return false
		} else {
			if(submitOnce)
				window._submittted = true

			return true
		}
	}
}

/*************** SET ELEMENT REQUIRED ***************/
function setRequiredElement(element, name){
	// change element bgColor 

	// if input group
	if(document.getElementById && document.getElementById(name + 'InputGroup')){
		var inputGroup = document.getElementById(name + 'InputGroup')
		inputGroup.style.backgroundColor = "#FFCCCC";
		inputGroup.onclick = new Function("this.style.backgroundColor = '';this.onfocus=''")
	}

	// change element bgColor 
	if(!element.style || element.type == "radio" || element.type == "checkboxes")return ;
	if(element.type == "hidden"){
		// height & date input
		var jsElements = ["feet", "inches", "day", "date", "month", "year", "hour", "minute", "am_pm"]
		var form = element.form;
		for(var i=0;i<jsElements.length;i++){
			var jsElement = form.elements['_' + element.name + '_' + jsElements[i] + '_'];
			if(jsElement && (jsElement.selectedIndex == -1 || getValue(jsElement) === '')){
				 setRequiredElement(jsElement);
			}
		}
	} else {
		if(!element.onfocus){
			element.style.backgroundColor = "#FFCCCC";
			element.onfocus = new Function("this.style.backgroundColor = '';this.onfocus=''")
		}
	}
}

/*************** FORMAT DATATYPE VALUE ***************/
function formatElementDateTypeValue(element, type, value){
	if(element.type != "text") 
		return value

	switch(type){
		case "currency" :
			element.value = value = formatCurrency(value);
			return value;
		default :
			return value;
	}
}

/*************** CHECK DATATYPE  ***************/
function checkDataType(type, value, expr){
	if(type == "required" && value == "")
		return false;
	if(value == "")
		return true;
	if(/maxcharacters([0-9]*)/i.exec(type))
		return value.length < parseInt(RegExp.$1)
	if(value == "null")
		return true

	switch(type){
		case "alphanumeric" :
			return /^\w+$/.test(value)
		case "phone" : 
			return /^\d\d\d(-| |\.)?\d\d\d(-| |\.)?\d\d\d\d$/.test(value)
		case "zip" : 
		case "zipcode" : 
			if(/^\D{1}\d{1}\D{1}\-?\d{1}\D{1}\d{1}$/.test(value)) // canadian
				return true
			else if(/^\d\d\d\d\d(-| |)?(\d\d\d\d)?$/.test(value)) // us
				return true
			else
				return false
		case "ssn" : 
			return /^\d\d\d(-| |)?\d\d(-| |)?\d\d\d\d$/.test(value)
		case "email" : 
			return /^(\w|\.|\-)+@(\w|\.|\-)+\.\w{2,4}$/.test(value)
		case "emails" : 
			value += '';
			var reEmailDelimiter = (value.indexOf(',') != -1)? /\s*,\s*/ : /\s*(\r|\n)\s*/ ;
			var emails = value.split(reEmailDelimiter);

			var invalidEmails = []
			for(var i=0;i<emails.length;i++){
				if(!checkDataType("email", emails[i]))
					invalidEmails[invalidEmails.length] = emails[i]
			}
			if(invalidEmails.length){
				alert(invalidEmails + " are not a valid email address.")
				return false
			} else {
				return true;
			}
		case "url" : // protocol/domain:port/ 
			return /^(http|https|ftp):\/\/[-\w\.]+(:\d+)?.*$/i.test(value)
		case "domain" : 
			return /^(www\.)?[a-z_-]+\.(com|net|org|info)$/i.test(value)
		case "integer" : 
		case "number" : 
			return /^\d+$/.test(value)
		case "float" : 
			return /^\d*\.?\d*$/.test(value)
		case "bit" : 
			return /^[01]$/.test(value)
		case "length" : 
			return /^\d+(px|em|%|pt)?$/.test(value)
		case "currency" : 
	     	return /[+-]?\$?\d{1,3}(,\d{3})*\.\d{2}/.test(value)
		case "hexcolor" : 
	     	return /#\w{3,6}/i.test(value)
		case "anydate":
			// MM/DD/YYYY
			var date = /^(\d{1,2})\/(\d{1,2})\/(\d{2,4})$/i.exec(value)
			if( date ){
				var month = parseInt(date[1], 10);
				var day = parseInt(date[2], 10);
				var year = parseInt(date[3], 10);

				if( !isValidYear(year) ) return false
				if( !isValidMonth(month) ) return false
				if( !isValidDay(month, day, year) ) return false;
				return true
			} 

			// MM/YYYY
			var date = /^(\d{1,2})\/(\d{2,4})$/i.exec(value)
			if( date ){
				var month = parseInt(date[1], 10);
				var year = parseInt(date[2], 10);
				if( !isValidMonth(month) ) return false
				if( !isValidYear(year) ) return false
				return true;
			}			

			// YYYY
			var date = /^(\d{2,4})$/i.exec(value)
			if(date){
				var year = parseInt(date[1], 10);
				if( !isValidYear(year) ) return false
				return true;
			}
			
			return false;
		case "datetime":
			var datetime = /^(\d{1,2})\/(\d{1,2})\/(\d{2,4}) (\d{1,2}):(\d{1,2}):(\d{1,2})\s?(AM|PM)?$/i.exec(value)
			if(datetime == null) return false;

			var month = parseInt(datetime[1], 10);
			var day = parseInt(datetime[2], 10);
			var year = parseInt(datetime[3], 10);

			if( !isValidYear(year) ) return false
			if( !isValidMonth(month) ) return false
			if( !isValidDay(month, day, year) ) return false;

			var hour = parseInt(datetime[4], 10);
			var minute = parseInt(datetime[5], 10);
			var second = parseInt(datetime[6], 10);
			if(hour > 25 || minute > 59 || second > 59 ) return false;

			return true;
		case "date":
			var date = /^(\d{1,2})\/(\d{1,2})\/(\d{4})*$/.exec(value)
			if(date == null) return false;

			var month = parseInt(date[1], 10);
			var day = parseInt(date[2], 10);
			var year = parseInt(date[3], 10);

			if( !isValidYear(year) ) return false;
			if( !isValidMonth(month) ) return false;
			if( !isValidDay(month, day, year) ) return false;

			return true;
		case "time" :
			var time = /^(\d{1,2}):(\d{1,2}):(\d{1,2})*$/.exec(value)
			if(time == null) return false
			var hour = parseInt(time[1], 10);
			var minute = parseInt(time[2], 10);
			var second = parseInt(time[3], 10);
			if(hour > 25 || minute > 59 || second > 59 )return false
			return true
		case "extension" : 
			if(!window.validExtensions) return true
			if(!validExtensions.length) return true
			return (new RegExp("\.(" + validExtensions.join("|") + ")$")).test(value)
		case "filename":
			return /[a-z0-9_-]+\.[a-z0-9]{1,4}$/i.test(value)
		case "creditcard":
			return validateCreditCardNumber(value)
		/* below datatype use expr */
		case "filetypes":
			var types = expr.split(/\s*,\s*/)
			for(var i=0;i<types.length;i++){
				if( value.toLowerCase().lastIndexOf(types[i]) == (value.length-types[i].length)) return true
			}
			return false
		case "not": 
			return (value != expr)
		case "confirm":
			return (value == expr)
		case "words":
			if(!expr) return true
			var numberOfWords = value.split(/\s+/).length
			return (numberOfWords <= (parseInt(expr) + maxWordBuffer) )
		case "max":
			return (value <= parseInt(expr))
		case "min":
			return (value >= parseInt(expr))
		case "maxlength":
			return (value.length <= parseInt(expr))
		case "minlength":
			return (value.length >= parseInt(expr))
		case "regexp":
			try{ return eval(expr).test(value) } 
			catch(e){ alert(expr + " is not a valid regular expression") }
		case "javascript":
			try{ return eval(expr) } 
			catch(e){ alert(expr + " is not a valid javascript expression") }
		default :
			return true;
	}

	// is valid day
	function isValidDay(month, day, year){
		var daysInMonth = new Array(31,(year%4 == 0)?29:28,31,30,31,30,31,31,30,31,30,31);			if(month > 13)return false;
		return (day >= 1 && day <= daysInMonth[month-1]);
	}

	// is valid year
	function isValidYear(year){
		return ((year >= dateMinYear && year <= dateMaxYear) || (year >= 0 && year <= 99));
	}
	
	// is validMonth
	function isValidMonth(month){
		return (month >= 1 && month <= 12);
	}

	// validate card number (from: http://www.tinycode.com/cc.c without permission)
	function validateCreditCardNumber(strNum){
		var nCheck = 0;
		var nDigit = 0;
		var bEven  = false;
		
		for (n = strNum.length - 1; n >= 0; n--){
			var cDigit = strNum.charAt (n);
			if (isDigit (cDigit)){
				var nDigit = parseInt(cDigit, 10);
				if (bEven) {
					if ((nDigit *= 2) > 9)
						nDigit -= 9;
				}
				nCheck += nDigit;
				bEven = ! bEven;
			} else if (cDigit != ' ' && cDigit != '.' && cDigit != '-'){
				return false;
			}
		}
		return (nCheck % 10) == 0;
	
		function isDigit (c){
			var strAllowed = "1234567890";
			return (strAllowed.indexOf(c) != -1);
		}
	}
}

/*************** GET VALIDATION MESSAGE  ***************/
function getValidationMessage(inputType, datatype, label, value, msg, expr){
	var dataTypeRequiresExpr = (
		datatype == "not" || datatype == "confirm" || datatype == "words" || 
		datatype == "min" || datatype == "minlength" || 
		datatype == "max" || datatype == "maxlength" || 
		datatype == "regexp" || datatype == "javascript" || 
		datatype == "filetypes"
	)

	if(msg != "" && !dataTypeRequiresExpr){ return msg }
	if(dataTypeRequiresExpr && msg != expr){ return msg }

	switch(datatype){
		case "required" : return (inputType.indexOf("select") == 0)?"Select an entry for " + label + ".":"An entry for " + label + " is required.";
		case "filename" : return "The selected file (" + value.substring(value.lastIndexOf("\\")+1 ) + ") for " + label + " can not contain spaces or special characters (use '_' or '-' instead of spaces).\n   Click 'Browse' and edit the file\'s name.";
		case "alphanumeric" : return getMsg(label, "letter_number_underscore");
		case "phone" : return getMsg(label, "XXX-XXX-XXXX");
		case "zip" : 
		case "zipcode" : return getMsg(label, "12345[-6789] US or Z5Z-5Z5 CANADIAN");
		case "ssn" : return getMsg(label, "XXX-XX-XXXX");
		case "email" : return getMsg(label, "someone@somewhere.com");
		case "emails" : return getMsg(label, "one@where.com,two@where.com");
		case "url" : return getMsg(label, "http://somewhere.com/about/");
		case "domain" : return getMsg(label, "somewhere.com or www.somewhere.com");
		case "integer" :
		case "number" : return getMsg(label, "123");
		case "float" : return getMsg(label, "123.45");
		case "bit" : return getMsg(label, "0 or 1");
		case "length" : return getMsg(label, "10pt, 10px, 1em, 100%, or 10");
		case "currency" : return getMsg(label, "$123.45 or 123.45");
		case "hexcolor" : return getMsg(label, "#FFFFFF");
		case "anydate" : return getMsg(label, "YYYY, MM/YYYY, or MM/DD/YYYY");
		case "datetime" : return getMsg(label, "MM/DD/YYYY HH:MM:SS");
		case "date" : return getMsg(label, "MM/DD/YYYY");
		case "time" : return getMsg(label, "HH:MM:SS");
		case "creditcard" : return getMsg(label, "49927398716");
		case "extension": return "A valid file extension for " + label + " is required. (*." + validExtensions.join(", *.") + ")";

		case "not" : return getMsg(label, value + " is not a valid");
		case "confirm" : return "The entry for " + label + " and confirmation do not match.\n   Please re-enter both fields";
		case "filetypes": return "A valid file extension (" + msg + ") for " + label + " is required.";
		case "words" : return "Please enter less than " + msg + " words for " + label + ". (You entered " + (value.split(/\s+/).length) + " words.)";
		case "maxlength" : return "Please enter less than " + msg + " characters for " + label + ". (You entered " + (value.length) + " characters.)";
		case "minlength" : return "Please enter more than " + msg + " characters for " + label + ". (You entered " + (value.length) + " characters.)";

		case "min" : return "Please enter a number greater than " + msg + " for " + label + ".";
		case "max" : return "Please enter a number less than " + msg + " for " + label + ".";

		default : return "A valid entry for " + label + " is required.";
	}
	
	// format message
	function getMsg(label, ex){
		return "A valid entry for " + label + " is required." + ((ex)?" (" + ex + ")":"")
	}
}

/*************** TRIM ELEMENT VALUE ***************/
function trimElementValue(element){
	if(noTrim) return false
	// trim value
	if(element.type == "password" || element.type == "text" || element.type == "textarea")
		element.value = trim(element.value)
}

/*************** REPLACE SPECIAL CHARACTERS ***************/
function replaceSpecialCharactersInElementValue(element){
	if(noReplaceSpecialCharacters) return false

	if(element.type == "password" || element.type == "text" || element.type == "textarea")
		element.value = replaceSpecialCharacters(element.value)

	// replace special characters
	function replaceSpecialCharacters(text){
		// “ ” ‘ ’ –  · 
		var msChar =  [
			{value:unescape('%u201C'), replace:'"'}, // “ 
			{value:unescape('%u201D'), replace:'"'}, // ” 
			{value:unescape('%u2018'), replace:"'"}, // ' 
			{value:unescape('%u2019'), replace:"'"}, // ' 
			{value:unescape('%u2012'), replace:"-"}, // – 
			{value:unescape('%u2013'), replace:"-"}, // – 
			{value:unescape('%u2014'), replace:"-"}, // – 
			{value:unescape('%u2015'), replace:"-"}, // – 
			{value:unescape('—'), replace:"-"}, // – 
			{value:unescape('%u2022'), replace:"*"} // ·
		]

		for(var i=0;i<msChar.length;i++){
			if(text.indexOf(msChar[i].value) == -1) continue
			text = text.replace( new RegExp(msChar[i].value, "g"), msChar[i].replace)
		}

		// fix bullets
		text = text.replace( /\*\s+/ig, "* ")
		return text
	}
}

/*************** TRIM ***************/
function trim(text){
	text = text.replace(/^(\s|\r|\n|\t|\f)+/,"")
	text = text.replace(/(\s|\r|\n|\t|\f)+$/,"")
	return text;
}

/*************** FORMAT FORM ELEMENT LABEL ***************/
function formatFormElementLabel(text){
	text = text.replace(/([a-z])([A-Z])/g, '$1 $2')
	if(text.indexOf("_") != -1)
		text = text.replace(/_/g, ' ')

	text = text.replace(/ And /g, ' and ')

	return "'" + text.charAt(0).toUpperCase() + text.substring(1) + "'"
}

/*************** IS FORM ELEMENT VISIBLE ***************/
function isFormElementVisible(arg1, arg2){
	if(arg1 && !arg2){
		var element = arg1;
		var form = element.form
		var elementName = element.name
	} else {
		var form = arg1
		var elementName = arg2
		var element = form.elements[elementName];
	}
	if(!element) return false;
	if(!form) return false;

	if(form.elements[elementName].length)
		var element = form.elements[elementName][0].parentNode
	else
		var element = form.elements[elementName]

	while(element){
		if(element.tagName == "FORM"){return true;}
		if(element.style){ 
			if(element.style.display == "none"){return false;} 
		}
		element = element.parentNode
	}
	return true
}

/*************** CHECK VALUE MAXLENGTH ***************/
function checkValueMaxLength(value, maxlength){
	if(!maxlength) maxlength = 255
	if(!value) 
		return true

	if(value.length <= maxlength)
		return true
	
	alert("Please enter less than " + maxlength + " characters. (You entered " + value.length + " characters.)")
	return false;
}
