//----------------------------------------------------------------------------------
// File: validationaide.js
//
// Copyright (c) 2007 Ste Brennan (dnaide.com)
// Licensed under the COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
// http://www.opensource.org/licenses/cddl1.php
//
//----------------------------------------------------------------------------------

//----------------------------------------------------------------------------------
// Modified by Matias Perrone - www.globalinnovation.com.ar
//----------------------------------------------------------------------------------

//
// Validator Rule classes
//
function ValidatorRule (name, errorMessage, validationMethod){
	this.validationMethod = validationMethod;
	this.errorMessage = errorMessage ? errorMessage : 'Validation error - no message.';
	this.name = name;
};
ValidatorRule.prototype = {
	doValidation : function(fieldValue, fieldObj) {
		return this.validationMethod(fieldValue, fieldObj);
	}
};

//
// Validator Rule Collection class
//
function ValidatorRuleCollection(){
	this.items = {};
};

ValidatorRuleCollection.prototype = {
	add : function(name, errorMessage, testFunction) {
		this.items[name] = new ValidatorRule(name, errorMessage, testFunction);
	}
};


function ValidatorLeyend(sLanguage) {

	if (typeof sLanguage == 'undefined') sLanguage = 'en-US';
	switch (sLanguage)
	{
		case 'es-AR':
		case 'es-ES':
		case 'es':
			this.Mandatory =			'Este es un campo obligatorio.';
			this.InvalidEmail =			'Por favor, ingrese una direcci&oacute;n de email v&aacute;lida.';
			this.InvalidNumber =		'Por favor, ingrese un n&uacute;mero v&aacute;lido.';
			this.InvalidDigits =		'Por favor, utilice s&oacute;lo n&uacute;meros, evite espacios, puntos o comas.';
			this.NoAlphaNum = 			'Por favor, utiliza s&oacute;lo letras (a-z) o n&uacute;meros (0-9) para este campo. No se permiten espacios u otros caracteres.';
			this.NoAlphaNumSpaces =		'Por favor, utiliza s&oacute;lo letras (a-z), letras especiales y/o n&uacute;meros (0-9) para este campo. Se permiten espacios.';
			this.InvalidDate_DDMMYYYY =	'Por favor, ingrese una fecha v&aacute;lida, debe ser dd/mm/yyyy';
			this.InvalidDate_MMDDYYYY =	'Por favor, ingrese una fecha v&aacute;lida, debe ser dd/mm/yyyy';
			this.InvalidDate_YYYYMMDD =	'Por favor, ingrese una fecha v&aacute;lida, debe ser yyyy/mm/dd';
			this.InvalidURL =			'Por favor, ingrese una direcci&oacute;n URL v&aacute;lida (Debe comiezar con &quote;http://&quote;, &quote;https://&quote; or &quote;ftp://&quote;)';
			this.InvalidMoneyDot =		'Por favor, ingrese una cantidad de $ v&aacute;lida. Por ejemplo $100.00';
			this.InvalidMoneyComma =	'Por favor, ingrese una cantidad de $ v&aacute;lida. Por ejemplo $100,00';
			this.UsernameTaken =		'El nombre de usuario no está disponible.';
			this.ChooseOne =			'Elige al menos una opci&oacute;n.';
			this.PasswordDoesNotMatch =	'Las claves no concuerdan.';
			this.PasswordConfirmMulti =	'Only one field must have the class "validator-password-confirm".';
			break;
		case 'en-US':
		case 'en-UK':
		case 'en':
		default:
			this.Mandatory =			'This is a mandatory field';
			this.InvalidEmail =			'Please, enter a valid email';
			this.InvalidNumber =		'Please, enter a valid number';
			this.InvalidDigits =		'Please, use numbers only, avoid spaces, dot or comma.';
			this.NoAlphaNum = 			'Please, use letters, special letters and/or numbers. Spaces and special chars are not allowed.';
			this.NoAlphaNumSpaces =		'Please, use letters, special letters, numbers  and/or spaces. Special chars are not allowed.';
			this.InvalidDate_DDMMYYYY =	'Please, enter a valid date, format = dd/mm/yyyy';
			this.InvalidDate_MMDDYYYY =	'Please, enter a valid date, format = mm/dd/yyyy';
			this.InvalidDate_YYYYMMDD =	'Please, enter a valid date, format = yyyy/mm/dd';
			this.InvalidURL =			'Please, enter a valid URL (Must start width &quote;http =//&quote;, &quote;https =//&quote; or &quote;ftp =//&quote;)';
			this.InvalidMoneyDot =		'Please, enter a valid amount of $. i.e. $100.00';
			this.InvalidMoneyComma =	'Please, enter a valid amount of $. i.e. $100,00';
			this.UsernameTaken =		'The username is already taken';
			this.ChooseOne =			'At least choose one option';
			this.PasswordDoesNotMatch =	'The password are different';
			this.PasswordConfirmMulti =	'Only one field must have the class "validator-password-confirm".';
			break;
	}
}


//
// Static methods
//
jQuery.validationAide = {
	getDefaultValidationRules : function(sLanguage){

		var rules = new ValidatorRuleCollection();
		var oLeyend = new ValidatorLeyend(sLanguage);

		rules.add('validator-required', oLeyend.Mandatory, function(fieldValue, fieldObj) {
			if (fieldValue == "")	return false;
			return true;
		});

		rules.add('required', oLeyend.Mandatory, function(fieldValue, fieldObj) {
			if (fieldValue == "")	return false;
			return true;
		});

		rules.add('validator-email', oLeyend.InvalidEmail, function(fieldValue, fieldObj) {
			if (fieldValue == "")	return true;
			return /\w{1,}[@][\w\-]{1,}([.]([\w\-]{1,})){1,3}$/.test(fieldValue);
		});

		rules.add('validator-number', oLeyend.InvalidNumber, function(fieldValue, fieldObj) {
			if (fieldValue == "")	return true;
			return (!isNaN(fieldValue) && !/^\s+$/.test(fieldValue));
		});

		rules.add('validator-digits', oLeyend.InvalidDigits, function(fieldValue, fieldObj) {
			if (fieldValue == "")	return true;
			return !/[^\d]/.test(fieldValue);
		});

		rules.add('validator-alphanum', oLeyend.NoAlphaNum, function(fieldValue, fieldObj) {
			if (fieldValue == "")	return true;
			return !/\W/.test(fieldValue);
		});

		rules.add('validator-alphanum-spaces', oLeyend.NoAlphaNumSpaces, function(fieldValue, fieldObj) {
			if (fieldValue == "")	return true;
			return !/[^(0-9A-Z_a-zŔ-˙)+( .\-)*]/.test(fieldValue);
		});

		rules.add('validator-date-ddmmyyyy', oLeyend.InvalidDate_DDMMYYYY, function(fieldValue, fieldObj) {
			if (fieldValue == "")	return true;
			var regex = /^(\d{2})\/(\d{2})\/(\d{4})$/;
			if(!regex.test(fieldValue)) return false;
			var d = new Date(fieldValue.replace(regex, '$2/$1/$3'));
			return ( parseInt(RegExp.$2, 10) == (1+d.getMonth()) ) &&
							(parseInt(RegExp.$1, 10) == d.getDate()) &&
							(parseInt(RegExp.$3, 10) == d.getFullYear() );
		});

		rules.add('validator-date-mmddyyyy', oLeyend.InvalidDate_MMDDYYYY, function(fieldValue, fieldObj) {
			if (fieldValue == "")	return true;
			var regex = /^(\d{2})\/(\d{2})\/(\d{4})$/;
			if(!regex.test(fieldValue)) return false;
			var d = new Date(fieldValue.replace(regex, '$2/$1/$3'));
			return ( parseInt(RegExp.$1, 10) == (1+d.getMonth()) ) &&
							(parseInt(RegExp.$2, 10) == d.getDate()) &&
							(parseInt(RegExp.$3, 10) == d.getFullYear() );
		});

		rules.add('validator-url', oLeyend.InvalidURL, function(fieldValue, fieldObj) {
			if (fieldValue == "")	return true;
			return /^(http|https|ftp):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(:(\d+))?\/?/i.test(fieldValue);
		});

		rules.add('validate-currency-comma', oLeyend.InvalidMoneyComma, function(fieldValue, fieldObj) {
			if (fieldValue == "")	return true;
			return /^\$?\-?([1-9]{1}[0-9]{0,2}([0-9]{3})*(\,[0-9]{0,2})?|[1-9]{1}\d*(\,[0-9]{0,2})?|0(\,[0-9]{0,2})?|(\,[0-9]{1,2})?)$/.test(fieldValue);
		});

		rules.add('validate-currency-dot', oLeyend.InvalidMoneyDot, function(fieldValue, fieldObj) {
			if (fieldValue == "")	return true;
			return /^\$?\-?([1-9]{1}[0-9]{0,2}([0-9]{3})*(\.[0-9]{0,2})?|[1-9]{1}\d*(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|(\.[0-9]{1,2})?)$/.test(fieldValue);
		});

		rules.add('validator-username', oLeyend.UsernameTaken, function(fieldValue, fieldObj) {
			if (typeof validatorUsernameFunction == 'function')
				return validatorUsernameFunction(fieldValue, fieldObj);
			else
			{
				alert('The function "validatorUsernameFunction" does not exists');
				return true;
			}
		});

		rules.add('validator-password', oLeyend.PasswordDoesNotMatch, function(fieldValue, fieldObj) {
			var aConfirm = $('.validator-password-confirm');
			if (aConfirm.length != 1)
			{
				alert(oLeyend.PasswordConfirmMulti);
				return false;
			}
			else
			{
				return (aConfirm.val() == fieldValue);
			}
		});

		rules.add('validator-required-once', oLeyend.ChooseOne, function(fieldValue, fieldObj) {
			var aOptions = $('.validator-required-once:checked');
			return (aOptions.length > 0);
		});

		return rules;
	},

	extendOptions : function(options){

		var retval = jQuery.extend({}, options || {});

		if (typeof retval.showInlineMessages == 'undefined')
			retval.showInlineMessages = false;

		if (typeof retval.inlineShowSpeed == 'undefined')
			retval.inlineShowSpeed= "";

		if (typeof retval.inlineMessageElementIdPrefix == 'undefined')
			retval.inlineMessageElementIdPrefix= "ValidationInlineErrorMessage-";

		if (typeof retval.inlineMessageCssClass == 'undefined')
			retval.inlineMessageCssClass= "validation-inline-error-message";

		if (typeof retval.showSummary == 'undefined')
			retval.showSummary = true;

		if (typeof retval.summaryElementId == 'undefined')
			retval.summaryElementId = "ClientValidationSummary";

		if (typeof retval.summaryMessage == 'undefined')
			retval.summaryMessage = "Por favor corrige lo siguiente:";

		if (typeof retval.summaryFieldMessageFormat == 'undefined')
			retval.summaryFieldMessageFormat = "##FIELD## - ##MESSAGE##";

		if (typeof retval.fieldErrorCssClass == 'undefined')
			retval.fieldErrorCssClass = "validation-failed";

		if (typeof retval.fieldMessageSeparator == 'undefined')
			retval.fieldMessageSeparator = ' - ';

		return retval;
	},


	resetForm : function (formId, options){

		if (typeof jQuery.fn.fieldStringVal != "function"){
			alert("ADVERTENCIA: la validación no funcionará a menos que stringaide esté cargada!\n\n"+
				  "WARNING: The validation will not work if stringaide is not loaded");
		}

		var fullOptions = jQuery.validationAide.extendOptions(options);

		if (fullOptions.showSummary){
			// Hide summary container
			jQuery("#" + fullOptions.summaryElementId).html("").hide();
		}

		// Loop through each input and remove any previous inline error message / classes
		jQuery(formId + " :input").each( function(){
			var inlineMessageElementId = "#" + fullOptions.inlineMessageElementIdPrefix + this.id;
			jQuery(inlineMessageElementId).remove();
			jQuery(this).removeClass(fullOptions.fieldErrorCssClass);
		});

	},


	resetInput : function (oInput){

		if (typeof jQuery.fn.fieldStringVal != "function"){
			alert("ADVERTENCIA: la validación no funcionará a menos que stringaide esté cargada!\n\n"+
				  "WARNING: The validation will not work if stringaide is not loaded");
		}

		var fullOptions = jQuery.validationAide.extendOptions({});

		// Remove any previous inline error message / classes
		var inlineMessageElementId = "#" + fullOptions.inlineMessageElementIdPrefix + oInput.id;
		jQuery(inlineMessageElementId).remove();
		jQuery(oInput).removeClass(fullOptions.fieldErrorCssClass);

	},


	validateForm : function(formId, validationRules, options, preFieldValidation, postFieldValidation, sLanguage){
		jQuery.validationAide.resetForm(formId, options);

		var fullOptions = jQuery.validationAide.extendOptions(options);

		var validatedOK = true;

		validationRules = validationRules ? validationRules : jQuery.validationAide.getDefaultValidationRules(sLanguage);

	  var scrollTo = "";
	  var focusField = "";
	  var firstErroredField = true;

	  if (fullOptions.showSummary){
			var messagesForSummary = new Array();
			var fieldsForSummary = new Array();
	  }

		// Loop through each input and validate
		jQuery(formId + " :input").each( function(){

			var elmId = this.id;

			if (elmId != ""){
				var jQueryElm = jQuery(this);
				var cssClassesStr = new String(jQueryElm.attr("class"));
				cssClassesStr = jQuery.trim(cssClassesStr);
				if (cssClassesStr.length > 0){
					var cssClasses = cssClassesStr.split(" ");

					for (var i=0; i<cssClasses.length; i++){

						var validationRule = validationRules.items[cssClasses[i]];

						if (validationRule){

							// Get value of the field as a string
							var fieldValue = jQueryElm.fieldStringVal();

							// Fire off preFieldValidation event
							if (typeof preFieldValidation == 'function')
								preFieldValidation(fieldValue, this);

							var retval = validationRule.doValidation(fieldValue, this);

							// Fire off postFieldValidation event
							if (typeof postFieldValidation == 'function')
								postFieldValidation(fieldValue, this, retval);

							if (!retval){

								validatedOK = false;

								// Set focus and scroll to the first errored element
								if (firstErroredField){
									scrollTo = elmId;
									focusField = elmId;
									firstErroredField = false;
								}

								// Set the error css class
								jQueryElm.addClass(fullOptions.fieldErrorCssClass);

								var title = jQueryElm.attr("title");
								if (!title || title == 'undefined')
								{
									if (!title || title == 'undefined')
										title = elmId;
								}
								var fieldFriendlyName = title;
								var fieldMessage = validationRule.errorMessage;

								if (fieldFriendlyName.indexOf(fullOptions.fieldMessageSeparator) > -1){
									var messageArr = fieldFriendlyName.split(fullOptions.fieldMessageSeparator);
									fieldFriendlyName = messageArr[0];
									fieldMessage = messageArr[1];
								}

								if (fullOptions.showSummary){
									// Add the message to the summary array
									fieldsForSummary.push(elmId);
									var messageForSummary = new String(fullOptions.summaryFieldMessageFormat);
									messageForSummary = messageForSummary.replace("##FIELD##", fieldFriendlyName);
									messageForSummary = messageForSummary.replace("##MESSAGE##", fieldMessage);
									messagesForSummary.push(messageForSummary);
								}

								if (fullOptions.showInlineMessages){
									var inlineMessageElementId = fullOptions.inlineMessageElementIdPrefix + elmId;
									// Insert the inline error message
									jQueryElm.after('<div id="' + inlineMessageElementId + '" class="' + fullOptions.inlineMessageCssClass + '">' + fieldMessage + '</div>');
									if (fullOptions.inlineShowSpeed != ""){
										jQuery("#" + inlineMessageElementId).hide();
										jQuery("#" + inlineMessageElementId).show(fullOptions.inlineShowSpeed);
									}
								}

								break;
							}
						}
					}
				}
			}

		});

		if (!validatedOK && fullOptions.showSummary){
			// Show the message summary
			var summaryHtml = "";
			if (fullOptions.summaryMessage != ""){
				summaryHtml = fullOptions.summaryMessage;
			}

			summaryHtml += "<ul>";
			for(var i=0;i<messagesForSummary.length; i++){
				summaryHtml += "<li><a href=\"#\" onclick=\"location.hash = '#" + fieldsForSummary[i] + "'; jQuery('#" + fieldsForSummary[i] + "')[0].focus(); return false;\">" + messagesForSummary[i] + "</a></li>";
			}
			summaryHtml += "</ul>";

			jQuery("#" + fullOptions.summaryElementId).html(summaryHtml).show();

			scrollTo = fullOptions.summaryElementId;
		}

		if (scrollTo != ""){
			location.hash = "#" + scrollTo;
		}

		if (focusField != ""){
			jQuery("#" + focusField)[0].focus();
		}

		return validatedOK;
	},

	validateThis : function(oInput, validationRules, preFieldValidation, postFieldValidation){
		jQuery.validationAide.resetInput(oInput);

		var validatedOK = true;

		var fullOptions = jQuery.validationAide.extendOptions({});

		validationRules = validationRules ? validationRules : jQuery.validationAide.getDefaultValidationRules();

	  var scrollTo = "";
	  var focusField = "";
	  var firstErroredField = true;

		// Loop through each input and validate

		var elmId = oInput.id;

		if (elmId != ""){
			var jQueryElm = jQuery(oInput);
			var cssClassesStr = new String(jQueryElm.attr("class"));
			cssClassesStr = jQuery.trim(cssClassesStr);
			if (cssClassesStr.length > 0){
				var cssClasses = cssClassesStr.split(" ");

				for (var i=0; i<cssClasses.length; i++){

					var validationRule = validationRules.items[cssClasses[i]];

					if (validationRule){

						// Get value of the field as a string
						var fieldValue = jQueryElm.fieldStringVal();

						// Fire off preFieldValidation event
						if (typeof preFieldValidation == 'function')
							preFieldValidation(fieldValue, oInput);

						var retval = validationRule.doValidation(fieldValue, oInput);

						// Fire off postFieldValidation event
						if (typeof postFieldValidation == 'function')
							postFieldValidation(fieldValue, oInput, retval);

						if (!retval){

							validatedOK = false;

							// Set focus and scroll to the first errored element
							if (firstErroredField){
								scrollTo = elmId;
								focusField = elmId;
								firstErroredField = false;
							}

							// Set the error css class
							jQueryElm.addClass(fullOptions.fieldErrorCssClass);

							var title = jQueryElm.attr("title");
							if (!title || title == 'undefined')
							{
								if (!title || title == 'undefined')
									title = elmId;
							}
							var fieldFriendlyName = title;
							var fieldMessage = validationRule.errorMessage;

							if (fieldFriendlyName.indexOf(fullOptions.fieldMessageSeparator) > -1){
								var messageArr = fieldFriendlyName.split(fullOptions.fieldMessageSeparator);
								fieldFriendlyName = messageArr[0];
								fieldMessage = messageArr[1];
							}

							var inlineMessageElementId = fullOptions.inlineMessageElementIdPrefix + elmId;
							// Insert the inline error message
							jQueryElm.after('<div id="' + inlineMessageElementId + '" class="' + fullOptions.inlineMessageCssClass + '">' + fieldMessage + '</div>');
							if (fullOptions.inlineShowSpeed != ""){
								jQuery("#" + inlineMessageElementId).hide();
								jQuery("#" + inlineMessageElementId).show(fullOptions.inlineShowSpeed);
							}

							break;
						}
					}
				}
			}
		}


		if (focusField != ""){
			jQuery("#" + focusField)[0].focus();
		}

		return validatedOK;
	}
};


//
// jQuery object method extensions
//
jQuery.fn.validationAideEnable = function(validationRules, options, preFieldValidation, postFieldValidation){
	jQuery.validationAide.resetForm("#" + this.id, options);
	this.unbind("submit");
	this.bind("submit", function(){ return jQuery.validationAide.validateForm("#" + this.id, validationRules, options, preFieldValidation, postFieldValidation); });
	return this;
};

jQuery.fn.validationAideDisable = function(){
	this.unbind("submit");
	return this;
};

jQuery.fn.validationAideDisableOnClick = function(formId){
	this.unbind("click");
	this.bind("click", function(){ jQuery(formId).unbind("submit"); });
	return this;
};

jQuery.fn.validationAideEnableOnClick = function(formId, validationRules, options, preFieldValidation, postFieldValidation){
	jQuery.validationAide.resetForm(formId, options);
	this.unbind("click");
	this.bind("click", function(){ jQuery(formId).validationAideEnable(validationRules, options, preFieldValidation, postFieldValidation); });
	return this;
};

jQuery.fn.validationAideDisableOnBlur = function(oInput){
	jQuery.validationAide.resetInput(oInput);
	this.unbind("blur");
	return this;
};

jQuery.fn.validationAideEnableOnBlur = function(oInput, validationRules, preFieldValidation, postFieldValidation){
	this.unbind("blur");
	this.blur(function(){ jQuery.validationAide.validateThis(oInput, validationRules, preFieldValidation, postFieldValidation); });
	return this;
};

