﻿jQuery.fn.uniform = function (extended_settings) {
    var self = this;
    var settings = jQuery.extend(
        jQuery.fn.uniform.defaults,
        extended_settings
    );

    var i18n_strings = jQuery.fn.uniform.language;

    this.validators = {

        get_val: function (name, classes, default_value) {
            var value = default_value;
            classes = classes.split(' ');
            for (var i = 0; i < classes.length; i++) {
                if (classes[i] == name) {
                    if ((classes[i + 1] != 'undefined') && ('val-' === classes[i + 1].substr(0, 4))) {
                        value = parseInt(classes[i + 1].substr(4), 10);
                        return value;
                    }
                }
            }
            return value;
        },

        required: function (field, caption) {
            if (field.is(':radio')) {
                var name = field.attr('name');
                if ($("input[name=" + name + "]:checked").length) {
                    return true;
                }
                return i18n('req_radio', caption);
            }
            if (field.is(':checkbox')) {
                var name = field.attr('name');
                if (field.is(":checked")) {
                    return true;
                }
                return i18n('req_checkbox', caption);
            }
            if (jQuery.trim(field.val()).replace(/\s/g, "") == "") {
                return i18n('required', caption);
            }
            return true;
        },

        validateMinLength: function (field, caption) {
            var min_length = this.get_val('validateMinLength', field.attr('class'), 0);

            if ((min_length > 0) && (field.val().length < min_length)) {
                return i18n('minlength', caption, min_length);
            }
            return true;
        },

        validateMin: function (field, caption) {
            var min_val = this.get_val('validateMin', field.attr('class'), 0);

            if ((parseInt(field.val(), 10) < min_val)) {
                return i18n('min', caption, min_val);
            }
            return true;
        },

        validateMaxLength: function (field, caption) {
            var max_length = this.get_val('validateMaxLength', field.attr('class'), 0);

            if ((max_length > 0) && (field.val().length > max_length)) {
                return i18n('maxlength', caption, max_length);
            }
            return true;
        },

        validateMax: function (field, caption) {
            var max_val = this.get_val('validateMax', field.attr('class'), 0);

            if ((parseInt(field.val(), 10) > max_val)) {
                return i18n('max', caption, max_val);
            }
            return true;
        },

        validateSameAs: function (field, caption) {
            var classes = field.attr('class').split(' ');
            var target_field_name = '';

            for (var i = 0; i < classes.length; i++) {
                if (classes[i] == 'validateSameAs') {
                    if (classes[i + 1] != 'undefined') {
                        target_field_name = classes[i + 1];
                        break;
                    }
                }
            }

            if (target_field_name) {
                var target_field = jQuery('input[name="' + target_field_name + '"]');
                if (target_field.length > 0) {
                    if (target_field.val() != field.val()) {
                        var target_field_caption = target_field.closest('div.' + settings.holder_class).find('label').text().replace('*', '');
                        return i18n('same_as', caption, target_field_caption);
                    }
                }
            }

            return true;
        },

        validateEmail: function (field, caption) {
            if (field.val().match(/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/)) {
                return true;
            } else {
                return i18n('email', caption);
            }
        },

        validateUrl: function (field, caption) {
            if (field.val().match(/^(http|https|ftp):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(:(\d+))?\/?/i)) {
                return true;
            }
            return i18n('url', caption);
        },

        validateNumber: function (field, caption) {
            if (field.val().match(/(^-?\d\d*\.\d*$)|(^-?\d\d*$)|(^-?\.\d\d*$)/) || field.val() == '') {
                return true;
            }
            return i18n('number', caption);
        },

        validateInteger: function (field, caption) {
            if (field.val().match(/(^-?\d\d*$)/) || field.val() == '') {
                return true;
            }
            return i18n('integer', caption);
        },

        validateAlpha: function (field, caption) {
            if (field.val().match(/^[a-zA-Z]+$/)) {
                return true;
            }
            return i18n('alpha', caption);
        },

        validateAlphaNum: function (field, caption) {
            if (field.val().match(/^[a-zA-Z0-9_@/.]*$/)) {
                return true;
            }
            return i18n('alphanum', caption);
        },

        validatePhrase: function (field, caption) {
            if ((field.val() == '') || field.val().match(/^[\w\d\.\-_\(\)\*'# :,]+$/i)) {
                return true;
            }
            return i18n('phrase', caption);
        },

        validatePhone: function (field, caption) {
            phoneNumber = /^\(?(\d{3})\)?[- ]?(\d{3})[- ]?(\d{4})$/;
            if (phoneNumber.test(field.val())) {
                return true;
            }
            return i18n('phone', caption);
        },

        validateDate: function (field, caption) {
            if (field.val().match('(1[0-9]|[1-9])/([1-3][0-9]|[1-9])/((19|20)[0-9][0-9]|[0-9][0-9])')) {
                return true;
            }
            return i18n('date', caption);
        },

        validateCallback: function (field, caption) {
            var classes = field.attr('class').split(' ');
            var callback_function = '';

            for (var i = 0; i < classes.length; i++) {
                if (classes[i] == 'validateCallback') {
                    if (classes[i + 1] != 'undefined') {
                        callback_function = classes[i + 1];
                        break;
                    }
                }
            }

            if (window[callback_function] != 'undefined' && (typeof window[callback_function] == 'function')) {
                return window[callback_function](field, caption);
            }

            return i18n('callback', caption, callback_function);
        }

    };

    var i18n = function (lang_key) {
        var lang_string = i18n_strings[lang_key];
        var bits = lang_string.split('%');
        var out = bits[0];
        var re = /^([ds])(.*)$/;
        for (var i = 1; i < bits.length; i++) {
            p = re.exec(bits[i]);
            if (!p || arguments[i] == null) continue;
            if (p[1] == 'd') {
                out += parseInt(arguments[i], 10);
            } else if (p[1] == 's') {
                out += arguments[i];
            }
            out += p[2];
        }
        return out;
    };

    var showFormError = function (form, title, messages) {
        if ($('#errorMsg').length) {
            $('#errorMsg').remove();
        }
        $message =
          $('<div />')
              .attr('id', 'errorMsg')
              .html("<h3>" + title + "</h3>");
        if (messages.length) {
            $message.append($('<ol />'));
            for (m in messages) {
                $('ol', $message).append(
                  $('<li />').text(messages[m])
              );
            }
        }
        form.prepend($message);
        $('html, body').animate({
            scrollTop: form.offset().top
        }, 500);
        $('#errorMsg').slideDown();
        return false;
    };

    var showFormSuccess = function (form, title) {
        if ($('#okMsg').length) {
            $('#okMsg').remove();
        }
        $message =
          $('<div />')
              .attr('id', 'okMsg')
              .html("<h3>" + title + "</h3>");
        form.prepend($message);
        $('html, body').animate({
            scrollTop: form.offset().top
        }, 500);
        $('#okMsg').slideDown();
        return false;
    };

    return this.each(function () {
        var form = jQuery(this);

        var validate = function ($input, valid, text) {
            var $p = $input.closest('div.' + settings.holder_class)
                           .andSelf()
                           .toggleClass(settings.invalid_class, !valid)
                           .toggleClass(settings.error_class, !valid)
                           .toggleClass(settings.valid_class, valid)
                           .find('p.formHint');

            if (!valid && !$p.data('info-text')) {
                $p.data('info-text', $p.html());
            }
            else if (valid) {
                text = $p.data('info-text');
            }

            if (text) {
                $p.html(text);
            }
        };

        form.find(settings.field_selector).each(function () {
            var $input = $(this),
                value = $input.val();

            $input.data('default-color', $input.css('color'));

            if (value === $input.data('default-value') || !value) {
                $input.not('select').css("color", settings.default_value_color);
                $input.val($input.data('default-value'));
            }
        });

        if (settings.ask_on_leave || form.hasClass('askOnLeave')) {
            var initial_values = form.serialize();
            $(window).bind("beforeunload", function (e) {
                if ((initial_values != form.serialize())
                    && (settings.ask_on_leave || form.hasClass('askOnLeave'))
                ) {
                    return ($.isFunction(settings.on_leave_callback))
                        ? settings.on_leave_callback(form)
                        : confirm(i18n('on_leave'));
                }
            });
        }

        form.submit(function () {
            form.removeClass('failedSubmit');

            form.find(settings.field_selector).each(function () {
                if ($(this).val() === $(this).data('default-value')) { $(this).val(""); }
            });

            if (settings.prevent_submit || form.hasClass('preventSubmit')) {
                form.find(settings.field_selector).each(function () {
                    $(this).blur();
                });

                if (form
                    .find('.' + settings.invalid_class)
                    .add('.' + settings.error_class).length
              ) {
                    form.addClass('failedSubmit');
                    return ($.isFunction(settings.prevent_submit_callback))
                    ? settings.prevent_submit_callback(form)
                    : showFormError(form, i18n('submit_msg'), [i18n('submit_help')]);
                }

                settings.ask_on_leave = false;
                form.removeClass('askOnLeave');
                return true;
            }

            if (form.parents('#qunit-fixture').length) {
                return false;
            }

            settings.ask_on_leave = false;
            form.removeClass('askOnLeave');
            return true;
        });

        form.delegate(settings.field_selector, 'focus', function () {
            form.find('.' + settings.focused_class).removeClass(settings.focused_class);

            var $input = $(this);

            $input.parents().filter('.' + settings.holder_class + ':first').addClass(settings.focused_class);

            if ($input.val() === $input.data('default-value')) {
                $input.val("");
            }

            $input.not('select').css('color', $input.data('default-color'));
        });

        form.delegate(settings.field_selector, 'blur', function () {
            var $input = $(this);
            var label = $(this)
                .closest('div.' + settings.holder_class)
                .find('label').text().replace('*', '');

            form.find('.' + settings.focused_class).removeClass(settings.focused_class);

            if (($input.val() === "" || $input.val() === $input.data('default-value'))
                && !$input.hasClass('required')
            ) {
                $input.not('select').css("color", settings.default_value_color);
                $input.val($input.data('default-value'));
                return;
            }

            var has_validation = false;
            for (validator in self.validators) {
                if ($input.hasClass(validator)) {
                    has_validation = true;
                    var validation_result = self.validators[validator]($input, label);
                    if (typeof (validation_result) == 'string') {
                        $input.trigger('error', validation_result);
                        return;
                    }
                }
            }

            if (has_validation) {
                $input.trigger('success');
            }

            $input.css('color', $input.data('default-color'));
            return;
        });

        form.delegate(settings.field_selector, 'error', function (e, text) {
            validate($(this), false, text);
        });

        form.delegate(settings.field_selector, 'success', function (e, text) {
            validate($(this), true);
        });
    });
};

jQuery.fn.uniform.language = {
    required      : '%s é obrigatório',
    req_radio     : 'Por favor escolha ao menos 1 item',
    req_checkbox  : 'Você deve marcar esta caixa para prosseguir',
    minlength     : '%s deve ter ao menos %d caracteres',
    min           : '%s deve ser maior ou igual a %d',
    maxlength     : '%s deve ter menos do que %d caracteres',
    max           : '%s deve ser menor ou igual a %d',
    same_as       : '%s deve ser o mesmo do que %s',
    email         : '%s não é um e-mail válido',
    url           : '%s não é uma URL válida',
    number        : '%s deve ser um número',
    integer       : '%s deve ser um número inteiro',
    alpha         : '%s deve conter apenas letras (sem caracteres especiais ou números)',
    alphanum      : '%s deve conter apenas caracteres válidos em um endereço de email',
    phrase        : '%s deve conter apenas letras, números, espaços e os seguintes caracteres: . , - _ () * # :',
    phone         : '%s deve ser um número de telefone',
    date          : '%s deve ser uma data (dd/mm/yyyy)',
    callback      : 'Falha ao validar o campo %s. A funcão de validação (%s) não foi definida!',
    on_leave      : 'Tem certeza de que deseja sair da página sem salvar seu formulário?',
    submit_msg    : 'Ooops, este formulário apresenta alguns erros.',
    submit_help   : 'Corrija os itens marcados abaixo.',
    submit_success: 'Obrigado, seu formulário foi enviado com sucesso.'
};

jQuery.fn.uniform.defaults = {
    prevent_submit          : false,
    prevent_submit_callback : false,
    ask_on_leave            : false,
    on_leave_callback       : false,
    valid_class             : 'valid',
    invalid_class           : 'invalid',
    error_class             : 'error',
    focused_class           : 'focused',
    holder_class            : 'ctrlHolder',
    field_selector          : 'input, textarea, select',
    default_value_color     : "#AFAFAF"
};

