(function($) {
    /*
    Validation Singleton
    */
    var Validation = function() {
        
        var rules = {
            
            required : {
                
               check: function(value, field, rules, i) {

                   if(value == null || value == ''){
                      return "* This field is required.";
									 }
									 
               }
							 
            },
						
						equals : {
                
               check: function(value, field, rules, i) {

                    var equalsField = rules[i + 1];

										if (field.attr('value') != $("#" + equalsField).attr('value')){
											return "* Fields do not match.";
										}
										
               } 
							 
            },
					
					regex : {
                
               check: function(value, field, rules, i) {

								var request = rules[i + 1];
								var pattern;
								
								switch(request){
									case 'email':
										pattern = /^([A-Za-z0-9_\-\.\'])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,6})$/;	
										break;
									default:
										pattern = null;
										break;							
								}
								
								var regExp = new RegExp(pattern);
								var pass = regExp.test(value);
								if(!pass){
									return "* Please enter a valid email";
								}
										
               } 
							 
            }
        }
        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('[class*=validate]').each(function() {
            
						var field = $(this);
            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("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,
                errorClass = "errorAlert",
                errorlist = $(document.createElement("div")).addClass(errorClass),								
								rulesParsing = field.attr('class'),
								getRules = /validate\[(.*)\]/.exec(rulesParsing),
								str = getRules[1],
								rules = str.split(/\[|,|\]/),
								position = field.position(),
								width = field.outerWidth(true),
								height = field.outerHeight(true),
								left = position.left + width + 20,
								top = position.top,
								errors = []; 
																
								errorlist.css({'left' : left, 'top' : top}).fadeIn(1000);
            
            field.next(".errorAlert").remove();
						
            for (var i = 0; i < rules.length; i++) {
		
                var rule = $.Validation.getRule(rules[i]);
								
								var errorMsg = undefined;
								
								switch (rules[i]) {

                    case "required":
                        errorMsg = rule.check(field.val(), field, rules, i)
                        break;
										case "equals":
                        errorMsg = rule.check(field.val(), field, rules, i)
                        break;
										case "regex":
                        errorMsg = rule.check(field.val(), field, rules, i)
                        break;
												
								}
								
								if (errorMsg !== undefined) {
									field.addClass("error");
									errors.push(errorMsg + "<br />");
								}
								
            }
						
            if(errors.length) {

                obj.field.unbind("keyup")
                obj.attach("keyup");
                field.after(errorlist.empty());
                for(error in errors) {                
                    errorlist.append(errors[error]);        
                }
                obj.valid = false;
            } 
            else {
                errorlist.remove();
                field.removeClass("error");
                obj.valid = true;
            }
        }
    }
		
    $('.errorAlert').live('click', function(){ 
			$(this).fadeOut();
		});
		
    /*
    Validation extends jQuery prototype
    */
    $.extend($.fn, {
        
        validation : function() {
            var validator = new Form($(this));
            $.data($(this), 'validator', validator);
            
                validator.validate();
                if(!validator.isValid()) {
									return false;
                }else{
									return true;
								}
        },
        validate : function() {
            
            var validator = $.data($(this)[0], 'validator');
            validator.validate();
            return validator.isValid();
            
        }
    });
    $.Validation = new Validation();
})(jQuery);
