/*
 * Inline Form Validation Engine, jQuery plugin
 * 
 * Copyright(c) 2009, Cedric Dugas
 * http://www.position-relative.net
 *	
 * Form validation engine witch allow custom regex rules to be added.
 * Licenced under the MIT Licence
 */

$(document).ready(function() {

	// SUCCESS AJAX CALL, replace "success: false," by:     success : function() { callSuccessFunction() }, 
	$("[class^=validate]").validationEngine({
                inlineValidation: true,
		success :  false,
		failure : function() {}
	})
});

jQuery.fn.validationEngine = function(settings) {
	if($.validationEngineLanguage){					// IS THERE A LANGUAGE LOCALISATION ?
		allRules = $.validationEngineLanguage.allRules
	}else{
		allRules = {"required":{    			  // Add your regex rules here, you can take telephone as an example
                                    "regex":"none",
                                    "alertText":"* This field is required",
                                    "alertTextCheckboxMultiple":"* Please select an option",
                                    "alertTextCheckboxe":"* This checkbox is required"},
                            "length":{
                                    "regex":"none",
                                    "alertText":"*Between ",
                                    "alertText2":" and ",
                                    "alertText3": " characters allowed"},
                            "card":{
                                    "regex":"none",
                                    "alertText":"*Invalid ",
                                    "alertText1":" card number "},
                            "maxlength":{
                                    "regex":"none",
                                    "alertText":"*Maximum ",
                                    "alertText2":" characters allowed"},
                            "minCheckbox":{
                                    "regex":"none",
                                    "alertText":"* Checks allowed Exceeded"},
                            "confirm":{
                                    "regex":"none",
                                    "alertText":"* Your field is not matching"},
                            "telephone":{
                                    "regex":"/^[0-9\-\(\)\ ]+$/",
                                    "alertText":"* Invalid phone number"},
                            "phone":{
                                    "regex":"/^[0-9\-\.\(\)\ ]+$/",   //"regex":"/^[2-9]{1}[0-9]{2}(-|.|\s)[0-9]{3}(-|.|\s)[0-9]{4}$/", 
                                    "alertText":"* Invalid phone number"},
                            "url":{
                                    "regex":"/^(((ht|f)tp(s?))\:\/\/)?(www.|[a-zA-Z].)[a-zA-Z0-9\-\.]+\.(com|edu|gov|mil|net|org|biz|info|name|museum|us|ca|uk)(\:[0-9]+)*(/($|[a-zA-Z0-9\.\,\;\?\'\\\+&%\$#\=~_\-]+))*$/",
                                    "alertText":"* Invalid url format"},                                                                    
                            "email":{
                                    "regex":/^([A-Za-z0-9_\-\.\'])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,6})$/,
                                    "alertText":"* Invalid email address"},
                            "date":{
                                    "regex":"/^[0-9]{4}\-\[0-9]{1,2}\-\[0-9]{1,2}$/",
                                    "alertText":"* Invalid date, must be in YYYY-MM-DD format"},
                            "mdydate":{
                                    "regex":"/^[0-9]{1,2}[/][0-9]{1,2}[/][0-9]{4}$/",
                                    "alertText":"* Invalid date, must be in MM/DD/YYYY format"},
                            "onlyNumber":{
                                    "regex":"/^[0-9\ ]+$/",
                                    "alertText":"* Numbers only"},
                            "price":{
                                "regex":"/^[0-9\. ]+$/",
                                "alertText":"* Numbers only"},
                            "noSpecialCaracters":{
                                    "regex":"/^[0-9a-zA-Z\ ]+$/",
                                    "alertText":"* No special characters allowed"},
                            "fax":{
                                    	"regex":"/^[0-9\-\(\)\ ]+$/",
                                        "alertText":"* Invalid fax number"},
                            "onlyLetter":{
                                    "regex":"/^[a-zA-Z\ \']+$/",
                                    "alertText":"* Letters only"},
                            "imageType":{
                                    "regex":"/^.bmp|.jpg|.JPG|.jpeg|.JPEG|.gif|.GIF|.png|.PNG$/",
                                    "alertText":"* Supports only images of type - jpg,png,gif"}
                            
					}
					// /^([0-9a-zA-Z :\\-_!@$%^&*()])+(.jpg|.JPG|.jpeg|.JPEG|.gif|.GIF|.png|.PNG)$/
					
					// "/^[a-zA-Z0-9_\.\-]+\@([a-zA-Z0-9\-]+\.)+[a-zA-Z0-9]{2,4}$/",

	}

 	settings = jQuery.extend({
		allrules:allRules,
		inlineValidation: true,
		success : false,
		failure : function() {}
	}, settings);	

	$("form").bind("submit", function(caller){   // ON FORM SUBMIT, CONTROL AJAX FUNCTION IF SPECIFIED ON DOCUMENT READY
		if(submitValidation(this) == false){
			if (settings.success){
				settings.success && settings.success(); 
				return false;
			}
		}else{
			settings.failure && settings.failure(); 
			return false;
		}
	})
	if(settings.inlineValidation == true){ 		// Validating Inline ?
		
		$(this).not("[type=checkbox]").bind("blur", function(caller){loadValidation(this)})
//		$(this+"[type=checkbox]").bind("click", function(caller){loadValidation(this)})
	}
	    var buildPrompt = function(caller,promptText,showTriangle) {
        // ERROR PROMPT CREATION AND DISPLAY WHEN AN ERROR OCCUR
		var divFormError = document.createElement('div')
		var formErrorContent = document.createElement('div')
		var arrow = document.createElement('div')
		
		
		$(divFormError).addClass("formError")
		$(divFormError).addClass($(caller).attr("id"))
		$(formErrorContent).addClass("formErrorContent")
		$(arrow).addClass("formErrorArrow")

		$("body").append(divFormError)
		$(divFormError).append(arrow)
		$(divFormError).append(formErrorContent)
		
		if(showTriangle == true){		// NO TRIANGLE ON MAX CHECKBOX AND RADIO
			$(arrow).html('<div class="line10"></div><div class="line9"></div><div class="line8"></div><div class="line7"></div><div class="line6"></div><div class="line5"></div><div class="line4"></div><div class="line3"></div><div class="line2"></div><div class="line1"></div>');
		}
		$(formErrorContent).html(promptText)
		callerTopPosition = $(caller).offset().top;
		callerleftPosition = $(caller).offset().left;
		callerWidth =  $(caller).width()
		callerHeight =  $(caller).height()
		inputHeight = $(divFormError).height()

		callerleftPosition = callerleftPosition + callerWidth -30//+20
		callerTopPosition = callerTopPosition  -inputHeight -10//+25
	
		$(divFormError).css({
			top:callerTopPosition,
			left:callerleftPosition,
			opacity:0
		})
		$(divFormError).fadeTo("fast",1.0);
	};
	var updatePromptText = function(caller,promptText) {	// UPDATE TEXT ERROR IF AN ERROR IS ALREADY DISPLAYED
		updateThisPrompt =  $(caller).attr("id")
		$("."+updateThisPrompt).find(".formErrorContent").html(promptText)
		
		callerTopPosition  = $(caller).offset().top;
		inputHeight = $("."+updateThisPrompt).height()
		
		callerTopPosition = callerTopPosition  -inputHeight -10
		$("."+updateThisPrompt).animate({
			top:callerTopPosition
		});
	}
	var loadValidation = function(caller) {		// GET VALIDATIONS TO BE EXECUTED
		
		rulesParsing = $(caller).attr('class');
		rulesRegExp = /\[(.*)\]/;
		getRules = rulesRegExp.exec(rulesParsing);
		str = getRules[1]
		pattern = /\W+/;
		result= str.split(pattern);	
		
		var validateCalll = validateCall(caller,result)
		return validateCalll
		
	};
	var validateCall = function(caller,rules) {	// EXECUTE VALIDATION REQUIRED BY THE USER FOR THIS FIELD
		var promptText =""	
		var prompt = $(caller).attr("id");
		var caller = caller;
		var callerName = $(caller).attr("name");
		isError = false;
		callerType = $(caller).attr("type");
		
		for (i=0; i<rules.length;i++){
			
			switch (rules[i]){
			case "optional": 
				if(!$(caller).val()){
					closePrompt(caller)
					return isError
				}
			break;
			case "required": 
				 if(isError == false)
					_required(caller,rules);
			
			break;
			case "custom":
				 if(isError == false)
					 _customRegex(caller,rules,i);
			break;
			case "length": 
				if(isError == false)
					_length(caller,rules,i);
			break;
            case "maxlength":
            	if(isError == false)
				 _maxlength(caller,rules,i);
			break;
			case "minCheckbox":
				if(isError == false) 
				 _minCheckbox(caller,rules,i);
			break;
			case "confirm": 
				if(isError == false)
				 _confirm(caller,rules,i);
			break;
            case "card":
            	if(isError == false)
                    _card(caller,rules,i);
            break;
			default :;
			};
		};
		
		if (isError == true){
			var showTriangle = true
			if($("input[name="+callerName+"]").size()> 1 && callerType == "radio") {		// Hack for radio group button, the validation go the first radio
				caller = $("input[name="+callerName+"]:first")
				showTriangle = false
				var callerId ="."+ $(caller).attr("id")
				if($(callerId).size()==0){ isError = true }else{ isError = false}
			}
			if($("input[name="+callerName+"]").size()> 1 && callerType == "checkbox") {		// Hack for radio group button, the validation go the first radio
				caller = $("input[name="+callerName+"]:first")
				showTriangle = false
				var callerId ="div."+ $(caller).attr("id")
				if($(callerId).size()==0){ isError = true }else{ isError = false}
			}
			if (isError == true){ // show only one
			
				($("div."+prompt).size() ==0) ? buildPrompt(caller,promptText,showTriangle)	: updatePromptText(caller,promptText)
			}
		}else{
			if($("input[name="+callerName+"]").size()> 1 && callerType == "radio") {		// Hack for radio group button, the validation go the first radio
				caller = $("input[name="+callerName+"]:first")
			}
			if($("input[name="+callerName+"]").size()> 1 && callerType == "checkbox") {		// Hack for radio group button, the validation go the first radio
				caller = $("input[name="+callerName+"]:first")
			}
			closePrompt(caller)
		}		
		
		/* VALIDATION FUNCTIONS */
		function _required(caller,rules){   // VALIDATE BLANK FIELD
			callerType = $(caller).attr("type")
		
			if (callerType == "text" || callerType == "password" || callerType == "textarea" || callerType == "file"){
				
				if(!$(caller).val()){
					isError = true;
					promptText += settings.allrules[rules[i]].alertText+"<br />"
				}	
			}
			if (callerType == "radio" || callerType == "checkbox" ){
				callerName = $(caller).attr("name")
		
				if($("input[name="+callerName+"]:checked").size() == 0) {
					isError = true
					if($("input[name="+callerName+"]").size() ==1) {
						promptText += settings.allrules[rules[i]].alertTextCheckboxe+"<br />" 
					}else{
						 promptText += settings.allrules[rules[i]].alertTextCheckboxMultiple+"<br />"
					}	
				}
			}	
			if (callerType == "select-one") { // added by paul@kinetek.net for select boxes, Thank you
					callerName = $(caller).attr("id");
				
				if(!$("select[name="+callerName+"]").val()) {
					isError = true;
					promptText += settings.allrules[rules[i]].alertText+"<br />";
				}
			}
			if (callerType == "select-multiple") { // added by paul@kinetek.net for select boxes, Thank you
					callerName = $(caller).attr("id");
				
				if(!$("#"+callerName).val()) {
					isError = true;
					promptText += settings.allrules[rules[i]].alertText+"<br />";
				}
			}
		}
        function _customRegex(caller,rules,position)
        { // VALIDATE REGEX RULES
            var customRule = rules[position+1]
            var pattern = eval(settings.allrules[customRule].regex)
            
            if($.browser.msie && rules == 'required,custom,imageType')
            { 
                var pattern = new RegExp("^.+\.((jpg)|(gif)|(jpeg))$");
                if(!pattern.test($(caller).attr('value')))
                {
                    isError = true
                    promptText += settings.allrules[customRule].alertText+"<br />"
                }
            }
            else
            {
                if(!pattern.test($(caller).attr('value')))
                {
                    isError = true
                    promptText += settings.allrules[customRule].alertText+"<br />"
                }
            }
        }
		//function _customRegex(caller,rules,position){		 // VALIDATE REGEX RULES
//			customRule = rules[position+1]
//			pattern = eval(settings.allrules[customRule].regex)
//			
//			if(!pattern.test($(caller).attr('value'))){
//				isError = true
//				promptText += settings.allrules[customRule].alertText+"<br />"
//			}
//		}
		function _confirm(caller,rules,position){		 // VALIDATE FIELD MATCH
			confirmField = rules[position+1]
			
			if($(caller).attr('value') != $("#"+confirmField).attr('value')){  
				isError = true
				if(confirmField == 'password')
					promptText += "Passwords must match<br />"
				else
					promptText += settings.allrules["confirm"].alertText+"<br />"
			}
		}
		function _length(caller,rules,position){    // VALIDATE LENGTH
		
			startLength = eval(rules[position+1])
			endLength = eval(rules[position+2])
			feildLength = $(caller).attr('value').length

			if(feildLength<startLength || feildLength>endLength){
				isError = true
				promptText += settings.allrules["length"].alertText+startLength+settings.allrules["length"].alertText2+endLength+settings.allrules["length"].alertText3+"<br />"
			}
		}
        function _maxlength(caller,rules,position){
        // VALIDATE MAXLENGTH
			actualLength = eval(rules[position+1])
			feildLength = $(caller).attr('value').length
			if(feildLength>actualLength ){
				isError = true
				promptText += settings.allrules["maxlength"].alertText+actualLength+settings.allrules["maxlength"].alertText2+"<br />"
			}
		}
        function _card(caller,rules,position){
            cardNumber = $(document.getElementById(rules[position+1])).attr('value')
            if($('input[name='+rules[position+2]+']:checked').val()==undefined){
                isError = true
                promptText += '* Please Select a card<br />'
            }else{
                cardName=$('input[name='+rules[position+2]+']:checked').val()
                if(!valid_card(cardNumber,cardName)){
                    isError = true
                    promptText += settings.allrules["card"].alertText+cardName+settings.allrules["card"].alertText1+"<br />"
                }
            }
        }
		function _minCheckbox(caller,rules,position){    // VALIDATE CHECKBOX NUMBER
		
			nbCheck = eval(rules[position+1])
			groupname = $(caller).attr("name")
			groupSize = $("input[name="+groupname+"]:checked").size()
			
			if(groupSize > nbCheck){	
				isError = true
				promptText += settings.allrules["minCheckbox"].alertText+"<br />"
			}
		}
        function valid_card(value,  param) {
            var cardName = param;

            var cards = new Array();
            cards [0] = {cardName: "Visa", lengths: "13,16", prefixes: "4", checkdigit: true};
            cards [1] = {cardName: "MasterCard", lengths: "16", prefixes: "51,52,53,54,55", checkdigit: true};
            cards [2] = {cardName: "DinersClub", lengths: "14,16", prefixes: "300,301,302,303,304,305,36,38,55", checkdigit: true};
            cards [3] = {cardName: "CarteBlanche", lengths: "14", prefixes: "300,301,302,303,304,305,36,38", checkdigit: true};
            cards [4] = {cardName: "AmEx", lengths: "15", prefixes: "34,37", checkdigit: true};
            cards [5] = {cardName: "Discover", lengths: "16", prefixes: "6011,650", checkdigit: true};
            cards [6] = {cardName: "JCB", lengths: "15,16", prefixes: "3,1800,2131", checkdigit: true};
            cards [7] = {cardName: "enRoute", lengths: "15", prefixes: "2014,2149", checkdigit: true};
            cards [8] = {cardName: "Solo", lengths: "16,18,19", prefixes: "6334, 6767", checkdigit: true};
            cards [9] = {cardName: "Switch", lengths: "16,18,19", prefixes: "4903,4905,4911,4936,564182,633110,6333,6759", checkdigit: true};
            cards [10] = {cardName: "Maestro", lengths: "16,18", prefixes: "5020,6", checkdigit: true};
            cards [11] = {cardName: "VisaElectron", lengths: "16", prefixes: "417500,4917,4913", checkdigit: true};

            var cardType = -1;
            for (var i=0; i<cards.length; i++) {
                    if (cardName.toLowerCase() == cards[i].cardName.toLowerCase()) {
                            cardType = i;
                            break;
                    }
            }
            if (cardType == -1) { return false; } // card type not found

            value = value.replace (/[\s-]/g, ""); // remove spaces and dashes
            if (value.length == 0) { return false; } // no length

            var cardNo = value;
            var cardexp = /^[0-9]{13,19}$/;
            if (!cardexp.exec(cardNo)) { return false; } // has chars or wrong length

            cardNo = cardNo.replace(/\D/g, ""); // strip down to digits

            if (cards[cardType].checkdigit){
                    var checksum = 0;
                    var mychar = "";
                    var j = 1;

                    var calc;
                    for (i = cardNo.length - 1; i >= 0; i--) {
                            calc = Number(cardNo.charAt(i)) * j;
                            if (calc > 9) {
                                    checksum = checksum + 1;
                                    calc = calc - 10;
                            }
                            checksum = checksum + calc;
                            if (j ==1) {j = 2} else {j = 1};
                    }

                    if (checksum % 10 != 0) { return false; } // not mod10
            }

            var lengthValid = false;
            var prefixValid = false;
            var prefix = new Array ();
            var lengths = new Array ();

            prefix = cards[cardType].prefixes.split(",");
            for (i=0; i<prefix.length; i++) {
                    var exp = new RegExp ("^" + prefix[i]);
                    if (exp.test (cardNo)) prefixValid = true;
            }
            if (!prefixValid) { return false; } // invalid prefix

            lengths = cards[cardType].lengths.split(",");
            for (j=0; j<lengths.length; j++) {
                    if (cardNo.length == lengths[j]) lengthValid = true;
            }
            if (!lengthValid) { return false; } // wrong length

            return true;
        }
return(isError) ? isError : false;
	};
	var closePrompt = function(caller) {	// CLOSE PROMPT WHEN ERROR CORRECTED
		closingPrompt = $(caller).attr("id")

		$("."+closingPrompt).fadeTo("fast",0,function(){
			$("."+closingPrompt).remove()
		});
	};
	var submitValidation = function(caller) {	// FORM SUBMIT VALIDATION LOOPING INLINE VALIDATION
		var stopForm = false
		$(caller).find(".formError").remove()
		var toValidateSize = $(caller).find("[class^=validate]").size()
		
		$(caller).find("[class^=validate]").each(function(){
			var validationPass = loadValidation(this)
			return(validationPass) ? stopForm = true : "";	
		});
		if(stopForm){							// GET IF THERE IS AN ERROR OR NOT FROM THIS VALIDATION FUNCTIONS
			destination = $(".formError:first").offset().top;
			$("html:not(:animated),body:not(:animated)").animate({ scrollTop: destination}, 1100)
			return true;
		}else{
			return false
		}
	};

};
function closePrompt(caller,outside)
{ // CLOSE PROMPT WHEN ERROR CORRECTED
    if(outside)
    {
        $(caller).fadeTo("fast",0,function(){
        $(caller).remove();
        });
        return false;
    }
}
