// formValidation_v0.5.0.js

// Form Validation
var val_errors = '';

// Some constants
var valEmailRule = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;
var valURLRule = /^(http|https)\:\/\/([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})([A-Za-z0-9\%\.\#\/\~\&\?\=\+\-\_\(\)\!\,\;\:]*)$/;
var thirtyDays = Array(1, 3, 5, 7, 8, 10, 12);


/********************************************************************************
 * function validateForm
 ********************************************************************************
 *
 * Description
 * ---------------
 * Performs error checking on the form and
 *
 * @param form: 	Form to check for errors
 *
 * @return bool:	Whether or not the form is error free
 *
 ********************************************************************************/

function validateForm(form) {
	val_errors = '';
	inputs = form.getElementsByTagName('input');
	selects = form.getElementsByTagName('select');
	textareas = form.getElementsByTagName('textarea');
	
	for ( var x = 0; x < inputs.length; x++ ) {
		if ( inputs[x].getAttribute('rel') ) {
			if ( inputs[x].tagName == 'INPUT' ) {
				if ( inputs[x].type == 'radio' ) {
					val_errors += validateRadio(form, inputs[x], inputs[x].getAttribute('rel'), inputs[x].getAttribute('valmsg'));
				} else if ( inputs[x].type == 'checkbox' ) {
					val_errors += validateCheckbox(form, inputs[x], inputs[x].getAttribute('rel'), inputs[x].getAttribute('valmsg'));
				} else {
					val_errors += validateInput(inputs[x], inputs[x].getAttribute('rel'), inputs[x].getAttribute('valmsg'));
				}
			}
		}
	}
	
	for ( var x = 0; x < selects.length; x++ ) {
		if ( selects[x].getAttribute('rel') ) {
			if ( selects[x].getAttribute('rel').indexOf('date') != -1 ) {
				var elem_names = selects[x].name.substr(0, selects[x].name.indexOf('['));
				val_errors += validateDate(selects[x], form[elem_names+'[d]'], form[elem_names+'[m]'], form[elem_names+'[y]'], selects[x].getAttribute('rel'), selects[x].getAttribute('valmsg'));
			} else {
				val_errors += validateSelect(selects[x], selects[x].getAttribute('rel'), selects[x].getAttribute('valmsg'));
			}
		}
	}
	
	for ( var x = 0; x < textareas.length; x++ ) {
		if ( textareas[x].getAttribute('rel') ) {
			val_errors += validateTextarea(textareas[x], textareas[x].getAttribute('rel'), textareas[x].getAttribute('valmsg'));
		}
	}
	
	if ( val_errors ) {
		if ( document.getElementById('msgMask') ) {
			throwMessage('Form Submission Error', val_errors.replace(/\n/g, "<br/>"),  true);
		} else {
			alert(val_errors);
		}
		return false;
	} else {
		return true;
	}
}



/********************************************************************************
 * function validateInput
 ********************************************************************************
 *
 * Description
 * ---------------
 * Helper function for attaching events to elements, removing the need to do 
 * browser-related checks everywhere.
 *
 * @param elem: 	Element being checked
 * @param rules: 	Validation rules to apply
 * @param valmsg: 	Message to show if validation fails
 *
 * @return string:	Any error message for this element
 *
 ********************************************************************************/

function validateInput(elem, rules, valmsg) {
	if ( elem.getAttribute('fieldname') ) {
		var fName = elem.getAttribute('fieldname');
	} else {
		var fName = elem.name;
	}
	
	// Do required field checking
	if ( rules.indexOf('required') != -1 ) {
		if ( elem.type == 'checkbox' ) {
			if ( !elem.checked ) {
				elem.className += ' formError';
				if ( valmsg ) {
					return valmsg + "\n";
				} else {
					return fName + " must be checked.\n";
				}
			}
		} else if ( elem.type == 'radio' ) {
			// Handled elsewhere
		} else if ( elem.type == 'submit' ) {
			// No checking!
		} else if ( elem.type == 'button' ) {
			// No checking!
		} else if ( elem.type == 'image' ) {
			// No checking!
		} else {
			if ( elem.value.replace(/^\s+|\s+$/g, '').length < 1 ) {
				elem.className += ' formError';
				
				if ( valmsg ) {
					return valmsg + "\n";
				} else {
					return fName + " is a required field.\n";
				}
			}
		}
	}
	
	
	
	// Do int checking
	if ( rules.indexOf('int') != -1 && elem.value ) {
		if ( elem.type == 'text' ) {
			for ( var x = 0; x < elem.value.length; x++ ) {
				if ( parseInt(elem.value.charAt(x)) != elem.value.charAt(x) ) {
					elem.className += ' formError';
					return fName + " must be a number.\n";
					break;
				}
			}
		}
	}
	
	// Do float checking
	if ( rules.indexOf('float') != -1 && elem.value ) {
		if ( elem.type == 'text' ) {
			var has_decimal = false;
			
			for ( var x = 0; x < elem.value.length; x++ ) {
				if ( !(parseInt(elem.value.charAt(x)) == elem.value.charAt(x) || (elem.value.charAt(x) == '.' && !has_decimal)) ) {
					elem.className += ' formError';
					return fName + " must be a number.\n";
					break;
				}
				
				if ( elem.value.charAt(x) == '.' ) {
					has_decimal = true;
				}
			}
		}
	}
	
	// Do email checking
	if ( rules.indexOf('email') != -1 && elem.value ) {
		if ( elem.type == 'text' ) {
			if ( !valEmailRule.test(elem.value) ) {
				elem.className += ' formError';
				return fName + " must be a valid email address.\n";
			}
		}
	}
	
	// Do url checking
	if ( rules.indexOf('url') != -1 && elem.value ) {
		if ( elem.type == 'text' ) {
			if ( !valURLRule.test(elem.value) ) {
				elem.className += ' formError';
				return fName + " must be a valid URL.\n";
			}
		}
	}
	
	// Do length checks
	if ( rules.indexOf('minlen') != -1 && elem.value ) {
		var minlen = parseInt(rules.match(/minlen=([0-9]*)+/)[1]);
		
		if ( elem.value.length < minlen ) {
			elem.className += ' formError';
			return fName + " must be longer than " + (minlen - 1) + " characters.\n";
		}
	}
	if ( rules.indexOf('maxlen') != -1 && elem.value ) {
		var maxlen = parseInt(rules.match(/maxlen=([0-9]*)+/)[1]);
		
		if ( elem.value.length > maxlen ) {
			elem.className += ' formError';
			return fName + " must be shorter than " + (maxlen + 1) + " characters.\n";
		}
	}
	
	// Remove error class on element since there were no errors
	elem.className = elem.className.replace(/formError/g, '');
	
	return '';
}




/********************************************************************************
 * function validateRadio
 ********************************************************************************
 *
 * Description
 * ---------------
 * Does some special checking to see if a radio button is selected from a group
 * of options
 *
 * @param form: 	Form that is being checked for errors
 * @param elem: 	Element being checked
 * @param rules: 	Validation rules to apply
 * @param valmsg: 	Message to show if validation fails
 *
 * @return string:	Any error message for this element
 *
 ********************************************************************************/

function validateRadio(form, elem, rules, valmsg) {
	if ( elem.getAttribute('fieldname') ) {
		var fName = elem.getAttribute('fieldname');
	} else {
		var fName = elem.name;
	}
	
	// Do required field checking
	if ( rules.indexOf('required') != -1 ) {
		var radios = form[elem.name].length;
		var checked = false;
		
		for ( idx = 0; idx < radios; idx++ ) {
			if ( form[elem.name][idx].checked ) {
				checked = true;
			}
		}
		
		if ( !checked ) {
			if ( valmsg ) {
				return valmsg + "\n";
			} else {
				return fName + " is a required field.\n";
			}
		}
	}
	
	return '';
}



/********************************************************************************
 * function validateCheckbox
 ********************************************************************************
 *
 * Description
 * ---------------
 * Does some special checking to see if a radio button is selected from a group
 * of options
 *
 * @param form: 	Form that is being checked for errors
 * @param elem: 	Element being checked
 * @param rules: 	Validation rules to apply
 * @param valmsg: 	Message to show if validation fails
 *
 * @return string:	Any error message for this element
 *
 ********************************************************************************/

function validateCheckbox(form, elem, rules, valmsg) {
	if ( elem.getAttribute('fieldname') ) {
		var fName = elem.getAttribute('fieldname');
	} else {
		var fName = elem.name;
	}
	
	// Do required field checking
	if ( rules.indexOf('required') != -1 ) {
		// See if this is a collection of input boxes or just a single
		if ( form[elem.name].length ) {
			var radios = form[elem.name].length;
			var checked = false;
			
			for ( idx = 0; idx < radios; idx++ ) {
				if ( form[elem.name][idx].checked ) {
					checked = true;
				}
			}
			
			if ( !checked ) {
				if ( valmsg ) {
					return valmsg + "\n";
				} else {
					return fName + " is a required field.\n";
				}
			}
		} else {
			if ( !elem.checked ) {
				elem.className += ' formError';
				if ( valmsg ) {
					return valmsg + "\n";
				} else {
					return fName + " must be checked.\n";
				}
			}
		}
	}
	
	return '';
}



/********************************************************************************
 * function validateSelect
 ********************************************************************************
 *
 * Description
 * ---------------
 * Does some special checking to see if a select box has been appropriately 
 * changed
 *
 * @param elem: 	Element being checked
 * @param rules: 	Validation rules to apply
 * @param valmsg: 	Message to show if validation fails
 *
 * @return string:	Any error message for this element
 *
 ********************************************************************************/

function validateSelect(elem, rules, valmsg) {
	if ( elem.getAttribute('fieldname') ) {
		var fName = elem.getAttribute('fieldname');
	} else {
		var fName = elem.name;
	}
	
	// Do required field checking
	if ( rules.indexOf('required') != -1 ) {
		
		if ( !elem.options[elem.selectedIndex].value ) {
			elem.className += ' formError';
				
			if ( valmsg ) {
				return valmsg + "\n";
			} else {
				return fName + " is a required field.\n";
			}
		}
	}
	
	if ( rules.indexOf('dontselect') != -1 ) {
		var dontselects = rules.match(/dontselect=([0-9\,]*)+/)[1].split(/[\,]/);
		for ( x in dontselects ) {
			if ( elem.selectedIndex == dontselects[x] ) {
				if ( valmsg ) {
					return valmsg + "\n";
				} else {
					return fName + " is a required field.\n";
				}
			}
		}
	}
	
	// Remove error class on element since there were no errors
	elem.className = elem.className.replace(/formError/g, '');
	
	return '';
}



/********************************************************************************
 * function validateTextarea
 ********************************************************************************
 *
 * Description
 * ---------------
 * Does some special checking to see if a textarea box has been appropriately 
 * filled out
 *
 * @param elem: 	Element being checked
 * @param rules: 	Validation rules to apply
 * @param valmsg: 	Message to show if validation fails
 *
 * @return string:	Any error message for this element
 *
 ********************************************************************************/

function validateTextarea(elem, rules, valmsg) {
	if ( elem.getAttribute('fieldname') ) {
		var fName = elem.getAttribute('fieldname');
	} else {
		var fName = elem.name;
	}
	
	// Do required field checking
	if ( rules.indexOf('required') != -1 ) {
		
		if ( !elem.value ) {
			elem.className += ' formError';
				
			if ( valmsg ) {
				return valmsg + "\n";
			} else {
				return fName + " is a required field.\n";
			}
		}
	}
	
	// Do length checks
	if ( rules.indexOf('minlen') != -1 && elem.value ) {
		var minlen = parseInt(rules.match(/minlen=([0-9]*)+/)[1]);
		
		if ( elem.value.length < minlen ) {
			elem.className += ' formError';
			return fName + " must be longer than " + (minlen - 1) + " characters.\n";
		}
	}
	if ( rules.indexOf('maxlen') != -1 && elem.value ) {
		var maxlen = parseInt(rules.match(/maxlen=([0-9]*)+/)[1]);
		
		if ( elem.value.length > maxlen ) {
			elem.className += ' formError';
			return fName + " must be shorter than " + (maxlen + 1) + " characters.\n";
		}
	}
	
	// Remove error class on element since there were no errors
	elem.className = elem.className.replace(/formError/g, '');
	
	return '';
}



/********************************************************************************
 * function validateDate
 ********************************************************************************
 *
 * Description
 * ---------------
 *
 * @param elem: 	Element being checked
 * @param rules: 	Validation rules to apply
 * @param valmsg: 	Message to show if validation fails
 *
 * @return string:	Any error message for this element
 *
 ********************************************************************************/

function validateDate(elem, elemD, elemM, elemY, rules, valmsg) {
	var tmpDate = new Date();
	var cur_date = tmpDate.getFullYear().toString() + ((tmpDate.getMonth() < 10) ? '0' : '' ) + tmpDate.getMonth().toString() + ((tmpDate.getDay() < 10) ? '0' : '' ) + tmpDate.getDay().toString();
	var date = elemY.value.toString() + ((parseInt(elemM.value) < 10) ? '0' : '' ) + parseInt(elemM.value).toString() + ((parseInt(elemD.value) < 10) ? '0' : '' ) + parseInt(elemD.value).toString();

	if ( elem.getAttribute('fieldname') ) {
		var fName = elem.getAttribute('fieldname');
	} else {
		var fName = elem.name;
	}
	
	// Do required field checking
	if ( rules.indexOf('required') != -1 ) {
		
		if ( !elemD.options[elemD.selectedIndex].value || !elemM.options[elemM.selectedIndex].value || !elemY.options[elemY.selectedIndex].value ) {
			elemD.className += ' formError';
			elemM.className += ' formError';
			elemY.className += ' formError';
				
			if ( valmsg ) {
				return valmsg + "\n";
			} else {
				return fName + " is a required field.\n";
			}
		}
	}
	
	// Validity checking for dates
	// TODO
	
		
	// Tense checking
	if ( rules.indexOf('past') != -1 ) {
		if ( date >= cur_date ) {
			return fName + " must be a date prior to today.\n";
		}
	} else if ( rules.indexOf('future') != -1 ) {
		if ( date <= cur_date ) {
			return fName + " must be a date after today.\n";
		}
	}
	
	// Remove error class on element since there were no errors
	elem.className = elem.className.replace(/formError/g, '');
	elemD.className = elemD.className.replace(/formError/g, '');
	elemM.className = elemM.className.replace(/formError/g, '');
	elemY.className = elemY.className.replace(/formError/g, '');
	
	return '';
}