var fValidator = new Class({
  
        options: {
                msgContainerTag: "div",
                msgClass: "fValidator-msg",

                styleNeutral: {"background-color": "#fff", "font-size": "10px", "border" : "1px solid #aeaeae"},
                styleInvalid: {"background-color": "#fcc", "font-size": "10px"},
                styleValid: {"background-color": "#fff",  "font-size": "10px"},

                required: {type: "required", re: /[^.*]/, msg: "Toto pole je nutno vyplnit."},
                alpha: {type: "alpha", re: /^[a-z ._-]+$/i, msg: "This field accepts alphabetic characters only."},
                alphanum: {type: "alphanum", re: /^[a-z0-9 ._-]+$/i, msg: "This field accepts alphanumeric characters only."},
                integer: {type: "integer", re: /^[-+]?\d+$/, msg: "Please enter a valid integer."},
                real: {type: "real", re: /^[-+]?\d*\.?\d+$/, msg: "Please enter a valid number."},
                date: {type: "date", re: /^((((0[13578])|([13578])|(1[02]))[\/](([1-9])|([0-2][0-9])|(3[01])))|(((0[469])|([469])|(11))[\/](([1-9])|([0-2][0-9])|(30)))|((2|02)[\/](([1-9])|([0-2][0-9]))))[\/]\d{4}$|^\d{4}$/, msg: "Please enter a valid date (mm/dd/yyyy)."},
                email: {type: "email", re: /^[a-z0-9._%-]+@[a-z0-9.-]+\.[a-z]{2,4}$/i, msg: "Vložte prosím správný formát emailu."},
                phone: {type: "phone", re: /^[\d]{8,12}$/, msg: "Vložte prosím správný formát tel.čísla bez mezer a předvolby."},
                psc: {type: "psc", re: /^[\d]{5}$/, msg: "Vložte prosím správný formát PSČ bez mezer."},
                url: {type: "url", re: /^(http|https|ftp)\:\/\/[a-z0-9\-\.]+\.[a-z]{2,3}(:[a-z0-9]*)?\/?([a-z0-9\-\._\?\,\'\/\\\+&amp;%\$#\=~])*$/i, msg: "Please enter a valid url."},
                confirm: {type: "confirm", msg: "Heslo pro potvrzení se neshoduje."},
                
                onValid: Class.empty,
                onInvalid: Class.empty
        },
         
        initialize: function(form, options) {
                this.form = $(form);
                this.setOptions(options);
                this.fields = this.form.getElements("*[class^=fValidate]");
                this.validations = [];

                this.fields.each(function(element) {
                        if(!this._isChildType(element)) element.setStyles(this.options.styleNeutral);
                        element.cbErr = 0;
                        var classes = element.getProperty("class").split(' ');
                        classes.each(function(klass) {
                                if(klass.match(/^fValidate(\[.+\])$/)) {
                                        var aFilters = eval(klass.match(/^fValidate(\[.+\])$/)[1]);
                                        for(var i = 0; i < aFilters.length; i++) {
                                                if(this.options[aFilters[i]]) this.register(element, this.options[aFilters[i]]);
                                                if(aFilters[i].charAt(0) == '=') this.register(element, $extend(this.options.confirm, {idField: aFilters[i].substr(1)}));
                                        }
                                }
                        }.bind(this));
                }.bind(this));

                this.form.addEvents({
                        "submit": this._onSubmit.bind(this),
                        "reset": this._onReset.bind(this)
                });
        },

        register: function(field, options) {
                field = $(field);
                this.validations.push([field, options]);
                field.addEvent("blur", function() {
                        this._validate(field, options);
                }.bind(this));
        },

        _isChildType: function(el) {
                var elType = el.type.toLowerCase();
                if((elType == "radio") || (elType == "checkbox")) return true;
                return false;
        },

        _validate: function(field, options) {
                switch(options.type) {
                        case "confirm":
                                if($(options.idField).getValue() == field.getValue()) this._msgRemove(field, options);
                                else this._msgInject(field, options);
                                break;
                        default:
                                if(options.re.test(field.getValue())) this._msgRemove(field, options);
                                else this._msgInject(field, options);
                }
        },

        _validateChild: function(child, options) {
                var nlButtonGroup = this.form[child.getProperty("name")];
                var cbCheckeds = 0;
                var isValid = true;
                 for(var i = 0; i < nlButtonGroup.length; i++) {
                        if(nlButtonGroup[i].checked) {
                                cbCheckeds++;
                                if(!options.re.test(nlButtonGroup[i].getValue())) {
                                        isValid = false;
                                        break;
                                }
                        }
                }
                if(cbCheckeds == 0 && options.type == "required") isValid = false;
                if(isValid) this._msgRemove(child, options);
                else this._msgInject(child, options);
        },

        _msgInject: function(owner, options) {
                if(!$(owner.getProperty("id") + options.type +"_msg")) {
                        var msgContainer = new Element(this.options.msgContainerTag, {"id": owner.getProperty("id") + options.type +"_msg", "class": this.options.msgClass})
                                .setHTML(options.msg)
                                .setStyle("opacity", 0)
                                .injectAfter(owner)
                                .effect("opacity", {
                                        duration: 500,
                                        transition: Fx.Transitions.linear
                                }).start(0, 1);
                        owner.cbErr++;
                        this._chkStatus(owner, options);
                }
        },

        _msgRemove: function(owner, options, isReset) {
                isReset = isReset || false;
                if($(owner.getProperty("id") + options.type +"_msg")) {
                        var el = $(owner.getProperty("id") + options.type +"_msg");
                        el.effect("opacity", {
                                duration: 500,
                                transition: Fx.Transitions.linear,
                                onComplete: function() {el.remove()}
                        }).start(1, 0);
                        if(!isReset) {
                                owner.cbErr--;
                                this._chkStatus(owner, options);
                        }
                }
        },

        _chkStatus: function(field, options) {
           this.bunka = document.getElementsByTagName("textbunka");
                if(field.cbErr == 0) {
                        field.effects({duration: 500, transition: Fx.Transitions.linear}).start(this.options.styleValid);
                        this.fireEvent("onValid", [field, options], 50);
                } else {
                        field.effects({duration: 500, transition: Fx.Transitions.linear}).start(this.options.styleInvalid);
                        this.fireEvent("onInvalid", [field, options], 50);
                }
        },

        _onSubmit: function(event) {
                event = new Event(event);
                var isValid = true;
                this.validations.each(function(array) {
                        if(this._isChildType(array[0])) this._validateChild(array[0], array[1]);
                        else this._validate(array[0], array[1]);
                        if(array[0].cbErr > 0) isValid = false;
                }.bind(this));

                if(!isValid) event.stop();
                return isValid;
        },

        _onReset: function() {
                this.validations.each(function(array) {
                        if(!this._isChildType(array[0])) array[0].setStyles(this.options.styleNeutral);
                        array[0].cbErr = 0;
                        this._msgRemove(array[0], array[1], true);
                }.bind(this));
        }
});

fValidator.implement(new Events);
fValidator.implement(new Options);