/*
 * JAVASCRIPT FORM VALIDATOR 2.0
 */
  
/**
 * Validator Object 2.0
 * @author Vito & Salo
 */
var Validation = {
	/**
	 * Criteria Function Object
	 */
	Is: {
			/**
			 * Tests if an element value is mandatory
			 * @method Mandatory
			 * @param {Mixed} elem -- form element to test or its dom id
			 * @return {Boolean} result -- test result
			 */
			Mandatory:	function(elem) {
							if(typeof elem == "string") elem = $(elem);
							return _exists(elem.value);
						},
			/**
			 * Tests if an element value is between a range
			 * @method Range
			 * @param {Mixed} elem -- form element to test or its dom id
			 * @param {Number} from -- left range bound
			 * @param {Number} to -- right range bound
			 * @param {Boolean} [boundsIncluded] -- optional, true if the range bounds are 'included', else 'excluded'. Default value is 'excluded'
			 * @param {String} [appliedTo] -- optional, validated by 'internal' or 'external' range values. Default value is 'internal'
			 * @return {Boolean} result -- test result
			 */
			Range:		function(elem, from, to, boundsIncluded, appliedTo) {
							if(typeof elem == "string") elem = $(elem);
							if(!_exists(elem) || !elem.value || !_exists(from) || !_exists(to)) return null;
							if(_exists(boundsIncluded) && boundsIncluded) {
								if(appliedTo && appliedTo == "external") {
									return (elem.value <= from || elem.value >= to);
								} else {
									return (elem.value >= from && elem.value <= to);
								}
							} else {
								if(appliedTo && appliedTo == "external") {
									return (elem.value < from || elem.value > to);
								} else {
									return (elem.value > from && elem.value < to);
								}
							}
						},
			/**
			 * Tests if an element value is greater than value
			 * @method Greater
			 * @param {Mixed} elem -- form element to test or its dom id
			 * @param {Number} value -- value to test
			 * @param {Boolean} [valueIncluded] -- optional, true if the value is 'included', else 'excluded'. Default value is 'excluded'
			 * @return {Boolean} result -- test result
			 */
			Greater:	function(elem, value, valueIncluded) {
							if(typeof elem == "string") elem = $(elem);
							if(!_exists(elem) || !elem.value || !_exists(value)) return null;
							return (!valueIncluded ? elem.value > value : elem.value >= value);
						},
			/**
			 * Tests if an element value is lesser than value
			 * @method Lesser
			 * @param {Mixed} elem -- form element to test or its dom id
			 * @param {Number} value -- value to test
			 * @param {Boolean} [valueIncluded] -- optional, true if the value is 'included', else 'excluded'. Default value is 'excluded'
			 * @return {Boolean} result -- test result
			 */
			Lesser:		function(elem, value, valueIncluded) {
							if(typeof elem == "string") elem = $(elem);
							if(!_exists(elem) || !elem.value || !_exists(value)) return null;
							return (!valueIncluded ? elem.value < value : elem.value <= value);
						},
			/**
			 * Tests if an element value is equal to something
			 * @method EqualTo
			 * @param {Mixed} elem -- form element to test or its dom id
			 * @param {Mixed} value -- something that have to be equal to element value
			 * @return {Boolean} result -- test result
			 */
			EqualTo:	function(elem, value) {
							if(typeof elem == "string") elem = $(elem);
							if(!_exists(elem) || !elem.value || !_exists(value)) return null;
							var re = new RegExp("^" + value + "$");
							return re.test(elem.value);
						},
			/**
			 * Tests if an element value length is between a range
			 * @method Long
			 * @param {Mixed} elem -- form element to test or its dom id
			 * @param {Number} [min] -- optional, min length
			 * @param {Number} [max] -- optional, max length
			 * @return {Boolean} result -- test result
			 */
			Long:		function(elem, min, max) {
							if(typeof elem == "string") elem = $(elem);
							if(!_exists(elem) || !elem.value) return null;
							return ((_exists(min) && !_exists(max)) ? (elem.value.length >= min) : ((!_exists(min) && _exists(max)) ? (elem.value.length <= max) : (elem.value.length >= min && elem.value.length <= max)));
						},
			/**
			 * Tests if an element is checked
			 * @method Checked
			 * @param {Mixed} elem -- form element to test or its dom id
			 * @return {Boolean} result -- test result
			 */
			Checked:	function(elem) {
							if(typeof elem == "string") elem = $(elem);
							if(!_exists(elem)) return null;
							return elem.checked;
						},
			/**
			 * Tests if an element value is a valid date
			 * @method Date
			 * @param {Mixed} elem -- form element to test or its dom id
			 * @return {Boolean} result -- test result
			 */
			Date:		function(elem) {
							if(typeof elem == "string") elem = $(elem);
							if(!_exists(elem) || !elem.value) return null;
							var re1 = /^(\d{4})(-\d{2}){2}$/;
							var re2 = /^\d{2}\.\d{2}\.\d{4}$/;
							var re3 = /^\d{2}\/\d{2}\/\d{4}$/;
							var re4 = /^\d{2}-\d{2}-\d{4}$/;
							return (re1.test(elem.value) || re2.test(elem.value) || re3.test(elem.value) || re4.test(elem.value));
						},
			/**
			 * Tests if an element value is an integer number
			 * @method Integer
			 * @param {Mixed} elem -- form element to test or its dom id
			 * @return {Boolean} result -- test result
			 */
			Integer:	function(elem) {
							if(typeof elem == "string") elem = $(elem);
							if(!_exists(elem) || !elem.value) return null;
							var re  = /^\d+$/;
							return re.test(elem.value);
						},
			/**
			 * Tests if an element value is a float number
			 * @method Float
			 * @param {Mixed} elem -- form element to test or its dom id
			 * @return {Boolean} result -- test result
			 */
			Float:		function(elem) {
							if(typeof elem == "string") elem = $(elem);
							if(!_exists(elem) || !elem.value) return null;
							var re  = /^[+-]?\d*(\.?|,?)\d*[^\.,]\b$/;
							return re.test(elem.value);
						},
			/**
			 * Tests if an element value is a valid IP number
			 * @method IP
			 * @param {Mixed} elem -- form element to test or its dom id
			 * @return {Boolean} result -- test result
			 */
			IP:			function(elem) {
							if(typeof elem == "string") elem = $(elem);
							if(!_exists(elem) || !elem.value) return null;
							var re = /^\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b$/;
							return re.test(elem.value);
						},
			/**
			 * Tests if an element value is a valid URI string
			 * @method URI
			 * @param {Mixed} elem -- form element to test or its dom id
			 * @return {Boolean} result -- test result
			 */
			URI:				function(elem) {
									if(typeof elem == "string") elem = $(elem);
									if(!_exists(elem) || !elem.value) return null;
									var re = /^((ht|f)tp(s?)\:\/\/)?[a-zA-Z0-9\-\.]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2})(\/\S*)?$/;
									return re.test(elem.value);
								},
			/**
			 * Tests if an element value is made only by letters
			 * @method Letters
			 * @param {Mixed} elem -- form element to test or its dom id
			 * @return {Boolean} result -- test result
			 */
			Letters:			function(elem) {
									if(typeof elem == "string") elem = $(elem);
									if(!_exists(elem) || !elem.value) return null;
									var re = /^[A-Za-zìèéòàù_ ]+$/;
									return re.test(elem.value);
								},
			/**
			 * Tests if an element value is made only by letters and numbers
			 * @method LettersAndNumbers
			 * @param {Mixed} elem -- form element to test or its dom id
			 * @return {Boolean} result -- test result
			 */
			LettersAndNumbers:	function(elem) {
									if(typeof elem == "string") elem = $(elem);
									if(!_exists(elem) || !elem.value) return null;
									var re = /^[A-Za-z0-9ìèéòàù_ \.]+$/;
									return re.test(elem.value);
								},
			/**
			 * Tests if an element value is valid mail address string
			 * @method Mail
			 * @param {Mixed} elem -- form element to test or its dom id
			 * @return {Boolean} result -- test result
			 */
			Mail:				function(elem) {
									if(typeof elem == "string") elem = $(elem);
									if(!_exists(elem) || !elem.value) return null;
									var re = /^[a-zA-Z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+(?:[a-zA-Z]{2}|com|org|net|gov|biz|info|name|aero|biz|info|jobs|museum)\b$/;
									return re.test(elem.value);
								},
			/**
			 * Tests if an element value is a strong password string
			 * @method StrongPassword
			 * @param {Mixed} elem -- form element to test or its dom id
			 * @return {Boolean} result -- test result
			 */
			StrongPassword:		function(elem) {
									if(typeof elem == "string") elem = $(elem);
									if(!_exists(elem) || !elem.value) return null;
									var relower = /[a-z]+/, reupper = /[A-Z]+/, redigits = /\d+/, rechars = /[;:,\. ]+/;
									return elemValue.length >= 8 && relower.test(elemValue) && reupper.test(elemValue) && redigits.test(elemValue) && rechars.test(elemValue);
								},
			/**
			 * Tests if an element value is a valid phone number string
			 * @method PhoneNumber
			 * @param {Mixed} elem -- form element to test or its dom id
			 * @return {Boolean} result -- test result
			 */
			PhoneNumber:		function(elem) {
									if(typeof elem == "string") elem = $(elem);
									if(!_exists(elem) || !elem.value) return null;
									var re = /^([\+]|00)?(\d+[\\ \.\/-]?\d+)+$/;
									return re.test(elem.value);
								}
	},
	/**
	 * Action Functions Object
	 */
	Do: {
			/**
			 * Opens an alert dialog box
			 * @method Alert
			 * @param {String} msg -- alert message
			 * @param {Mixed} [elem] -- optional, form element to focus after closing the alert box or its dom id
			 * @return {Boolean} result -- true to continue executing
			 */
			Alert:			function(msg, elem) {
								alert(msg);
								if(_exists(elem)) {
									Validation.Do.Select(elem);
								}
								return true;
							},
			/**
			 * Opens a confirm dialog box
			 * @method Confirm
			 * @param {String} msg -- confirm message
			 * @param {Mixed} [elem] -- optional, form element to focus after closing the confirm box or its dom id
			 * @return {Boolean} result -- true if user confirms, else false
			 */
			Confirm:		function(msg, elem, conf) {
								if(!confirm(msg)) {
									if(_exists(elem)) {
										Validation.Do.Select(elem);
									}
									return false;
								}
								return true;
							},
			/**
			 * Opens an alert dialog box and block executing the form
			 * @method Block
			 * @param {String} msg -- block message
			 * @param {Mixed} [elem] -- optional, form element to focus after closing the blocking alert box or its dom id
			 * @return {Boolean} result -- false to block executing
			 */
			Block:			function(msg, elem) {
								alert(msg);
								if(_exists(elem)) {
									Validation.Do.Select(elem);
								}
								return false;
							},
			/**
			 * Enables an element
			 * @method Enable
			 * @param {Mixed} elem -- the element to enable or its dom id
			 * @return {Boolean} result -- true to continue executing
			 */
			Enable: 		function(elem) {
								if(typeof elem == "string") elem = $(elem);
								if(_exists(elem)) elem.disabled = false;
								return true;
							},
			/**
			 * Disables an element
			 * @method Disable
			 * @param {Mixed} elem -- the element to disable or its dom id
			 * @return {Boolean} result -- true to continue executing
			 */
			Disable: 		function(elem) {
								if(typeof elem == "string") elem = $(elem);
								if(_exists(elem)) elem.disabled = true;
								return true;
							},
			/**
			 * Sets a default value to an element
			 * @method DefaultValue
			 * @param {Mixed} elem -- the element, or its dom id, to set its value
			 * @param {String} value -- value to set to the element
			 * @return {Boolean} result -- true to continue executing
			 */
			DefaultValue:	function(elem, value) {
								if(typeof elem == "string") elem = $(elem);
								if(_exists(elem)) elem.value = value;
								return true;
							},
			/**
			 * Selects an element
			 * @method Select
			 * @param {Mixed} elem -- the element to select or its dom id
			 * @return {Boolean} result -- true to continue executing
			 */
			Select:			function(elem) {
								if(typeof elem == "string") elem = $(elem);
								if(_exists(elem)) {
									elem.focus();
									if((elem.type && elem.type.match(/text|password|input/)) && elem.nodeName == "TEXTAREA") elem.select();
								}
								return true;
							},
			/**
			 * Checks an element
			 * @method Check
			 * @param {Mixed} elem -- the element to check or its dom id
			 * @return {Boolean} result -- true to continue executing
			 */
			Check:			function(elem) {
								if(typeof elem == "string") elem = $(elem);
								if(_exists(elem)) elem.checked = true;
								return true;
							},
			/**
			 * Unchecks an element
			 * @method Uncheck
			 * @param {Mixed} elem -- the element to uncheck or its dom id
			 * @return {Boolean} result -- true to continue executing
			 */
			Uncheck:		function(elem) {
								if(typeof elem == "string") elem = $(elem);
								if(_exists(elem)) elem.checked = false;
								return true;
							},
			/**
			 * Goes to an element. This method is an alias of Select
			 * @method GoTo
			 * @param {Mixed} elem -- the element to go to or its dom id
			 * @return {Boolean} result -- true to continue executing
			 */
			GoTo:			function(elem) {
								if(typeof elem == "string") elem = $(elem);
								return Validation.Do.Select(elem);
							},
			/**
			 * Shows an element
			 * @method Show
			 * @param {Mixed} elem -- the element to show or its dom id
			 * @param {String} [css] -- optional, specifies how the element have to be sown: by setting style visibility value, by setting style display value or by setting a className value
			 * @return {Boolean} result -- true to continue executing
			 */
			Show:			function(elem, css) {
								if(typeof elem == "string") elem = $(elem);
								if(_exists(elem)) {
									if(!_exists(css) || css == "visibility") {
										elem.style.visibility = "visible";
									}
									else if(css == "display") {
										elem.style.display = "";
									} else {
										elem.className = css;
									}
								}
								return true;
							},
			/**
			 * Hides an element
			 * @method Hide
			 * @param {Mixed} elem -- the element to hide or its dom id
			 * @param {String} [css] -- optional, specifies how the element have to be sown: by setting style visibility value, by setting style display value or by setting a className value
			 * @return {Boolean} result -- true to continue executing
			 */
			Hide:			function(elem, css) {
								if(typeof elem == "string") elem = $(elem);
								if(_exists(elem)) {
									if(!_exists(css) || css == "visibility") {
										elem.style.visibility = "hidden";
									}
									else if(css == "display") {
										elem.style.display = "none";
									} else {
										elem.className = css;
									}
								}
								return true;
							}
	}
};
