/**
 * form-validation.js
 *
 * validation javascript des formulaires + tooltip à côté des inputs
 * @author collomb
 * @version 1.0
 */

var EMAIL_ERROR_MSG = "Veuillez saisir une adresse mail au format nom@domaine.com";
var URL_ERROR_MSG = "Veuillez saisir une adresse au format http://www.domaine.com";
var STRING_ERROR_MSG = "%d caractères minimum";
var PASSWORD_ERROR_MSG = "%d caractères minimum";
var PASSWORD_MIN_LENGTH = 6;
var FLOAT_ERROR_MSG = "Veuillez saisir un nombre réel";
var INT_ERROR_MSG = "Veuillez saisir un nombre entier";
var SIREN_ERROR_MSG = "Veuillez saisir un numéro SIREN valide";
var CITY_ERROR_MSG = "La commune spécifiée est inconnue. Veuillez en sélectionner une dans la liste proposée";
var PASSWORD_CONFIRM_ERROR_MSG = "Les mots de passe ne correspondent pas";

var DATE_ERROR_MSG = "Veuillez saisir une date au format %s";
var DATE_FORMAT_STR = "jj/mm/aaaa";
var DATE_DDMM_FORMAT_STR = "jj/mm";
var DATE_MMYYYY_FORMAT_STR = "mm/aaaa";
var DATE_YYYY_FORMAT_STR = "aaaa";
var DATE_DAY_ERROR_MSG = "Jour non valide";
var DATE_MONTH_ERROR_MSG = "Mois non valide";
var DATE_YEAR_ERROR_MSG = "Année de 1900 à 2100";

var TIME_HHMM_FORMAT_STR = "hh:mm";
var TIME_ERROR_MSG = "Veuillez saisir une date au format %s";
var TIME_HOUR_ERROR_MSG = "Heure non valide";
var TIME_MINUTE_ERROR_MSG = "Minute non valide";

$.fn.inputTooltip = function(options) {
    $.fn.inputTooltip.div = null;

    var defaults = {
        bgColor: "#E2E2FF",
		txtColor: "#444444",
        width: "21em"
    };
    options = $.extend(defaults, options);

    this.each(function() {
		var $tooltip = $("#" + this.id + "_tooltip");
		var $this = $(this);
        if ($tooltip.length == 1)
            $this.focus(function(){
                if (! $.fn.inputTooltip.div)
                {
                    $(document.body).append('<div id="_inputTooltip_" style="display:none;position:absolute;z-index:99;">'+
                        '<div style="position:absolute;top:5px;right:0;width:0;' +
                            'height:0;' +
                            'border-top: 7px solid transparent; _border-top-color: white;' +
                            'border-bottom: 7px solid transparent; _border-bottom-color: white;' +
                            'border-right: 14px solid ' + options.bgColor + ';' +
                            'border-left: 0 solid ' + options.bgColor + ';"><!-- --></div>' +
                        '<div id="_inputTooltipContent_" ' +
							'style="margin-right:14px;width:' + options.width + '; background-color:' + options.bgColor + '; color:' + options.txtColor + '; padding:0.5em; font-size: 11px;"></div>'+
                        '</div>');
                    $.fn.inputTooltip.div = $("#_inputTooltip_");
                    $.fn.inputTooltip.contentDiv = $("#_inputTooltipContent_");
                }
                $.fn.inputTooltip.contentDiv.html($tooltip.html());
				if ($tooltip.hasClass("tooltip_left")) {
					$("div:eq(0)", $.fn.inputTooltip.div).css({"right": "0", "left": "", "border-right-width": "0", "border-left-width": "14px"});
					$("div:eq(1)", $.fn.inputTooltip.div).css({"margin-right": "14px", "margin-left": "0"});
					$.fn.inputTooltip.div.css({top:$this.offset().top, left:$this.offset().left - $.fn.inputTooltip.div.outerWidth()}).show();
				} else {
					$("div:eq(0)", $.fn.inputTooltip.div).css({"left": "0", "right": "", "border-right-width": "14px", "border-left-width": "0"});
					$("div:eq(1)", $.fn.inputTooltip.div).css({"margin-right": "0", "margin-left": "14px"});
					$.fn.inputTooltip.div.css({top:$this.offset().top, left:$this.offset().left + $this.outerWidth()}).show();
				}
            }).blur(function(){
				if ($.fn.inputTooltip.div)
                {
					$.fn.inputTooltip.div.hide();
				}
            });
    });
};

$.fn.formValidation = function(options) {
	var defaults = {};

	options = $.extend(defaults, options);

	$.fn.formValidation.customValidation = new Array();

	/**
	 * Ajoute une fonction personnalisée de validation pour les cas complexes - ex : une date doit être supérieure à une autre
	 * @param <function> func la function de validation
	 */
	$.fn.formValidation.addCustomValidation = function(func) {
		$.fn.formValidation.customValidation.push(func);
	}

	/**
	 * Vérifie le format d"une date.
	 * @param <string> str     la date
	 * @param <string> format  le format de date utilisé pour les message de retour
	 * @return <bool|string> un message de retour si erreur. TRUE si la vérification du format est ok
	 */
	$.fn.formValidation.checkDate = function(str, format)
	{
		var parts = str.split("/")
		if (parts.length != 3) {
			return DATE_ERROR_MSG.replace("%s", format);
		}
		var d = parseInt(parts[0], 10);
		var m = parseInt(parts[1], 10);
		var y = parseInt(parts[2], 10);

		if (isNaN(m) || m < 1 || m > 12) {
			return DATE_MONTH_ERROR_MSG;
		}
		if (isNaN(y) || y < 1900 || y > 2100) {
			return DATE_YEAR_ERROR_MSG;
		}
		leap = function(year) {if (year % 400 == 0) return true;if (year %100 == 0) return false;return (year % 4 == 0);}
		var daysInMonth = [31, leap(y) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
		if (isNaN(d) || d < 1 || d > daysInMonth[m - 1]) return DATE_DAY_ERROR_MSG;
		return true;
	}

	/**
	 * Vérifie le format d"un temps.
	 * @param <string> str     le temps
	 * @param <string> format  le format de temps utilisé pour les message de retour
	 * @return <bool|string> un message de retour si erreur. TRUE si la vérification du format est ok
	 */
	$.fn.formValidation.checkTime = function(str, format)
	{
		var parts = str.split("h");
		if (parts.length != 2) {
			parts = str.split(":");
			if (parts.length != 2) {
				return TIME_ERROR_MSG.replace("%s", format);
			}
		}
		var h = parseInt(parts[0], 10);
		var m = 0;
		if (parts[1] != "") {
			m = parseInt(parts[1], 10);
		}

		if (isNaN(h) || h < 0 || h > 23) return TIME_HOUR_ERROR_MSG;
		if (isNaN(m) || m < 0 || m > 59) return TIME_MINUTE_ERROR_MSG;

		return true;
	}

	/**
	 * Vérifie le format d'un numéro SIREN
	 * @param <string> siren     le numéro siren
	 * @return <bool|string> un message de retour si erreur. TRUE si la vérification du format est ok
	 * algo de luhn. code original provenant de http://www.javascriptfr.com/code.aspx?ID=16330
	 */
	$.fn.formValidation.checkSiren = function(siren)
	{
		if ((siren.length == 9) || ! (isNaN(siren))) {
			var sum = 0;
			var tmp;
			for (var i = 0; i < 9; i++) {
				tmp = parseInt(siren.charAt(i)) * (i % 2 + 1);
				if (tmp > 9) tmp -= 9;
				sum += tmp;
			}
			if (sum % 10 == 0) {
				return true;
			}
		}
		return SIRE_ERROR_MSG;
	}

	/**
	 * Vérifie le format d'une URL
	 * @param <string> url     l'rl
	 * @return <bool|string> un message de retour si erreur. TRUE si la vérification du format est ok
	 */
	$.fn.formValidation.checkUrl = function(input)
	{
		if (input.value.match(/^https?:\/\/[^ ]+$/)) {
			return true;
		}
		if ((input.value == 'http://' || input.value == '') && $(input).hasClass("nullAllowed")) {
			return true;
		}
		return URL_ERROR_MSG;
	}

	/**
	 * Vérifie la validité d'une ville saisie
	 * @param <object> input    le champ de saisie de la ville
	 * @return <bool|string> un message de retour si erreur. TRUE si la vérification du format est ok
	 */
	$.fn.formValidation.checkCity = function(input)
	{
		if (! this.noValid) {
			if (input.data) {
				if (input.value.indexOf(input.data.value) < 0) {
					return CITY_ERROR_MSG
				}
			} else {
				if ($("#" + input.id + '_id').val() == '') {
					return CITY_ERROR_MSG;
				}
			}
		}
		return true;
	}

	$.fn.formValidation.validate = function(input, validationType, $output)
	{
		var valid = true;
		if (! $(input).hasClass("nullAllowed") && input.value == "") {
			valid = "Champ obligatoire"
		}
		else if (input.value != "") {
			switch (validationType) {
				case "validEmail" :if (! input.value.match(/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/)) valid = EMAIL_ERROR_MSG;break;
				case "validURL" :valid = this.checkUrl(input);break;
				case "validPassword" :if (input.value.length < PASSWORD_MIN_LENGTH) valid = PASSWORD_ERROR_MSG.replace('%d', PASSWORD_MIN_LENGTH);break;
				case "validDate" :valid = this.checkDate(input.value, DATE_FORMAT_STR);break;
				case "validDateDDMM" :valid = this.checkDate(input.value + "/2000", DATE_DDMM_FORMAT_STR);break;
				case "validDateMMYYYY" :valid = this.checkDate("01/" + input.value, DATE_MMYYYY_FORMAT_STR);break;
				case "validDateYYYY" :valid = this.checkDate("01/01/" + input.value, DATE_YYYY_FORMAT_STR);break;
				case "validTimeHHMM" :valid = this.checkTime(input.value, TIME_HHMM_FORMAT_STR);break;
				case "validFloat" :if (parseFloat(input.value) != input.value) valid = FLOAT_ERROR_MSG;break;
				case "validInteger" :if (parseInt(input.value, 10) != input.value) valid = INT_ERROR_MSG;break;
				case "validSiren" :valid = this.checkSiren(input.value);break;
				case "validSelect" :valid = input.value != '' && input.value != '-1';break;
				case "validCity" :valid = this.checkCity(input); break;
				case "validPasswordConfirmation" :if (input.value != $(".validPassword:first").val()) valid = PASSWORD_CONFIRM_ERROR_MSG;break;
			}
		}
		if (valid === true) {
			$("#label_" + input.id + ", #" + input.id).removeClass("validationError").addClass("validationSuccess");
			$("#" + input.id + '_tooltip').remove('.validationError');
			$("#" + input.id + '_tooltip .validationError').removeClass('validationError').empty();
		} else {
			var $lbl = $("#label_" + input.id);
			$lbl.add("#" + input.id).removeClass("validationSuccess").addClass("validationError");
			$("#" + input.id + '_tooltip .validationError').removeClass('validationError').empty();
			$("#" + input.id + '_tooltip').append('<span class="validationError"><br/>' + valid + '</span>');
			$output.append('<p>' + $lbl.text() + ' : ' + valid + '</p>')
		}
	}

	$.fn.formValidation.onInputChange = function()
	{
		$("#label_" + this.id + ", #" + this.id).removeClass("validationError");
	}

	this.submit(function(event) {
		if (event.noValidation) {
			return;
		}
		if ($("button[type=submit].disabled", $form).length > 0) {
			event.preventDefault();
			return;
		}
		var $form = $(this);
		var $output = $(".formValidationMessages", $form).empty();
		$(".validEmail", $form).each(function(){$.fn.formValidation.validate(this, "validEmail", $output);});
		$(".validURL", $form).each(function(){$.fn.formValidation.validate(this, "validURL", $output);});
		$(".validDate", $form).each(function(){$.fn.formValidation.validate(this, "validDate", $output);});
		$(".validString", $form).each(function(){$.fn.formValidation.validate(this, "validString", $output);});
		$(".validPassword", $form).each(function(){$.fn.formValidation.validate(this, "validPassword", $output);});
		$(".validDateDDMM", $form).each(function(){$.fn.formValidation.validate(this, "validDateDDMM", $output);});
		$(".validDateMMYYYY", $form).each(function(){$.fn.formValidation.validate(this, "validDateMMYYYY", $output);});
		$(".validDateYYYY", $form).each(function(){$.fn.formValidation.validate(this, "validDateYYYY", $output);});
		$(".validTimeHHMM", $form).each(function(){$.fn.formValidation.validate(this, "validTimeHHMM", $output);});
		$(".validFloat", $form).each(function(){$.fn.formValidation.validate(this, "validFloat", $output);});
		$(".validInteger", $form).each(function(){$.fn.formValidation.validate(this, "validInteger", $output);});
		$(".validSiren", $form).each(function(){$.fn.formValidation.validate(this, "validSiren", $output);});
		$(".validCity", $form).each(function(){$.fn.formValidation.validate(this, "validCity", $output);});
		$(".validPasswordConfirmation", $form).each(function(){$.fn.formValidation.validate(this, "validPasswordConfirmation", $output);});
		$("select.validSelect", $form).each(function(){$.fn.formValidation.validate(this, "validSelect", $output);});
		for (var i in $.fn.formValidation.customValidation) {
			$.fn.formValidation.customValidation[i]($form, "validationError", $output);
		}

		if ($(".validationError:visible", $form).length > 0 && $output.html() != '') {
			$(document).scrollTop($output.show().offset().top);
			event.preventDefault();
		} else {
			$("button[type=submit]", $form).addClass("disabled").html("Envoi en cours...");
			$output.hide();
		}
	});

	this.each(function(){
		$("input, textarea", this).inputTooltip({tooltipClass: "js_tooltip"});
		$(".validEmail, .validURL, .validDate, .validString, .validPassword, .validDateDDMM, .validDateMMYYYY, .validDateYYYY, .validFloat, .validInteger, .validSiren, .validPasswordConfirmation, " +
			".validCity, .validSelect",	this).change($.fn.formValidation.onInputChange);
		$(".validSelect", this).select($.fn.formValidation.onInputChange);
	});
}

$(document).ready(function(){
	$(".formValidation").formValidation({});
});
