﻿(function ($) {
    $.fn.extend({
        //Function that initializes the validateHandle plugin
        //@param settings the settings for the plugin
        validateHandle: function (settings) {
            var options = $.extend({}, $.fn.validateHandle.defaults, settings);
            //            if (settings) { options = $.extend({}, $.fn.validateHandle.defaults, settings); } else { }
            return this.each(function () {
                var that = $(this);
                that.data('rules', []);
                $.each(options.defaultRule, function (key, value) {
                    //cache appendTo and errorClass for later calls with .addRule
                    that.data('appendTo', options.appendTo);
                    that.data('errorClass', options.errorClass);

                    //If the rule is in the $.fn.validateHandle.defaults.defaultRule
                    if (that.hasClass(key)) {
                        that.addRule(value);
                    }
                });

                that.bind('focusout', function () {
                    var tag = $(this).get(0).tagName;
                    if (tag !== 'DIV') {
                        setTimeout(function () { that.validate(); }, 200);
                    }
                });
            });
        },
        //Function that adds a rule to the selected elements
        //@param rule the rule object that gets added to the element rules set
        //@return returns each element so that this function call can be chained.
        addRule: function (rule) {
            return this.each(function () {
                var element = $(this);
                var localRule = $.extend({}, rule);
                if (!element.data('rules')) {
                    element.data('rules', []);
                }
                element.data('rules').push(localRule);
                if (element.hasClass('quiet')) {
                    element.data('required', false);
                }
            });
        },
//        removeRule: function () {
//            $.each($(this).data('rules'), function (index, value) {
//                
//            });
//        },
        //Function that applies a rule to an element
        //@param rule the rule object that is getting applied to the element
        applyRule: function (rule) {
            var that = $(this);
            var tag = that.get(0).tagName;
            var id = that.attr('id');
            var thatAppendTo = that.data('appendTo');
            var errorClass = that.data('errorClass');
            var errorLabel = $('#' + id + '_error_label');
            switch (tag) {
                case 'SELECT':
                    if (((rule.bool !== undefined && !rule.bool()) || (rule.rule !== undefined && rule.rule.minLength !== undefined && (that.val() !== null ? that.val().length : -1) < rule.rule.minLength))) {
                        that.raiseError(rule);
                    } else if ($(this).data('errored') && that.hasClass('error')) {
                        that.removeError();
                    }
                    break;
                case 'INPUT':
                    if (that.attr('type') === 'text' || that.attr('type') === 'password') {
                        if ((rule.rule !== undefined && !rule.rule.test(that.val())) || (rule.bool !== undefined && !rule.bool())) {
                            that.raiseError(rule);
                        } else if (that.data('errored') && that.hasClass('error')) {
                            that.removeError();
                        }
                    } else if (that.attr('type') === 'radio' || that.attr('type') === 'checkbox') {
                        var addErrorClassTo = that.parent();
                        var errorLabel2 = '';
                        if (((rule.rule !== undefined && rule.rule.minLength !== undefined && that.parent().find('[name=' + that.attr('name') + ']:checked').length < rule.rule.minLength)) || (rule.bool !== undefined && !rule.bool())) {
                            //Clearing out other errors for the same validation
                            if (that.attr('name') !== undefined && thatAppendTo === undefined) {
                                errorLabel2 = that.parent().parent().find('[id$=_error_label][name=' + that.attr('name') + ']');
                                errorLabel2.prev('br').remove();
                                errorLabel2.next('br').remove();
                                errorLabel2.remove();
                            } else if (that.attr('name') !== undefined && thatAppendTo !== undefined) {
                                errorLabel2 = thatAppendTo.find('[id$=_error_label][name=' + that.attr('name') + ']');
                                errorLabel2.prev('br').remove();
                                errorLabel2.next('br').remove();
                                errorLabel2.remove();
                            }

                            errorLabel.prev('br').remove();
                            errorLabel.next('br').remove();
                            errorLabel.remove();
                            if (thatAppendTo !== undefined) {
                                $('<br/><label id="' + that.attr('name') + '_error_label" class="labelerror ' + rule.errorClass + '" name="' + that.attr('name') + '">' + rule.message + '</label><br/>').appendTo(thatAppendTo);
                            } else {
                                $('<br/><label id="' + that.attr('name') + '_error_label" class="labelerror ' + rule.errorClass + '" name="' + that.attr('name') + '">' + rule.message + '</label><br/>').insertAfter(that.parents('div[name=' + that.attr('name') + ']').first());
                            }
                            that.data('errored', true);
                            that.addClass('error');
                            addErrorClassTo.addClass('error');
                        } else if (that.data('errored') && that.parent().hasClass('error')) {
                            //Clearing out other errors for the same validation
                            if (that.attr('name') !== undefined && thatAppendTo === undefined) {
                                errorLabel2 = that.parent().parent().find('[id$=_error_label][name=' + that.attr('name') + ']');
                                errorLabel2.prev('br').remove();
                                errorLabel2.next('br').remove();
                                errorLabel2.remove();
                            } else if (that.attr('name') !== undefined && thatAppendTo !== undefined) {
                                errorLabel2 = thatAppendTo.find('[id$=_error_label][name=' + that.attr('name') + ']');
                                errorLabel2.prev('br').remove();
                                errorLabel2.next('br').remove();
                                errorLabel2.remove();
                            }

                            errorLabel.prev('br').remove();
                            errorLabel.next('br').remove();
                            errorLabel.remove();
                            that.data('errored', false);
                            that.removeClass('error');
                            addErrorClassTo.removeClass('error');
                            that.parent().find('[name=' + that.attr('name') + '].error').removeClass('error');
                        }
                    }
                    break;
                case 'TEXTAREA':
                    if ((rule.rule !== undefined && !rule.rule.test(that.val())) || (rule.bool !== undefined && !rule.bool())) {
                        that.raiseError(rule);
                    } else if (that.data('errored') && that.hasClass('error')) {
                        that.removeError();
                    }
                    break;
                case 'DIV':
                    if ((rule.rule !== undefined && !rule.rule.test(that.val())) || (rule.bool !== undefined && !rule.bool())) {
                        that.raiseError(rule);
                    } else if (that.data('errored') && that.hasClass('error')) {
                        that.removeError();
                    }
                    break;
            }
            return !that.data('errored');
        },
        //Function that validates all of the selected elements
        //@return returns true if the elements are valid and false if they are not
        validate: function () {
            this.each(function () {
                var that = $(this);
                var rules = that.data('rules');
                if (rules === null || rules === undefined) {
                    return true;
                    //                    throw "validateHandle has not been initialized for this element (" + that.attr('id') +  ") or this element does not have any rules.";
                }
                if (that.data('required') === false && $.trim(that.val()) === '') {
                    //If the element is not required and it has been left blank then remove it's error and return
                    if (that.data('errored')) {
                        that.removeError();
                    }
                    return true;
                }
                var valid = true;
                $.each(rules, function (index, rule) {
                    //If the element is still valid
                    if (valid) {
                        valid = that.applyRule(rule);
                    }
                });
            });
            if ($(this).filter('.error').length > 0) {
                //                $(this).filter('.error').first().focus();
                return false;
            } else {
                return true;
            }
        },
        //Function that removes the error class, data, and label from an element
        //@return returns each element so that this function call can be chained.
        removeError: function () {
            return this.each(function () {
                var that = $(this);
                var errorLabel = $('#' + that.attr('id') + '_error_label');
                errorLabel.prev('br').remove();
                errorLabel.next('br').remove();
                errorLabel.remove();
                that.removeClass('error');
                that.data('errored', false);
                that.parent().removeClass('error');
                that.parent().find('[name=' + that.attr('name') + '].error').removeClass('error');
            });
        },
        //Function that adds an error to an element
        //@param rule the rule object
        //@return returns each element so that this function call can be chained.
        raiseError: function (rule) {
            var message = rule.message;
            return this.each(function () {
            //                var tag = $(this).get(0).tagName;
                var that = $(this);
                var id = that.attr('id');
                var errorLabel = $('#' + id + '_error_label');
                var thatAppendTo = that.data('appendTo');
                var errorClass = that.data('errorClass');
                errorLabel.prev('br').remove();
                errorLabel.next('br').remove();
                errorLabel.remove();
                if (thatAppendTo !== undefined) {
                    $('<br/><label id="' + id + '_error_label" class="labelerror ' + errorClass + '">' + message + '</label><br/>').appendTo(thatAppendTo);
                } else {
                    $('<br/><label id="' + id + '_error_label" class="labelerror ' + errorClass + '">' + message + '</label><br/>').appendTo(that.parent());
                }
                that.data('errored', true);
                that.addClass('error');
            });
        },
        //Function to get the default rules
        getDefaultRules: function () {
            return $.fn.validateHandle.defaults.defaultRule;
        }
    });
    $.extend({
        validateHandle: function (settings) {
            return $().validateHandle(settings);
        },
        addRule: function (rule, errorMessage) {
            return $().addRule(rule, errorMessage);
        },
        //        removeRule: function (rule) {
        //            return $().removeRule(rule);
        //        },
        validate: function () {
            return $().validate();
        },
        removeError: function () {
            return $().removeError();
        },
        raiseError: function (rule) {
            return $().raiseError(rule);
        },
        getDefaultRules: function () {
            return $().getDefaultRules();
        }
    });
   
    $.fn.validateHandle.defaults = {
        defaultRule: {  //Default Rules are always executed before any other rule on an element.
            //username: { "rule": /[A-Za-z0-9-_]{4,50}$/, "message": "Must be 4-50 characters." },
            //password: { "rule": /[A-Za-z0-9-_]{4,50}$/, "message": "Must be 4-50 characters." },
            unicodeNonSpecial: { "rule": /^([\s]*[a-zA-Z\u00C0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]{1}[\s]*){1,100}$/,
                "message": "Must be 1-100 characters in length. No special characters (!.*%@#)."
            },
            telephone: { "rule": new RegExp("^\\D?(\\d{3})\\D?\\D?(\\d{3})\\D?(\\d{4})$"), "message": "Please enter a valid telephone number" },
            email: { "rule": new RegExp("\\w+[\\w-\\.]*\\@\\w+((-\\w+)|(\\w*))\\.[a-z]{2,3}"), "message": "Please enter a valid email address" }
        },
        appendTo: undefined,
        errorClass: ""
    };
    $.fn.validateHandle.strings = {};
})(jQuery);

