﻿(function($) {
    $.fn.editvalidation = function(opciones) {

        validator = function(form, cultureInfo) {
            this.currentForm = form;
            this.cultureInfo = cultureInfo;
        };

        $.extend(validator, {
            prototype:
            {
                methods:
                {
                    required: function(value, element, param) {
                        switch (element.nodeName.toLowerCase()) {
                            case 'select':
                                var val = $(element).val();
                                return val && val.length > 0;
                            case 'input':
                                if (this.checkable(element))
                                    return this.getLength(value, element) > 0;
                            default:
                                return $.trim(value).length > 0;
                        };
                    },
                    minlength: function(value, element, param) {
                        return this.optional(element) || this.getLength($.trim(value), element) >= param;
                    },
                    maxlength: function(value, element, param) {
                        return this.optional(element) || this.getLength($.trim(value), element) <= param;
                    },
                    rangelength: function(value, element, param) {
                        var length = this.getLength($.trim(value), element);
                        return this.optional(element) || (length >= param.min && length <= param.max);
                    },
                    min: function(value, element, param) {
                        return this.optional(element) || this.numberToInvariantCulture(value) >= param;
                    },
                    max: function(value, element, param) {
                        return this.optional(element) || this.numberToInvariantCulture(value) <= param;
                    },
                    range: function(value, element, param) {
                        num = this.numberToInvariantCulture(value);
                        return this.optional(element) || (num >= param.min && num <= param.max);
                    },
                    email: function(value, element) {
                        return this.optional(element) || /^(((([a-zA-Z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-zA-Z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?[,|;]?)+$/.test(value);
                    },
                    url: function(value, element) {
                        return this.optional(element) || /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value);
                    },
                    date: function(value, element) {
                        switch (this.cultureInfo.dateElementOrder) {
                            case 'ymd':
                                return this.optional(element) || /^(19\d{2}|20\d{2}|\d{2})([\.,\/,-])([1-9]|0[1-9]|1[012])([\.,\/,-])([1-9]|0[1-9]|[12][0-9]|3[01])$/.test(value);
                            case 'mdy':
                                return this.optional(element) || /^([1-9]|0[1-9]|1[012])([\.,\/,-])([1-9]|0[1-9]|[12][0-9]|3[01])([\.,\/,-])(19\d{2}|20\d{2}|\d{2})$/.test(value);
                            default:  //dmy
                                return this.optional(element) || /^([1-9]|0[1-9]|[12][0-9]|3[01])([\.,\/,-])([1-9]|0[1-9]|1[012])([\.,\/,-])(19\d{2}|20\d{2}|\d{2})$/.test(value);
                        };
                    },
                    number: function(value, element) {
                        return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:[,|\.|''|\s]\d{3})+)(?:[,|\.]\d+)?$/.test(value);
                    },
                    integer: function(value, element) {
                        return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:[,|\.|''|\s]\d{3})+)$/.test(value);
                    },
                    digits: function(value, element) {
                        return this.optional(element) || /^\d+$/.test(value);
                    },
                    accept: function(value, element, param) {
                        var ext = param.replace(/,/g, '|');
                        return this.optional(element) || value.match(new RegExp(".(" + ext + ")$", "i"));
                    },
                    equalTo: function(value, element, param) {
                        return this.optional(element) || value == $(param).val();
                    },
                    alphanumeric: function(value, element) {
                        return this.optional(element) || /^\w+$/.test(value);
                    },
                    letters: function(value, element) {
                        return this.optional(element) || /^[a-zA-Z]+$/.test(value);
                    },
                    pattern: function(value, element, param) {
                        var regExPattern = new RegExp("^" + param + "$");
                        return this.optional(element) || regExPattern.test(value);
                    }

                },
                optional: function(element) {
                    return !this.methods.required.call(this, element.value, element);
                },
                checkable: function(element) {
                    return /radio|checkbox/i.test(element.type);
                },
                findByName: function(name) {
                    var form = this.currentForm;
                    return $(document.getElementsByName(name)).map(function(index, element) {
                        return element.form == form && element.name == name && element || null;
                    });
                },
                getLength: function(value, element) {
                    switch (element.nodeName.toLowerCase()) {
                        case 'select':
                            return $("option:selected", element).length;
                        case 'input':
                            if (this.checkable(element))
                                return this.findByName(element.name).filter(':checked').length;
                        case 'textarea':
                            return value.length + this.getNewlineCount(value);
                    }
                    return value.length;
                },
                getNewlineCount: function(content) {
                    var newlineCount = 0;
                    for (var i = 0; i < content.length; i++) {
                        if (content.charAt(i) == '\n') {
                            newlineCount++;
                        };
                    };
                    return newlineCount;
                },
                numberToInvariantCulture: function(num) {
                    if (num != undefined && this.cultureInfo.numberDecimalSeparator != '.') {
                        num = num.toString();
                        a = num.split(this.cultureInfo.numberDecimalSeparator);
                        x = a[0]; // parte entera
                        y = a[1]; // parte decimal
                        x = x.replace(this.cultureInfo.numberGroupSeparator, '');
                        if (y != undefined) {
                            return Number(x + '.' + y);
                        } else {
                            return Number(x);
                        }
                    }
                    return Number(num);
                }
            }
        });

        this.each(function() {

            var config = {
                confirmText: '',
                rules: {},
                cultureInfo: {
                    numberDecimalSeparator: ',', numberGroupSeparator: '.',
                    dateElementOrder: 'dmy', dateFormat: 'dd/mm/yy'
                },
                messages: {}
            };

            jQuery.extend(config, opciones);

            var errorList = [];
            fvalidator = new validator(this, config.cultureInfo);

            function reset() {
                errorList = [];
            };
            function addError(element, rule, param) {
                var label;
                if (config.rules[element].label != undefined) {
                    label = config.rules[element].label;
                } else {
                    label = element;
                };

                var message = config.messages[rule];
                theregex = /\$?\{(\d+)\}/g;
                if (theregex.test(message)) {
                    if (param != undefined) {
                        param = normalizeParamMsgError(rule, param);
                    }
                    message = format(message, param);
                }

                var title = config.rules[element].title;
                if (title != undefined) {
                    message += ". " + title;
                }

                errorList.push({
                    message: message,
                    element: element,
                    label: label
                });
            };
            function format(source, params) {
                for (var i in params) {
                    source = source.replace(new RegExp("\\{" + i + "\\}", "g"), params[i]);
                };
                return source;
            };
            function normalizeParamMsgError(rule, param) {
                switch (rule) {
                    case "rangelength", "range":
                        return [Number(param.min), Number(param.max)];
                    case "minlength", "maxlength", "min", "max":
                        return [Number(param)];
                    case "date":
                        return [config.cultureInfo.dateFormat];
                    case "pattern":
                        return [param];

                };
                return [param];
            };
            function valid() {
                return size() == 0;
            };
            function size() {
                return errorList.length;
            };
            function showErrors() {
                if (!valid()) {
                    var msg = config.messages['erroresdetectados'] + ':';
                    for (var indice in errorList) {
                        msg += "\n'" + errorList[indice].label + "' " + errorList[indice].message + ".";
                    }
                    alert(msg);
                }
            };

            function check(elementName, parameters) {
                var element = document.getElementById(elementName);

                if (element != undefined) {
                    $.each(parameters, function(rule, param) {
                        if (rule != 'label' && rule != 'title') {
                            var result = fvalidator.methods[rule].call(fvalidator, element.value.replace(/\r/g, ""), element, param);
                            if (!result) {
                                addError(elementName, rule, param);
                                return false;
                            }
                        }
                    });
                }
                return true;
            };

            function checkForm(value) {
                var rules = config.rules;
                $.each(rules, function(elementName, param) {
                    check(elementName, param);
                });
            };

            $(this).submit(function(event) {
                reset();
                checkForm();
                if (!valid()) {
                    event.preventDefault();
                    showErrors();
                } else {
                    if (config.confirmText != '' && !confirm(config.confirmText)) {
                        event.preventDefault();
                    }
                }
            });

        });
        return this;
    };
})(jQuery);
