window['App'] = window.App || {};
App.Forms = {

	FormList : {},
	
	/**
	 * Valide les règles associées à un champ
	 * @param DOMElement Input, Select ou Textarea. Les autres sont ignorés
	 * @param Event event Optionel. A utiliser pour définir si le champ doit être controlé. 
	 * @return boolean True si toutes les règles sont validées
	 */
	checkFieldValidity: function(field, event) {
		
		// Si le champ est envoyé par un évènement
		event = event || (field['target']) ? field : null;
		field = field['target'] || field;
		
		// On n'applique que sur les champs d'entrées
		if (field.nodeName !== 'INPUT'  &&
			field.nodeName !== 'SELECT' &&
			field.nodeName !== 'TEXTAREA') return true;
		
		// On recherche le nom du formulaire de validation
		var jField = jQuery(field),
			jSubForm = jField.parents('fieldset.jqSubForm').get(0);
		
		var form = jSubForm || field.form,
			formName = form['id'] ? form.id.replace(/:.*$/, '') : 'form',
			isMultiValue = (/\[\]$/.exec(field.name) !== null),
			fieldName = jSubForm ? String(field.name).replace(/^.*\[([^\]]+)\]$/, '$1') : String(field.name).replace(/\[\]$/, '');
		
		// Aucun control disponible pour le formulaire, le champ est valide
		if (!App.Forms.FormList[formName]) return true;
		var ruleset = App.Forms.FormList[formName][fieldName];
		// Pas de validateur ? Le champ est valide
		if (!ruleset) return true;
		ruleset.options = ruleset['options'] || {};
		
		// si le controle est fait par un évènement, on controle que l'on puisse bien le passer
		if (event && ruleset['checkOn']) {
			var doCheck = ruleset.checkOn[event.type] === undefined ? true : ruleset.checkOn[event.type];
			if (!doCheck) return;
		}
		
		// Cas spécifique pour FCKEditor, on synchronise le champ d'origine avant de lui appliquer les controles
		var isFCKEditor = jField.hasClass('jqFCKEditor')
		if (isFCKEditor) {
			var oEditor = FCKeditorAPI.GetInstance(field.id);
			//if (oEditor.ResetIsDirty())
			oEditor.UpdateLinkedField();
			var fckTextareaContent = field.value;
			// On dégage les balises pour les contrôles
			field.value = Utile.htmlEntitiesDecode(fckTextareaContent.replace(/(<\/?[\S][^>]*>)/gi, ""));
		}
		
		// Suppression de la valeur de tooltip si existante
		if (ruleset['tooltip'] && field.value == ruleset['tooltip']) {
			field.value = '';
		}
		
		// Validation des règles associées
		var i = 0;
		while (ruleset[i]) {
			var validatorName = ruleset[i].name,
				validatorReturn = App.Forms.Validator[validatorName](field, ruleset[i].parameters);
			if (validatorReturn !== true) {
				if (isFCKEditor) field.value = fckTextareaContent;
				return App.Forms.displayFieldStatus(field, false, validatorReturn, ruleset, i);
			}
			i++;
		}
		
		// Si toutes les règles sont validées
		if (isFCKEditor) field.value = fckTextareaContent;
		return App.Forms.displayFieldStatus(field, true, null, ruleset);
	},
	
	/**
	 * Valide un formulaire
	 * @param DOMElement form Le noeud formulaire a valider
	 */
	checkFormValidity: function(form) {
		
		var event = (form['target']) ? form : null;
		
		// Si le formulaire est envoyé par un évènement
		form = form['target'] || form;
		if (form.nodeName != 'FORM') return;
		
		var formName = form['id'] ? form.id : 'form',
			formValidity  = true,
			fieldValidity = false,
			validatedFields = {}; // Contient la liste des champs déjà validés (les noms de champs)
		
		// Aucun control disponible pour le formulaire, il est valide
		if (!App.Forms.FormList[formName]) return true;
		
		var fieldToFocus = null;
		for (var i = 0; i < form.elements.length; i++) {
			var field = form.elements[i];
			// Nom de champs déjà validé ? On passe au suivant
			if (validatedFields[field.name]) continue;
			
			fieldValidity  = App.Forms.checkFieldValidity(form.elements[i], event);
			formValidity  &= fieldValidity;
			if (!fieldToFocus && !fieldValidity)
				fieldToFocus = field;
			validatedFields[field.name] = true;
		}
		
		if (event && !formValidity)
			event.stopPropagation();
		
		if (!formValidity) {
			if (fieldToFocus) fieldToFocus.focus();
			if(jQuery['scrollTo'])
				jQuery['scrollTo'](fieldToFocus, 250)
			else
				window.scrollTo(0, 200);
		}
		
		return formValidity ? true : false; // On s'assure qu'on renvoi bien un booleen
	},
	
	/**
	 * Vide le status d'erreur du champ
	 */
	clearFieldStatus: function(field) {
		var fieldName = String(field.name).replace('[]', ''),
			errorDiv = document.getElementById('errors_'+fieldName);
		if (errorDiv) jQuery(errorDiv).html('').removeClass('isValid').removeClass('isInvalid');
	},
	
	/**
	 * Affiche le status d'un champ
	 * @param DOMElement field Le champs pour lequel on affiche le status
	 * @param boolean isValid True si le champ est valide
	 * @param string message Le massage a afficher
	 * @param object rulset Le jeu de controle du champ
	 * @param int rulesetIndex L'index dans le jeu de controle a utiliser pour le parsing du message d'erreur
	 * @return boolean Renvoi isValid
	 */
	displayFieldStatus: function(field, isValid, message, ruleset, rulesetIndex) {
		if (!ruleset) ruleset = {};
		ruleset.message = ruleset['message'] || {};
		if (ruleset['canDisplayValidMessage'] === undefined)
			ruleset['canDisplayValidMessage'] || true;
		
		var form = field.form,
			formName = form['name'] ? form.name : 'form',
			isMultiValue = field.name.match(/\[\]$/),
			fieldName = String(field.name).replace('[]', ''),
			jField = jQuery(field),
			errorDiv = document.getElementById('errors_'+fieldName),
			showValidMessage = ruleset.message['showValidMessage'] === undefined ? true : ruleset.message['showValidMessage'];
		
		if (!errorDiv) {
			errorDiv = document.createElement('DIV');
			errorDiv.className = "errors";
			errorDiv.id = "errors_" + fieldName;
			jField.after(errorDiv);
		}
		
		if ((!isValid) || (showValidMessage && isValid)) {
			errorDiv.style.display = '';
			var jErrorDiv = jQuery(errorDiv);
			// Pour faciliter l'intégration
			if (isValid) {
				jErrorDiv.removeClass('isInvalid').addClass('isValid');
				jField.removeClass('isInvalid').addClass('isValid');
			}
			else {
				jErrorDiv.removeClass('isValid').addClass('isInvalid');
				jField.removeClass('isValid').addClass('isInvalid');
			}
		}
		else {
			errorDiv.style.display = 'none';
		}
		try {
			message = message ? ruleset.message[message] || translator[message] || message : null;
		} catch (e) {}
		
		// Parse du message
		if (rulesetIndex !== undefined && ruleset[rulesetIndex] && ruleset[rulesetIndex]['parameters']) {
			var parameters = ruleset[rulesetIndex]['parameters'];
			for (var i in parameters) message = message.replace('%'+i+'%', parameters[i]);
		}
		
		// On affiche ou pas la validité du message
		if (isValid && !ruleset.canDisplayValidMessage) {
			errorDiv.innerHTML = '';
			return isValid;
		}
		
		errorDiv.innerHTML = (!isValid && message) ? message : '<img src="images/valid.gif" alt="'+App.trad("Champs valide")+'" border="0">';
		
		return isValid;
	},
	
	Validator : {
		Zend_Validate_NotEmpty: function(element, parameters) {
			if (element.type == 'checkbox' || element.type == 'radio')
				return	(jQuery("input:checked[type="+element.type+"][name='"+element.name+"']").length > 0) ? true : 'notChecked';
			else
				return 	(element.value.replace("\r", "").replace("\n", " ").match(/^\s*$/) === null)	? true : 'isEmpty';
		},
		
		Zend_Validate_Alnum: function(element, parameters)	{
			var value = element.value;
			if (parameters.allowWhiteSpace && value.match(/^[a-z0-9\s]*$/i) !== null)
				return true;
			if (value.match(/^[a-z0-9\s]*$/i) !== null)
				return true;
			return 'notAlnum';
		},
		
		Zend_Validate_Float: function(element, parameters)	{
			var value = String(element.value);
			value = jQuery.trim(value.replace(',', '.')); // Petit hack pour être sur de toujours avoir un flottant avec point
			element.value = value;
			if (value == '') return true;
			if (value.match(/^[-+]?\d+(?:[\.]\d+)?$/) === null) return 'notFloat';
			if (parseFloat(value) !== NaN) return true;
			return 'notFloat';
		},
		
		Zend_Validate_Int: function(element, parameters)	{
			var value = String(element.value);
			if (value == '') return true;
			if (value.match(/^[-+]?\d+$/) === null) return 'notInt';
			if (parseInt(value) !== NaN) return true;
			return 'notInt';
		},
		
		ZendX_Validate_IntOrEmpty: function(element, parameters)	{
			if (App.Forms.Validator.Zend_Validate_NotEmpty(element, parameters) === true)
				return App.Forms.Validator.Zend_Validate_Int(element, parameters);
			return true;
		},
		
		Zend_Validate_Between: function(element, parameters) {
			if (element.value == '') return true;
			var value = parseFloat(element.value);
			if (value === NaN) return 'notBetween';
			if (value >= parameters.min && value <= parameters.max) return true; 
			return 'notBetween';
		},
		
		Zend_Validate_InArray: function(element, parameters) {
			if (typeof(parameters.haystack) == 'string') {
				parameters.haystack = String(parameters.haystack).split(";");
			}
			if (parameters.haystack instanceof Array) {
				/* IE */
				if (!parameters.haystack.indexOf) {
					for (var i = 0; i < parameters.haystack.length; i++) {
						if (parameters.haystack[i]==element.value || parameters.haystack[i]==parseInt(element.value))
							return(true);
					}
				/* Firefox */
				} else if (parameters.haystack.indexOf(element.value) >= 0 || parameters.haystack.indexOf(parseInt(element.value)) >= 0)
					return true;
			} else if (parameters.haystack instanceof Object) {
				if (parameters.haystack[element.value] || false)
					return true;
			}
			return 'notInArray';
		},
		
		ZendX_Validate_InArrayOrEmpty: function(element, parameters) {
			if (App.Forms.Validator.Zend_Validate_NotEmpty(element, parameters) === true)
				return App.Forms.Validator.Zend_Validate_InArray(element, parameters);
			return true;
		},
		
		Zend_Validate_Digits: function(element, parameters)	{
			if (element.value.match(/^[0-9\s]*$/i) !== null)
				return true;
			return 'notDigits';
		},
		
		Zend_Validate_StringLength: function(element, parameters) {
			if (element.value.length > parameters.max)
				return 'stringLengthTooLong';
			if (element.value.length < parameters.min)
				return 'stringLengthTooShort';
			return true;
		},
		
		Zend_Validate_EmailAddress: function(element, parameters) {
			var value 	= element.value;
			
			if (value.match(/^((.+)@([^@]+))?$/i) === null)
				return 'emailAddressInvalid';
			
			var ajaxResponse = jQuery.ajax({
				type: "POST",
				url: App.CUB.urlAjax,
				data: ({
					name:   element.name.replace('[]', ''),
					value:  value,
					numero_form:  App.CUB.numero_form,
					fromJs: 1
				}),
				async: false,
				cache: false
			});
			
			var headers = ajaxResponse['responseHeaders'] || Utile.parseHTTPHeaders(ajaxResponse.getAllResponseHeaders());
			if (headers['X-Cub-Field-Validity'] == 'VALID')
				return true;
			
			var response = ajaxResponse.responseText;
			
			if (parseInt(response) === 0)
				return 'notUniqueEmail';
			else
				return App.Forms.parseMessage(translator['emailAddressInvalidHostname'], value, {
					hostname: value.replace(/^[^@]+@/, '')
				});
		},
		
		Zend_Validate_Regex: function(element, parameters) {
			var regexp = typeof(parameters.pattern) == "string" ? eval(parameters.pattern) : parameters.pattern;
			if (element.value == '' || element.value.match(regexp) !== null)
				return true;
			return 'regexNotMatch';
		},	
		
		Zend_Validate_Identical: function(element, parameters) {
			if (element.value == document.getElementById(parameters.token).value)
				return true;
			return 'notSame';
		},	
		
		ZendX_Validate_String: function(element, parameters) {
			return App.Forms.Validator.Zend_Validate_Regex(element, {pattern: /^[a-zA-Z0-9!&ÀÁÂÃÄÅàáâãäåÒÓÔÕÖØòóôõöøÈÉÊËèéêëÇçÌÍÎÏìíîïÙÚÛÜùúûüÿÑñ \-\/',\._#]+$/i});
		},	
		
		ZendX_Validate_Phone: function(element, parameters) {
			return App.Forms.Validator.Zend_Validate_Regex(element, {pattern: /^(?:\(\+?\d{2,3}\)|\+)?[- \d]{6,14}$/});
		},
		
		ZendX_Validate_Date: function(element, parameters) {
			return true;
		}
	},
	
	parseMessage: function(message, value, parameters) {
		message = message.replace('%value%', value);
		for (prop in parameters)
			message = message.replace('%'+prop+'%', parameters[prop]);
		return message;
	},
	
	applyTooltips: function(form) {
		
		if (form.nodeName != 'FORM') return;
		
		var formName = form['id'] ? form.id : 'form'; // Contient la liste des champs déjà validés (les noms de champs)
		
		// Aucun control disponible pour le formulaire, il est valide
		if (!App.Forms.FormList[formName]) return true;
		
		for (var i = 0; i < form.elements.length; i++) {
			var field = form.elements[i],
				fieldName = field.name || '';

			if (!field.id) field.id = Utile.randomUID();
			
			var ruleset = App.Forms.FormList[formName][fieldName];
			if (!ruleset) continue;
			if (ruleset['tooltip']) {
				jQuery(field).emptyonclick({
					defaultValue: ruleset['tooltip'],
					defaultClass: 'defaultValue'
				});
			}
		}
	}
}

jQuery.behaviors.register(function(node) {
	// Pas de formulaire ? Pas la peine de continuer
	var jForm = jQuery("form", node);
	if (!jForm.length) return;
	
	jQuery(":input", jForm).change(App.Forms.checkFieldValidity);
	jQuery(".inputText", jForm).blur(App.Forms.checkFieldValidity);
	jForm.each(function() {
		App.Forms.applyTooltips(this);
	});
	jForm.submit(App.Forms.checkFormValidity);
	
});
