/**
* SIMPLE FORM VALIDATION PLUGIN
* Author: Daniel Chen
* Version 1.0  (July 29, 2010)
* REQUIRES:
	@ /www/css/subscribe.css -> CSS (Form styles)
    @ Empty generic Hidden Field prepended within the FORM Element
	@ /www/js/subscribe.js -> JAVASCRIPT event handler to call plugin
* CONFIGURABLE OPTIONS:
	@ requiredClass: 'required' // CssClass on input tag for required fields
 	@ emailClass: 'email' // CssClass on input tag for email format
 	@ integerClass: 'integer' // CssClass on input tag for numbers only
	@ phoneClass: 'phone' // CssClass on input tag for phone xxx-xxx-xxxx format
	@ checkboxes: 'mustselect' // CssClass to put on list parent for manadatory selection
	@ invalidClass: 'invalid' // CssClass on input tag for errors
	@ messageContainer: 'ValidationMessage' // ID name for element that hold validation messaging summary
*/
(function($) {
$.fn.validate = function(options){
    var opts = $.extend({}, $.fn.validate.defaults, options);
	var invalid = 0;
	var errorMsgArray = [];
	function isInteger(s) {
        if (s != '' && s.match(/^(\d*)$/)) {
            return true;
        }
        else {
            return false;
        }
    }
	function isInputEmpty(s) {
        if($.trim(s) === ""){
			return false;
		}
		else {
			return true;
		}
    }
	function isValidEmail(s){
		var filter  = /([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+>?$/;
		if(s.search(filter) == -1){
			return false;
		}
		else {
			return true;
		}
	}
	function isValidPhoneNumber(s){
		// var filter = /\d{3}\-\d{3}\-\d{4}/;
		var filter = /^\(?(\d{3})\)?[- ]?(\d{3})[- ]?(\d{4})$/;
		if(s.search(filter) == -1){
		    return false;
		}
		else {
			return true;
		}
	}
	function isPasswordValid(s, min) {
        if($.trim(s).length < min){
			return false;
		}
		else {
			return true;
		}
    }
	function confirmPassword(v1,v2){
		var p1 = $.trim(v1);
		var p2 = $.trim(v2);
		if(p2 === p1){
			return true;
		}
		else {
			return false;
		}
	}	
    return this.each(function() {
        $this = $(this);
        // Find necessary DOM elements
        var o = $.meta ? $.extend({}, opts, $this.data()) : opts;

		function evaluateField(obj, func){
			if(func == false){
				highlightField(obj);
				errorMsgArray.push(obj.attr("alt"));	
			}
		}
		function keyUpCheck(obj, func){
			if(func === false){
				highlightField(obj);
			}
			else {
				validField(obj);
			}
		}
		function highlightField(input){
			input.addClass(opts.invalidClass);
			invalid++
		}
		function validField(input){
			input.removeClass(opts.invalidClass);
		}
		// Loop through all required fields and validate
		$this.find("input."+ o.requiredClass).each(function(){
			// If empty
			evaluateField($(this), isInputEmpty(this.value));
		});
		$this.find("select").each(function(){
			// If value is unchanged
			if(this.value === "0"){
				$(this).next("span.required").fadeIn();
				errorMsgArray.push($(this).attr("alt"));
				invalid++
			}
		});
		$this.find("input."+ o.integerClass).each(function(){
			// If number
			evaluateField($(this), isInteger(this.value));
		});
		$this.find("input."+ o.phoneClass).each(function(){
			// If value is NOT in xxx-xxx-xxxx format
			evaluateField($(this), isValidPhoneNumber(this.value));	
		});
		$this.find("input."+ o.emailClass).each(function(){
			// If invalid email address
			evaluateField($(this), isValidEmail(this.value));
		});
		$this.find("input."+ o.passwordClass).each(function(){
			// If password meets min requirement
			evaluateField($(this), isPasswordValid(this.value, 6));
		});
		$this.find("input."+ o.confirmClass).each(function(){
			var password = $this.find("input[type=password]").eq(0).val();
			// If confirm password matches password
			evaluateField($(this), confirmPassword(this.value, password));
		});
		$this.find("."+ o.checkboxes).each(function(){
			var totalchecked = $(this).find("input[type=checkbox]:checked, input[type=radio]:checked").length;
			// If nothing is checked
			if(totalchecked < 1){
				$(this).parent().addClass("invalid");
				errorMsgArray.push($(this).attr("title"));
				invalid++
			}
		});

		// Event Handlers to re-validate on keyup
		$("input."+ o.requiredClass).keyup(function(){
			keyUpCheck($(this), isInputEmpty(this.value));
		});
		$("input."+ o.emailClass).keyup(function(){
			keyUpCheck($(this), isValidEmail(this.value));
		});
		$("input."+ o.emailClass).blur(function(){
			keyUpCheck($(this), isValidEmail(this.value));
		});
		$("input."+ o.integerClass).keyup(function(){
			keyUpCheck($(this), isInteger(this.value));
		});
		$("input."+ o.phoneClass).keyup(function(){
			keyUpCheck($(this), isValidPhoneNumber(this.value));
		});
		$("input."+ o.passwordClass).keyup(function(){
			keyUpCheck($(this), isPasswordValid(this.value, 6));
		});
		$("input."+ o.confirmClass).keyup(function(){
			var password = $this.find("input[type=password]").eq(0).val();
			// If confirm password matches password
			keyUpCheck($(this), confirmPassword(this.value, password));
		});
		$("select").change(function(){
			if(this.value !== "0"){
				$(this).next("span.required").fadeOut();
			}	
		});
		$("."+ o.checkboxes + " input[type=checkbox]" + ", " + "."+ o.checkboxes + " input[type=radio]").click(function(){
			if($(this).is(":checked")){
				$(this).parents().removeClass("invalid");
			}
		});
		
		if(invalid > 0){
			$("#" + o.messageContainer).find("p").html(errorMsgArray.join(", ").toString()).end().slideDown();
			$this.find("input[type=hidden]").eq(0).val(false);
		}
		else {
			$("#" + o.messageContainer).hide();	
			$this.find("input[type=hidden]").eq(0).val(true);
		}
    });
};
$.fn.validate.defaults = {
		requiredClass: 'required',
    	emailClass: 'email',
    	integerClass: 'integer',
		phoneClass: 'phone',
		invalidClass: 'invalid',
		checkboxes: 'mustselect',
		passwordClass: 'password',
		confirmClass: 'confirm',
		messageContainer: 'ValidationMessage'
};
})(jQuery);

