﻿(function ($)
{
    var Validation = function ()
    {
        var rules = {

            required: {
                check: function (elem)
                {
                    if (elem.attr("type") == "checkbox" || elem.attr("type") == "radio") {
                        for (var i = 0; i < elem.length; i++)
                            if (elem[i].checked) return true;
                    }
                    else if (elem.val())
                        return true;

                    return false;
                },
                msg: "Required"
            },
            phone: {
                check: function (elem)
                {
                    if (elem.val())
                        return testPattern(elem.val(), "^([\(]{1}[0-9]{3}[\)]{1}[ ]{1}[0-9]{3}[\-]{1}[0-9]{4})$");
                    return true;
                },
                msg: "Invalid phone number"
            },
            email: {
                check: function (elem)
                {
                    if (elem.val())
                        return testPattern(elem.val(), "^[A-Za-z0-9](([_\.\-]?[a-zA-Z0-9]+)*)@([A-Za-z0-9]+)(([\.\-]?[a-zA-Z0-9]+)*)\.([A-Za-z]{2,})$");
                    return true;
                },
                msg: "Invalid e-mail address"
            },
            url: {
                check: function (elem)
                {
                    if (elem.val())
                        return testPattern(elem.val(), "^https?://(.+\.)+.{2,4}(/.*)?$");
                    return true;
                },
                msg: "Invalid URL"
            },
            password: {
                check: function (elem)
                {
                    if (elem.val())
                        return elem.val().length >= 8 & elem.val().length <= 14;
                    return true;
                },
                msg: "Password must be between 8-14 characters"
            },
            date: {
                check: function (elem)
                {
                    if (elem.val())
                        return !/Invalid|NaN/.test(new Date(elem.val()));
                    return true;
                },
                msg: "Invalid date"
            },
            dateISO: {
                check: function (elem)
                {
                    if (elem.val())
                        return !/Invalid|NaN/.test(new Date(elem.val()));
                    return true;
                },
                msg: "Invalid date"
            },
            compare: {
                check: function (elem, compare)
                {
                    if (elem.val() && compare) {
                        return elem.val() == compare;
                    }
                    return true;
                },
                msg: "Mismatch"
            },
            minValue: {
                check: function (elem, min)
                {
                    if (elem.val() && min) {
                        return elem.val() >= min;
                    }
                    return true;
                },
                msg: "Value too low"
            },
            maxValue: {
                check: function (elem, max)
                {
                    if (elem.val() && max) {
                        return elem.val() <= max;
                    }
                    return true;
                },
                msg: "Value too high"
            },
            minChars: {
                check: function (elem, min)
                {
                    if (elem.val() && min) {
                        return elem.val().length >= min;
                    }
                    return true;
                },
                msg: "Too few characters"
            }

        }
        var testPattern = function (value, pattern)
        {
            var regExp = new RegExp(pattern, "");
            return regExp.test(value);
        }
        return {
            addRule: function (name, rule)
            {
                rules[name] = rule;
            },
            getRule: function (name)
            {
                return rules[name];
            }
        }
    }

    /* 
    Form factory 
    */
    var Form = function (form)
    {
        var fields = [];

        form.find("[validation]").each(function ()
        {
            var field = $(this);
            if (field.attr('validation') !== undefined) {
                fields.push(new Field(field));
            }
        });
        this.fields = fields;
    }
    Form.prototype = {
        validate: function ()
        {
            for (field in this.fields) {
                this.fields[field].validate();
            }
        },
        isValid: function ()
        {
            for (field in this.fields) {
                if (!this.fields[field].valid) {
                    this.fields[field].field.focus();
                    return false;
                }
            }            
            // Closes prettyPhoto modal window if not a login form
            if ($("[validation=password]").val() == undefined)  window.parent.$.prettyPhoto.close();            
            return true;
        }
    }

    /* 
    Field factory 
    */
    var Field = function (field)
    {
        this.field = field;
        this.valid = false;
        this.attach("change");
    }
    Field.prototype = {

        attach: function (event)
        {
            var obj = this;
            if (event == "change") {
                obj.field.bind("change", function ()
                {
                    return obj.validate();
                });
            }
            if (event == "keyup") {
                obj.field.bind("keyup", function (e)
                {
                    return obj.validate();
                });
            }
        },

        validate: function ()
        {

            var obj = this,
                field = obj.field,
                errorlist = $(document.createElement("span")).addClass("val-success"),
                types = field.attr("validation").split(" "),
                errors = [];

            field.next(".val-success").remove();
            field.next(".val-failure").remove();
            for (var type in types) {

                var rule = $.Validation.getRule(types[type]);
                if (!rule.check(field)) errors.push(rule.msg);
            }
            if (field.attr("compare") != undefined) {
                var id = "#" + field.attr("compare");
                var rule = $.Validation.getRule("compare");
                if (!rule.check(field, $(id).val())) errors.push(rule.msg);
            }
            if (field.attr("minValue") != undefined) {
                var rule = $.Validation.getRule("minValue");
                if (!rule.check(field, field.attr("minValue"))) errors.push(rule.msg);
            }
            if (field.attr("maxValue") != undefined) {
                var rule = $.Validation.getRule("maxValue");
                if (!rule.check(field, field.attr("maxValue"))) errors.push(rule.msg);
            }
            if (field.attr("minChars") != undefined) {
                var rule = $.Validation.getRule("minChars");
                if (!rule.check(field, field.attr("minChars"))) errors.push(rule.msg);
            }

            obj.field.unbind("keyup")
            obj.attach("keyup");
            field.after(errorlist.empty());
            field.attr("title", "");

            if (errors.length) {
                for (error in errors) {
                    errorlist.removeClass("val-success").addClass("val-failure").append("&nbsp;&nbsp;&nbsp;&nbsp;");
                    errorlist.attr("title", errors[error]);
                    field.attr("title", errors[error]);
                }
                obj.valid = false;
            }
            else {
                errorlist.removeClass("val-failure").addClass("val-success").append("&nbsp;&nbsp;&nbsp;&nbsp;")
                obj.valid = true;
            }
        }
    }

    /*
    Validation extends jQuery prototype
    */
    $.extend($.fn, {

        ecValidate: function ()
        {
            var validator = new Form($(this));
            $.data($(this)[0], 'validator', validator);

            $(this).bind("submit", function (e)
            {
                validator.validate();
                if (!validator.isValid()) {
                    e.preventDefault();
                }
            });

            $(this).find("[maxChars]").each(function ()
            {
                if ($(this).attr("maxChars") != undefined) {
                    var charsleft = $(document.createElement("div")).addClass("val-charsleft");
                    var maxChars = $(this).attr("maxChars");

                    $(this).unbind("keypress keydown").bind("keypress keydown", function (e)
                    {
                        if ($(this).val().length <= maxChars) {

                            $(".val-charsleft, .val-fewcharsleft").remove();
                            $(this).next(".val-success, .val-failure").remove();
                            $(this).after().after(charsleft.empty());

                            charsleft.append((maxChars - $(this).val().length) + " chars left");

                            if ($(this).val().length >= (maxChars - (maxChars * 0.2)))
                                charsleft.removeClass("val-charsleft").addClass("val-fewcharsleft");
                            else
                                charsleft.removeClass("val-fewcharsleft").addClass("val-charsleft");

                            charsleft.css("width", $(this).css("width"));
                        }
                        else if (e.keyCode != "8" && e.keyCode != "46") e.preventDefault();
                    });
                }
            });

        },
        validate: function ()
        {
            var validator = $.data($(this)[0], 'validator');
            validator.validate();
            return validator.isValid();
        }
    });
    $.Validation = new Validation();
})(jQuery);
