/**
 * @author Sebastian Romero April-29-2009
 * @param {String} message
 * @example $("input").displayOnFieldError("Oops!");
 */
jQuery.fn.displayOnFieldError = function(message){
	
	var str_message = message;
	var str_errorclassField = "error";
	var scope = this;

	/**
	 * 
	 * @param {JqueryObject} field
	 */
	var displayOnFieldError = function(field){
		var div_error = scope.errorbubble(str_message);
		$(field).parent().find(".error_bubble").remove();
		$(field).parent().append(div_error);
		$(field).addClass(str_errorclassField);
		scope.posError(div_error, $(field));
	};
	
	/**
	 * @param {JqueryObject} errorMessage
	 * @param {JqueryObject} field
	 * Position the Error After the Field
	 */
	this.posError = function(errorMessage, field){
		var offset = field.offset();
		var obj_pos = new Object();
		if(field.hasClass("showTop")){
			obj_pos = {
				top:-20,
				left:(field.width() - errorMessage.width())/2
			}
		} else if(field.hasClass("showBottom")){
			obj_pos = {
				top:field.height() + 40,
				left:(field.width() - errorMessage.width())/2
			}
		} else if(field.hasClass("showRight")){
			obj_pos = {
				top:22,
				left:field.width() + 20
			}
		} else {
			obj_pos = {
				top:20,
				left:(errorMessage.width() + 40)*-1
			}
			field.parent().find(".flag").css({
				top:Math.ceil(errorMessage.height() /2) - 3
			});
		}
		errorMessage.css(obj_pos);
		return;
	};
	
	/**
	 * 
	 * @param {String} message
	 * This function creates the error bubble
	 */
	this.errorbubble = function(message){
		var div_bubble = $(document.createElement("div"));
		div_bubble.addClass("error_bubble")
		div_bubble.html("<p>" + message + "</p><div class=\"flag leftflag\"></div>");
		return div_bubble;
	};
	
    this.each(function(){
        displayOnFieldError(this);
    });
};
/**
 * @author Sebastian Romero April-29-2009 Based on PartsDirect Validation Logic
 * @param {Function} onvalid
 * @param {Function} onerror
 * @example 
 	$(document.forms[0]).validate(function(){
 		$(this).submit();
	},function(elements){
		elements.each(function(){
			....
		});
	});
 * @return {Boolean} Returns if the is valid or not
 * @version 1.0
 */
jQuery.fn.validate = function(onvalid, onerror){
	
	/**
	 * Public properties
	 */
	this.str_errorPattern = ".errorfield";
	this.boo_isValid = true;
	this.fnc_onvalid = onvalid;
	this.fnc_onerror = onerror;
	/**
	 * Private variables
	 */
	var scope = this;
	var form;
	
	/**
	 * Constructor
	 */
	var validate = function(){
		$(form).find("input:enabled,textarea:enabled,select:enabled").each(function(){
			for (var rule in scope.validationRules) {
                if (scope.validationRules.hasOwnProperty(rule)) {
                    scope.validationRules[rule]($(this));
                }
            }
        });  
	};
	
	/**
	 * Public methods
	 * addErrorOnForm
	 * @param {JqueryObject} field
	 * @param {String} message
	 */
	
	this.addErrorOnForm = function(field, message){
		field.addClass(scope.str_errorPattern);
		scope.boo_isValid = false;
		field.displayOnFieldError(message);
	};
	
	/**
	 * 
	 * @param {Object} oField
	 */
	this.getLabel = function(oField) {
		if(oField.attr('title')){
			return oField.attr('title');
		} else if($('[for=' + oField.attr('id') + ']').length) {
			return $('[for=' + oField.attr('id') + ']').text().replace('*','')
		} else if($('[for=' + oField.attr('name') + ']').length) {
			return $('[for=' + oField.attr('name') + ']').text().replace('*','')
		} else { 
			return oField.attr('name')
		}
	}
	
	/**
	 * Validation Rules Object
	 */
	this.validationRules = {
		/**
		 * @param {JqueryObject} field
		 */
        required: function(field){
            if (field.hasClass("required")) {
                switch (field.attr("type")) {
                    case "radio":
                        if (!$("input[name='" + field.attr('name') + "']").attr("checked")) {
							scope.addErrorOnForm(field, "option selection is required.");
                        }
                        break;
                    case "checkbox":
                        if (!field.attr("checked")) {
							scope.addErrorOnForm(field, scope.getLabel(field) + " is required.");
                        }
                        break;
                    case "text":
                    default:
                        if (!field.val() || field.val() == field.attr('title') || field.val().replace(/[' ']{1,}/, '') == '') {
                            scope.addErrorOnForm(field, scope.getLabel(field) + " is required.");
                        }
                }
            }
            return true;
        },
		
		/**
		 * 
		 * @param {JqueryObject} field
		 * @example 
		 *	<input type="text" class="minMax min_5 max_40" />
		 *	.minMax - enables min/max validation (required)
		 *	.min_X - minimum length	(optional if max_X present)
		 *	.max_X - maximum length	(optional if min_x present)
		 */
        minMax: function(field){
            if (field.hasClass('minMax')) {
                var classes, minChar, maxChar;
                classes = field.attr('class').split(' ');
                for (var i = 0; i < classes.length; i++) {
                    if (classes[i].match('min_')) {
                        minChar = classes[i].replace('min_', '');
                    }
                    if (classes[i].match('max_')) {
                        maxChar = classes[i].replace('max_', '');
                    }
                }
                if (field.val() && field.val().length < minChar) {
					scope.addErrorOnForm(field, scope.getLabel(field) + ' must be at least ' + minChar + ' characters.');
                }
                if (field.val() && field.val().length > maxChar) {
					scope.addErrorOnForm(field, scope.getLabel(field) + ' must be less than ' + (parseInt(maxChar, 10) + 1) + ' characters.');
                }
            }
            return true;
        },
		
		/**
		 * 
		 * @param {JqueryObject} field
		 * @example <input type="text" class="email" />
		 */
        email: function(field){
            var emailRegEx = /\b[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,4}\b/;
            if (field.hasClass('email') && !field.val().match(emailRegEx) && field.val() !== '') {
				scope.addErrorOnForm(field, scope.getLabel(field) + ' is invalid.');
            }
            return true;
        },
        password: function(field){
        },
		
		/**
		 * 
		 * @param {JqueryObject} field
		 * Apply class 'match' and 'match_FIELDNAME' to one of the two fields.
		 * @example
		 * <label for="emailAddress">Email address</label>
		 * <input type="text" class="match match_emailAddressConfirm" />
		 * <label for="emailAddressConfirm">Confirm email address</label>
		 * <input type="text" class="" />
		 */
        matching: function(field){
            if (field.hasClass('match')) {
                var classes, matchingField;
                classes = field.attr('class').split(' ');
                for (var i = 0; i < classes.length; i++) {
                    if (classes[i].match('match_')) {
                        matchingField = $('[name=' + classes[i].replace('match_', '') + ']');
                    }
                }
                if (field.val() && field.val() != matchingField.val()) {
					scope.addErrorOnForm(field, scope.getLabel(field) + ' does not match ' + scope.getLabel(matchingField) + '.');
					scope.addErrorOnForm(matchingField.attr('name'));
                }
            }
            return true;
        }
    }
	/**
	 * Constructor Call
	 */
    this.each(function(){
		form = this;
        validate(this);
    });
	
	if(this.fnc_onvalid)
		if(this.boo_isValid)
			this.fnc_onvalid(this);
	if(this.fnc_onerror)
		this.fnc_onerror($(this.str_errorPattern, this));
	return this.boo_isValid;
};
