var Dom = YAHOO.util.Dom;

var Db = {};

Db.util =
{
	objectToUrl: function(params)
	{
		var url = "";
		for (key in params)
		{
			var value = escape(params[key]);
			url += key + '=' + value + '&';
		}
		return url;
	}
}

Db.Validations =
{
	_validations: {},
	
	CausesValidation: true,

	Validator: function(controlName, validation, params)
	{
		var _valid = false;
		var _control = Dom.get(controlName);
		var _validating = false;
		var _blurInitiated = false;
		
		var getControl = function()
		{
			return _control;
		};

		var validate = function(e)
		{
			_blurInitiated = (e && e.type == 'blur');
			_validating = true;
			_valid = validation.call(this, this);
			if (typeof(_valid) == 'boolean')
			{
				_validating = false;
			} 
			return _valid;
		};
		
		var isValid = function()
		{
			return _valid;
		};
		
		var setValid = function(valid)
		{
			_valid = valid;
		};
		
		var isValidating = function()
		{
			return _validating;
		}
		
		var setValidating = function(validating)
		{
			_validating = validating;
		};
		
		var getBlurInitiated = function()
		{
			return _blurInitiated;
		};
		
		YAHOO.util.Event.addListener(_control, 'blur', validate, params);
		
		_control.validator = {
			params: params,
			getControl: getControl,
			validate: validate,
			isValid: isValid,
			setValid: setValid,
			isValidating: isValidating,
			setValidating: setValidating,
			getBlurInitiated: getBlurInitiated
		};
		
		return _control.validator;
	},
	
	HiddenButtonTrackerCreated: [],
	
	AddListener: function(controlName, validatorName, callback, params)
	{
		var validator = new this.Validator(controlName, callback, params);
		var idForm = validator.getControl().form.id;
		
		YAHOO.util.Event.onDOMReady(function()
		{
			if (validatorName == 'CustomValidate' && params.serverCallback && !(idForm in Db.Validations.HiddenButtonTrackerCreated))
			{
				var hd = document.createElement('INPUT');
				hd.type = 'hidden';
				hd.id = 'hdButtonTracker_' + idForm;
				hd.value = '';
				validator.getControl().form.appendChild(hd);
				
				Db.Validations.HiddenButtonTrackerCreated[idForm] = true;
				
				Dom.getElementsBy(
					function(el) { return el.type == 'submit'; },
					'input',
					validator.getControl().form,
					function(el)
					{
						YAHOO.util.Event.addListener(el, 'click',
							function(ev, elInn)
							{
								hd.value = elInn.name + '=' + elInn.value;
							}, el);
					} );
			}
		});
		
		var name = controlName + '_' + validatorName;
		if (!this._validations[idForm])
		{
			this._validations[idForm] = {};
		}
		this._validations[idForm][name] = validator;
	},	

	Submit: function(form, doValidations)
	{
		if (!Db.Validations.CausesValidation)
		{
			Db.Validations.CausesValidation = true;
			return true;
		}
		
		doValidations = (typeof(doValidations) == "undefined") ? true : doValidations;
		var formValid = true;
		var validator, valid;
		for (i in this._validations[form])
		{
			validator = this._validations[form][i];
			valid = doValidations ? validator.validate(false) : validator.isValid();
			if (!valid)
			{
				formValid = false;
			}
		}
		if (formValid && !doValidations)
		{
			var trackHd = Dom.get('hdButtonTracker_' + form);
			if (trackHd && trackHd.value != '')
			{
				var parts = trackHd.value.split('=');
				
				var hd = document.createElement('INPUT');
				hd.type = 'hidden';
				hd.name = parts[0];
				hd.value = parts[1];
				Dom.get(form).appendChild(hd);
			}
			Dom.get(form).submit();
			return false;
		}
		return formValid;
	},

	Validate: function (controlName, validation, message, params)
	{
		var control = Dom.get(controlName);
		
		if (!control)
		{
			return;
		}
		
		if (control.disableValidations)
		{
			return true;
		}
		
		//if it is a HTMLRichTextArea, save the HTML to the textarea
		if (control.HTMLRichTextArea_editor) control.HTMLRichTextArea_editor.saveHTML();
		
		params = params || {};
		params.id = controlName + '_' + validation;
		params.name = controlName;
		params.control = control;
		params.value = control.value;
		params.validation = validation;
		params.message = message;
		params.form = control.form.id;
		params.validator = Db.Validations._validations[control.form.id][params.id];
		var validateFunc = Db.Validations[validation];
		if (typeof validateFunc != 'function')
		{
			// TODO: error manager
			//console.log("No se encuentra la funcion para validar: " + validation);
		}
		if (!params.value && !params.required && validation != 'CompareValidate' && !params.validateOnEmpty)
		{
			return true;
		}
		try
		{
			var valid = validateFunc(params);
			//don't show the message for server-side custom validations
			if (validation != 'CustomValidate' || !params.serverCallback)
			{
				Db.Validations.ShowMessage(params, valid);
			}
			return valid;
		}
		catch (err)
		{
			// TODO: catch error
			//console.log(err);
		}
		return true;
	},
	
	ShowMessage: function(params, valid)
	{
		var htmlMessage = Dom.get('val_' + params.name + '_' + params.validation);
		htmlMessage.style.display = valid ? 'none' : 'inline';
		var tabHeader = Db.Validations.GetValidatorTab(params.control);
		if (params.control.validatorValid == undefined) params.control.validatorValid = true;
		var validStateChanged = params.control.validatorValid != valid;
		params.control.validatorValid = valid;
		if (!valid)
		{
			htmlMessage.innerHTML = this._ParseMessage(params.message, params);
			//update tab label if it exists and valid state changed
			if (tabHeader && validStateChanged)
			{
				if (tabHeader.errors == undefined) tabHeader.errors = 1;
				else tabHeader.errors++;
				
				if (tabHeader.errors == 1)
				{
					tabHeader.innerHTML += Db.Validations.TabErrorAppend;
				}
			}
		}
		else
		{
			//update tab label if it exists and valid state changed
			if (tabHeader && validStateChanged)
			{
				if (tabHeader.errors != undefined && tabHeader.errors > 0)
				{
					tabHeader.errors--;
					
					if (tabHeader.errors == 0)
					{
						var tabError = Dom.getElementsByClassName('tabError', 'span', tabHeader);
						if (tabError.length > 0)
						{
							tabHeader.removeChild(tabError[0]);
						}
					}
				}
			}
		}
	},

	TabErrorAppend: '<span class="tabError" style="color:red;"> *</span>',
	
	GetValidatorTab: function(control)
	{
		var tab = Dom.getAncestorByClassName(control, 'tab-content');
		if (tab)
		{
			if (tab.tabViewIndex == undefined)
			{
				var parent = tab.parentNode;
				for (var i = 0, j = 0, len = parent.childNodes.length; i < len; i++)
				{
					if (parent.childNodes[i] == tab)
					{
						tab.tabViewIndex = j;
						break;
					}
					if (parent.childNodes[i].nodeType == 1) j++;
				}
			}
			var tabHeaders = Dom.getChildrenBy(Dom.getPreviousSibling(tab.parentNode), function(e) { return e.tagName.toLowerCase() == 'li'; });
			return tabHeaders[tab.tabViewIndex].childNodes[0].childNodes[0];
		}
		
		return null;
	},
	
	_ParseMessage: function(message, params)
	{
		for (var param in params)
		{
			message = message.replace("%%" + param + "%%", params[param]);
		}
		return message;
	},
	
	RequiredFieldValidate: function(params)
	{
		return YAHOO.lang.trim(params.value) != '';
	},
	
	NumericValidate: function(params)
	{
		var value = params.value;
		switch (params.type)
		{
			case 'int':
				value = value.replace(/\./, 'dummy');
				return !isNaN(value);
			case 'float':
				value = parseFloat(value);
				return !isNaN(value);
			case 'positive':
				return parseFloat(value) == value && value >= 0;
			case 'negative':
				return parseFloat(value) == value && value <= 0;
			case 'positive_not_0':
				return parseFloat(value) == value && value > 0;
			case 'negative_not_0':
				return parseFloat(value) == value && value < 0;
		}
		return true;
	},
	
	RangeValidate: function(params)
	{
		var value = params.value;
		if (isNaN(value))
		{
			return false;
		}
		return (value >= params.min && value <= params.max);
	},
	
	RegularExpressionValidate: function(params)
	{
		var re = new RegExp(params.regexp, 'i');
		return re.test(params.value); 
	},
	
	CompareValidate: function(params)
	{
		params.compare_value = Dom.get(params.compare).value
		var comparation = "params.value " + params.compare_type;
		comparation += "params.compare_value ";
		return eval(comparation);
	},
	
	CustomValidate: function(params)
	{
		if (params.serverCallback)
		{
			var url = window.location.href;
			var callback =
			{
				success: function(o) {
					var received = YAHOO.lang.JSON.parse(o.responseText);
					//console.log(received);
					// TODO: gestionar el error que recibe
					Db.Validations.ShowMessage(params, received.valid);
					validator = Db.Validations._validations[params.form][params.id];
					validator.setValid(received.valid);
					validator.setValidating(false);
					
					//don't submit the form on blur event
					if (!params.validator.getBlurInitiated())
					{
						Db.Validations.Submit(params.form, false);
					}
				},
				// TODO: gestionar el error
				failure: function(o) {/*console.log("failure", o);*/},
				argument: [params]
			}
			YAHOO.util.Connect.asyncRequest('POST', url, callback, Db.util.objectToUrl(params));
			return null;
		}
		else
		{
			//dark magic
			return new Function('param', params.callback)(params.value);
		}
	}
}
