﻿$.link4seo.validation = {}; 

$.link4seo.validation.ValidatorMgr = {
    registerRule: function(rule, type) {
        this[rule] = type;
    },

    createValidator: function(rule, options) {
        options = options || {};
        if (this[rule]) {
            return new this[rule](options);
        }
        return null;
    }
};

$.link4seo.validation.ValidateResult = function() {
    this.result = false;
    this.msg = '';
    this.modifier = null;

    this.onModified = function(result) {
    };

    this.modify = function(result, msg, modifier) {
        this.result = result;
        this.msg = msg;
        this.modifier = modifier;

        if (jQuery.isFunction(this.onModified)) {
            this.onModified(this);
        }
    };
};

$.link4seo.validation.CustomValidator = $.link4seo.Extensible.extend({
    errorMsg: '',

    successor: null,

    acceptTypes: ['text', 'password', 'checkbox', 'radio', 'select'],

    initialize: function(options) {
        $.extend(this, options);
    },

    doValidate: function(input, result) {
        this.setError(result);
    },

    validate: function(input, result) {
        if ($.inArray($(input).attr('type').toLowerCase(), this.acceptTypes) != -1 ||
            $.inArray($(input).attr('tagName').toLowerCase(), this.acceptTypes) != -1) {
            this.doValidate(input, result);
        }


        if (result.result && this.successor) {
            this.successor.validate(input, result);
        }
    },

    setError: function(result) {
        result.modify(false, this.errorMsg, this);
    }
});

$.link4seo.validation.ValidatorMgr.registerRule('custom', jQuery.CustomValidator); 

$.link4seo.validation.FormValidator = function(form, options) {
    jQuery.extend(this, {
        validators: new Array(),

        addValidator: function(validator) {
            this.validators.push(validator);
        },

        success: function() {
        },

        failure: function(errors) {
        },

        validate: function() {
            var errors = new Array();
            var result = true;

            var formValidator = $(this).data('validator');
            $.each(formValidator.validators, function() {
                if (!this.isValid()) {
                    result = false;
                    if (this.result.msg) {
                        errors.push(this.result.msg);
                    }
                }
            });

            if (result && formValidator.success) {
                formValidator.success();
            }
            else if (formValidator.failure) {
                formValidator.failure(errors);
            }

            return result;
        }
    });

    options = options || {};
    $.extend(this, options);

    $(form).bind('submit', this.validate);
};

$.fn.formValidator = function(options) {
    return this.each(function() {
        var self = $(this);
        if (self.attr('tagName').toLowerCase() == 'form') {
            var validator = self.data('validator');
            if (validator) {
                $.extend(validator, options);
            }
            else {
                self.data('validator', new $.link4seo.validation.FormValidator(self, options));
            }
        }
    });
};

$.fn.performValidation = function(group, onSuccess, onFailure) {
    this.doValidate = function(validators) {
        var errors = new Array();
        var result = true;

        $.each(validators, function() {
            if (!this.isValid()) {
                result = false;
                if (this.result.msg) {
                    errors.push(this.result.msg);
                }
            }
        });

        if (result && onSuccess) {
            onSuccess();
        }
        else if (onFailure) {
            onFailure(errors);
        }

        return result;
    };

    var self = $(this);
    if (self.attr('tagName').toLowerCase() == 'form') {
        var validators = self.data('validator').validators;
        if (validators && validators.length > 0) {
            if (group && typeof group == 'string' && group.length > 0) {
                validators = $.grep(validators, function(validator) {
                    return (validator.group == group);
                });
            }
            return this.doValidate(validators);
        }
    }

    return true;
};

$.link4seo.validation.InputValidator = $.link4seo.Extensible.extend({
    readyMsg: '',
    focusMsg: '',
    validMsg: '',
    readyClass: 'validation-ready',
    errorClass: 'validation-error',
    focusClass: 'validation-focus',
    validClass: 'validation-valid',

    group: null,

    msgTarget: '',

    input: null,

    head: null,
    tail: null,

    addValidator: function(validator) {
        if (validator) {
            if (this.head) {
                this.tail.successor = validator;
                this.tail = validator;
            }
            else {
                this.head = validator;
                this.tail = validator;
            }
        }
    },

    isValid: function() {
        if (!this.result.result) {
            this.validate();
        }
        return this.result.result;
    },

    onError: function(input, msgTarget, cssClass, msg) { },
    onValid: function(input, msgTarget, cssClass, msg) { },
    onReady: function(input, msgTarget, cssClass, msg) { },
    onFocus: function(input, msgTarget, cssClass, msg) { },

    validate: function() {
        this.result.modify(true, this.validMsg, this);

        if (this.head) {
            this.head.validate(this.input, this.result);
        }
    },

    initialize: function(options) {
        options = options || {};

        $.extend(this, options);

        if (this.msgTarget && this.msgTarget != '') {
            this.msgTarget = $('#' + this.msgTarget);
        }

        if (!this.input) {
            return;
        }

        var self = this;

        this.result = new $.link4seo.validation.ValidateResult();
        this.result.onModified = function(result) {
            if (result.result) {
                self.onValid(self.input, self.msgTarget, self.validClass, self.validMsg);
            }
            else {
                self.onError(self.input, self.msgTarget, self.errorClass, result.msg);
            }
        }

        $(this.input).bind('change', function() {
            self.validate();
        }).bind('focus', function() {
            if (!self.isValid()) {
                self.onFocus(self.input, self.msgTarget, self.focusClass, self.focusMsg);
            }
        }).bind('blur', function() {
            if (self.isValid()) {
                self.onValid(self.input, self.msgTarget, self.validClass, self.validMsg);
            }
            else {
                self.onError(self.input, self.msgTarget, self.errorClass, self.result.msg);
            }
        });

        this.onReady(this.input, this.msgTarget, this.readyClass, this.readyMsg);
    }
});

$.extend($.link4seo.validation.InputValidator, {
    showMsg: function(css, msg) {
        this.getTargetEl().removeClass().addClass(css).html(msg);
    },

    getTargetEl: function() {
        if (!this.msgTarget || this.msgTarget == '') {
            return $('#' + $(this.input).attr('id') + 'Tip');
        }
        else {
            return this.msgTarget;
        }
    },

    onError: function(input, msgTarget, cssClass, msg) {
        this.showMsg(cssClass, msg);
    },
    onValid: function(input, msgTarget, cssClass, msg) {
        this.showMsg(cssClass, msg);
    },
    onReady: function(input, msgTarget, cssClass, msg) {
        this.showMsg(cssClass, msg);
    },
    onFocus: function(input, msgTarget, cssClass, msg) {
        this.showMsg(cssClass, msg);
    }
});

jQuery.fn.initValidator = function(options) {
    return this.each(function() {
        var form = $(this.form);
        var formValidator = form.data('validator');

        if (!formValidator) {
            form.formValidator({});
        }

        options['input'] = this;
        var validator = new $.link4seo.validation.InputValidator(options);
        formValidator.addValidator(validator);
        $(this).data('validator', validator);
    });
};

jQuery.fn.addValidator = function(rule, options) {
    return this.each(function() {
        var validator = $(this).data('validator');

        if (validator) {
            validator.addValidator($.link4seo.validation.ValidatorMgr.createValidator(rule, options));
        }
    });
}

$.link4seo.validation.RequiredValidator = $.link4seo.validation.CustomValidator.extend({
    doValidate: function(input, result) {
        var value = $(input).val();
        if (!value || !value.length > 0) {
            this.setError(result);
        }
    }
});

$.link4seo.validation.ValidatorMgr.registerRule('required', $.link4seo.validation.RequiredValidator);

$.link4seo.validation.LengthValidator = $.link4seo.validation.CustomValidator.extend({
    min: 0,
    max: 0,

    getMin: function() {
        return this.min || this.min >= 0 ? this.min : 0;
    },

    getMax: function() {
        return this.max || this.max >= 0 ? this.max : 0;
    },

    doValidate: function(input, result) {
        var value = $(input).val();
        if (!value || value.length < this.getMin() || value.length > this.getMax()) {
            this.setError(result);
        }
    }
});

$.link4seo.validation.ValidatorMgr.registerRule('length', $.link4seo.validation.LengthValidator);

$.link4seo.validation.RegexValidator = $.link4seo.validation.CustomValidator.extend({
    acceptTypes: ['text', 'password'],

    regex: '',

    getRegex: function() {
        return new RegExp(this.regex || '');
    },

    doValidate: function(input, result) {
        var regex = this.getRegex();
        if (!regex.test($(input).val())) {
            this.setError(result);
        }
    }
});

$.link4seo.validation.ValidatorMgr.registerRule('regex', $.link4seo.validation.RegexValidator);

$.link4seo.validation.ValueValidator = $.link4seo.validation.CustomValidator.extend({
    not: null,

    accept: null,

    doValidate: function(input, result) {
        var val = $(input).val();
        if (this.accept && typeof this.accept == 'string' &&
            val != this.accept) {
            this.setError(result);
        }
        else if (this.accept && typeof this.accept == 'object' &&
                this.accept.length && this.accept.length > 0 &&
                $.inArray(val, this.accept) == -1) {
            this.setError(result);
        }
        else if (this.not && typeof this.not == 'string' &&
            val == this.not) {
            this.setError(result);
        }
        else if (this.not && typeof this.not == 'object' &&
            this.not.length && this.not.length > 0 &&
            $.inArray(val, this.not) != -1) {
            this.setError(result);
        }
    }
});

$.link4seo.validation.ValidatorMgr.registerRule('value', $.link4seo.validation.ValueValidator);

$.link4seo.validation.AjaxValidator = $.link4seo.validation.CustomValidator.extend({
    acceptTypes: ['text', 'password'],

    url: '',

    extraParams: {},

    method: 'post',

    username: '',

    password: '',

    contentType: 'application/json; charset=utf-8',

    isPending: false,

    isAsmx: true,

    wrapper: 'd',

    doValidate: function(input, result) {
        if (this.isPending) {
            return;
        }

        var data = { value: $(input).val() };
        $.extend(data, this.extraParams);

        if (this.isAsmx) {
            data = JSON.stringify(data);
        }

        var self = this;

        this.isPending = true;

        $.ajax({
            url: this.url,
            type: this.method,
            contentType: this.contentType,
            username: this.username,
            password: this.password,
            cache: false,
            data: data,
            dataType: 'json',

            success: function(data, test) {
                self.isPending = false;
                if (self.wrapper) {
                    data = data[self.wrapper];
                }
                if (data) {
                    if (result.modifier == self) {
                        result.modify(true, '', this);
                    }
                }
                else {
                    self.setError(result);
                }
            },

            error: function(xhr, text) {
                self.isPending = false;
                self.setError(result);
            }
        });

        this.setError(result);
    }
});

$.link4seo.validation.ValidatorMgr.registerRule('ajax', $.link4seo.validation.AjaxValidator);