(function($) {
    /*
    Validation Singleton
    */
    var Validation = function() {
        var rules = {
            email : {
               check: function(value) {
                   if(value)
                       return testPattern(value,/^(("[\w-\s]+")|([\w-]+(?:\.[\w-]+)*)|("[\w-\s]+")([\w-]+(?:\.[\w-]+)*))(@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$)|(@\[?((25[0-5]\.|2[0-4][0-9]\.|1[0-9]{2}\.|[0-9]{1,2}\.))((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\.){2}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\]?$)/i);
                   return true;
               }
            },
            url : {
               check : function(value) {
                   if(value)
                       return testPattern(value,"^https?://(.+\.)+.{2,4}(/.*)?$");
                   return true;
               }
            },
            required : {
               check: function(value) {
                   if(value)
                       return true;
                   else
                       return false;
               }
            },
            codePostal : {
               check: function(value) {
                   if(value.length == 5)
                       return true;
                   else
                       return false;
               }
            },
            entier : {
                check: function(value) {
                   var exp = new RegExp("^[0-9]+$","g");
                   return exp.test(value);
                }
            },
            telephone : {
                check: function(value) {
                   var exp = new RegExp("^[0-9]{10}$","g");
                   return exp.test(value);
                }
            }
        }
        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;
                }
            }
            return true;
        }
    }

    /*
    Field factory
    */
    var Field = function(field) {
        this.field = field;
        this.valid = false;
        this.attach("blur");
    }
    Field.prototype = {
        attach : function(event) {
            var obj = this;
            if(event == "blur") {
                obj.field.bind("blur",function() {
                    return obj.validate();
                });
            }
        },
        validate : function() {
            var obj = this,
                field = obj.field,
                types = field.attr("validation").split(":"),
                container = field.parent(),
                errorSpan = field.next('span'),
                errors = 0;

            for (var type in types) {
                var rule = $.Validation.getRule(types[type]);
                if (rule) {
                    if(!rule.check(field.val())) {
                        errors = errors+1;
                    }
                }
            }
            if(errors>0) {
                obj.field.unbind("keyup")
                obj.attach("keyup");
                errorSpan.css({'visibility':'visible'});
                obj.valid = false;
            }
            else {
                errorSpan.css({'visibility':'hidden'});
                obj.valid = true;
            }
        }
    }

    /*
    Validation extends jQuery prototype
    */
    $.extend($.fn, {
        validation : function() {
            var validator = new Form($(this));
            $.data($(this)[0], 'validator', validator);
        },
        validate : function() {
            var validator = $.data($(this)[0], 'validator');
            validator.validate();
            return validator.isValid();
        }
    });
    $.Validation = new Validation();
})(jQuery);
