/*jslint strict:true, evil: true, onevar: true, nomen: false  */ /*global $, jQuery, console, hbx, window, ndm, document, each  */

"use strict";

/*
    Function: jQuery.fn.CG_validate
    Form validation for cases where there is more than one form on the screen
    The form object itself is passed to the validator by id or class
*/

var CG_ajaxFormValid = true,
    CG_ajaxform_posted = false;

jQuery.fn.CG_validator = function(options) {
	var zForm = this;
    $(this).each(function(){
        var validOptions = jQuery.extend({
            errorElement:"span",
            errorClass:"error",
				errorParentClass: "error-wrapper",
				errorsPanel: null,
				defaultRequiredMessage: "[field] is required",
				requiredAfterSubmit: true,
				submitAttempted: false,
            ajaxSubmit:false,
				mapEnterToTab: false,
				transitionTime: 200,
				useKeyUpTrigger: false,
				submitCallback: null
            },options||{}),

            formValid = true,

            CG_checkAlpha = function(fieldObj){

            },

            CG_checkDecimal = function(fieldObj){
                /*  Rules - must be only numbers and one single dot
                    Dot can't be at beginning
                */
                var fieldVal = $(fieldObj).val(),
                    dotSegs = fieldVal.split(".");

                if((parseInt($(fieldObj).val(),10) || $(fieldObj).val() < 1) && dotSegs.length < 3){
                    return true;
                }else{
                    return false;
                }
            },
            
           CG_checkDigits = function(fieldObj){
                var fieldVal = $(fieldObj).val();
                var digitPattern = /^[\d\._]+?$/;
                if(digitPattern.test(fieldVal)){
                    return true;
                }else{
                    return false;
                }
            },


            CG_checkEmail = function(fieldObj){
                /*  Rules - must have an @ and a dot
                    Dot can't be at end, @ can't be at beginning
                */

					/* New rules: +*?@+*?\.+*? */
                var fieldVal = $(fieldObj).val();
					 var emailPattern = /[\w\d\._-]+?@[\w\d\.-_]+?\.[\w\d\.-_]+?/;
//                if(fieldVal.indexOf("@") !== -1 && fieldVal.indexOf(".") !== -1 && fieldVal.substring(0,1)!== "@" && fieldVal.substring(fieldVal.length-1)!== "."){
                if(emailPattern.test(fieldVal)) {
                    return true;
                }else{
                    return false;
                }
            },

            CG_checkMoney = function(fieldObj){
                /*  Rules
                    If it has a dot it must be followed by 2 numbers
                    Dot can't be at beginning
                */
                var fieldVal = $(fieldObj).val(),
                    dollarSegs = fieldVal.split("."),
                    validDot = true;

                if(dollarSegs.length === 2 && dollarSegs[1].length !== 2){
                    validDot = false;
                }

                if(parseFloat($(fieldObj).val()) !== "NaN" && dollarSegs[0].length > 0 && validDot){
                    return true;
                }else{
                    return false;
                }
            },

				CG_checkABN = function(fieldObj) {
					/* ABNs consist of 11 digits.
					 * Validation here is to remove all non digit characters and the
					 * check for 11 digits */

					var ABNPattern = /\d{11}/;
					var fieldVal = $(fieldObj).val();
					//We need to strip non digits here
					fieldVal = fieldVal.replace(/\D*/g,"");
					
					if(ABNPattern.test(fieldVal)) {
						$(fieldObj).val(fieldVal);
						//if the validation is good, repopulate the field with only the numbers
						return true;
					} else {
						return false;
					}
				},

            CG_checkPhone = function(fieldObj){
                /*  Rules supplied by Drive  */
                var fieldVal = $(fieldObj).val();
					fieldVal = fieldVal.replace(/\D*/g,"");

					 /* This is being updated to allow for sales force rules.
					  * Sales for rules are effectively 'must be ten digits.'
					  * We are being slightly more specific to match area codes. */
                var AusLndlnePtrn = /^0([2,3,7,8,4,9])(\d{8})$/;

                if(!AusLndlnePtrn.test(fieldVal)){
                    return false;
                }else{
						 $(fieldObj).val(fieldVal);
                    return true;
                }
            },

            CG_checkSelect = function(fieldObj){
                var fieldVal = $(fieldObj).val();
                if(fieldVal === "" || fieldVal === "--"){
                    return false;
                }else{
                    return true;
                }
            },

            CG_checkLengthMin = function(fieldObj,minLength){
                if($(fieldObj).val().length < minLength){
                    return false;
                }else{
                    return true;
                }
            },

            CG_checkLengthMax = function(fieldObj,maxLength){
                if($(fieldObj).val().length > maxLength){
                    return false;
                }else{
                    return true;
                }
            },

            CG_checkRequired = function(fieldObj){
					var $field = $(fieldObj);
                if(
							 ($field.attr("type") != "checkbox" && $field.val() !== "") ||
							 ($field.attr("type") == "checkbox" && $field.is(":checked"))
						){
                    return true;
                } else {
                    return false;
                }
            },

            CG_checkNotZero = function(fieldObj){
                if(parseFloat($(fieldObj).val()) !== 0){
                    return true;
                }else{
                    return false;
                }
            },

				CG_checkState = function(fieldObj) {
					/* Checks for a valid (australian) state entry. */

					var fieldVal = $(fieldObj).val().toUppercase();
					var statePattern = /^[NSW|QLD|VIC|WA|TAS|NT|SA|ACT]$/;

					if(statePattern.test(fieldVal)) {
						return true;
					} else {
						return false;
					}

				},

				CG_checkFilled = function (fieldObj) {
//					console.info("Checking filled");
					var val = $(fieldObj).val();
					if(val != null && val.match(/.+/)) {
//						console.info("It contains something");
					}
					return false;
				},

				CG_checkOther = function (fieldObj) {
					/* This checks the validity of another field 
					 * if the provided field contains the right value */

					var fieldVal = $(fieldObj).val();
					var condition = $(fieldObj).attr("data-require-condition");
					var target = $(fieldObj).attr("data-require-target");
					var hiding = $(fieldObj).attr("data-other-hiding");
					if(fieldVal == condition) {
						$(target).attr("data-required",true);
						CG_checkFieldValidInline($(target));
						if(hiding && hiding != "") {
							$(hiding).show(validOptions.transitionTime);
						}
						return true;
					} else {
						$(target).attr("data-required",false);
						//If the initial condition isn't set then 
						//this setting passes
						if(hiding && hiding != "") {
							$(hiding).hide(validOptions.transitionTime);
						}
						CG_checkFieldValidInline($(target));
						return true;
					}
				},

				CG_checkExcludeCharacter = function (fieldObj) {
					var fieldVal = $(fieldObj).val();
					var condition = $(fieldObj).attr("data-valid-condition");

					if(fieldVal.indexOf(condition) == -1) {
						return true;
					} else {
						return false; 
					}
				},

            CG_showInlineError = function(fieldObj,errTyp){
                //Check if an error already exists
					 
					 
                var messages = validOptions.messages;
					 var msgTxt = errTyp;
					 var fieldId = fieldObj.attr("id");
					 var msgDef = messages[fieldId];
                
					 var labelObj = $(fieldObj).parent();
					 var errId = null;
                var errorObjs = $(labelObj).find(validOptions.errorElement+"."+validOptions.errorClass);

                if(msgDef !== "NULL" && msgDef != undefined){
                    if(typeof(msgDef) === "string"){
                        msgTxt = msgDef;
                    }else{
                        if(msgDef[errTyp] !== "NULL" && msgDef[errTyp] != undefined){
									errId = fieldId+"-"+errTyp;
									msgTxt = msgDef[errTyp];
                        }
                    }
                } else if(errTyp == "required") {
						 var label = $("label[for='"+fieldId+"']").text();
						 if(label != "") {
							 label = label.replace(":","").toLowerCase();
							 errId = fieldId+"-"+errTyp;
							 msgTxt = validOptions.defaultRequiredMessage.replace("[field]",label);
						 }
					 }

                if(errorObjs.length > 0){
                    errorObjs.eq(0).text(msgTxt);
                }else{

						 $(labelObj).addClass(validOptions.errorParentClass);
						 var append = $('<'+validOptions.errorElement+' >'+msgTxt+'</'+validOptions.errorElement+'>');
						 $(append).addClass(validOptions.errorClass);
						 $(append).prop("id","field-error-"+fieldId);

                    $(labelObj).append(append);
                }

					 //If there is an errors panel we should add this message to it.
					 CG_addError(errId,msgTxt);
            },

				CG_removeError = function (errId) {
					if(!validOptions.errorsPanel) { return false; }
					var errorPanel = $(validOptions.errorsPanel);

					errorPanel.find("."+errId).remove();

					if(errorPanel.find(".error").length == 0) {
						errorPanel.hide(300);
					}
				},

				CG_addError = function (errId,errMessage) {
					//make sure we are operating on something that exists.
					if(!validOptions.errorsPanel) { return false; }
					var errorPanel = $(validOptions.errorsPanel);
					if(errorPanel.children(".errorlist").length == 0) {
						CG_setupErrorList();
					}

					var errorList = errorPanel.children(".errorlist");

					if(errorList.children("."+errId).length == 0) {
						$("<li class='"+errId+" error'>"+errMessage+"</li>").appendTo(errorList);
					}

					errorPanel.show(300,"swing");
					//errorPanel.show("slide",{},2000);

				},

				CG_clearErrors = function () {
					$(validOptions.errorsPanel).children(".errorlist").remove();
				},

				CG_setupErrorList = function () {
					$("<ul class='errorlist'>").appendTo($(validOptions.errorsPanel));
				},

            CG_checkFieldValidInline = function(fieldObj){
					/* I want to migrate this function away from using 
					 * 'itype', 'required' etc. The newer HTML5 standards
					 * allow for any 'data-' field as a valid html attribute.
					 * We need to move towards this where we can.
					 */
					 //'data-validation' is a replacement for 'itype'
					 //'data-required' is a replacement for 'required'
                    var fieldReq = $(fieldObj).attr("required") || $(fieldObj).attr("data-required"),
                    fieldMin = $(fieldObj).attr("minlength"),
                    fieldMax = $(fieldObj).attr("maxfldlength"),
                    fieldZero = $(fieldObj).attr("zeroallowed"),
                    fieldValid = true;
							var fieldTyp = $(fieldObj).attr("itype") || $(fieldObj).attr("data-validation");
							var fieldId = fieldObj.attr("id");

							if($(fieldObj).attr("data-ignore") == true || $(fieldObj).attr("disabled") == true) {
								return null;
							}
						//data-require-other contains the name of the field
						//That is required. in this case data-validation needs to be
						//'other'
						//fieldOther = $(fieldObj).attr("data-require-target"),
						//This should be used to specify the condition for the required target.
						//fieldTarget = $(fieldObj).attr("data-require-condition"),


                if((fieldReq === "true") && (!validOptions.requiredAfterSubmit || (validOptions.submitAttempted && validOptions.requiredAfterSubmit))){
                    fieldValid = CG_checkRequired(fieldObj);
                    if(!fieldValid){ CG_showInlineError($(fieldObj),"required"); return false; }
						  else {CG_removeError(fieldId+"-required"); }
                }

                if(fieldMin !== ""){
                    fieldValid = CG_checkLengthMin(fieldObj,fieldMin);
                    if(!fieldValid){ CG_showInlineError($(fieldObj),"minlength"); return false; }
						  else {CG_removeError(fieldId+"-minlength"); }
                }

                if(fieldMax !== ""){
                    fieldValid = CG_checkLengthMax(fieldObj,fieldMax);
                    if(!fieldValid){ CG_showInlineError($(fieldObj),"maxfldlength"); return false; }
						  else {CG_removeError(fieldId+"-maxfldlength"); }
                }

                if(fieldZero === "false"){
                    fieldValid = CG_checkNotZero(fieldObj);
                    if(!fieldValid){ CG_showInlineError($(fieldObj),"zeroallowed"); return false; }
						  else {CG_removeError(fieldId+"-zeroallowed"); }
                }


                if(fieldReq === "true" || $(fieldObj).val() !== ""){
						 fieldValid = CG_runChecks(fieldObj);
						 if(fieldValid) {
							 CG_removeError(fieldId+"-"+fieldTyp);
						 }
                }

                if(fieldValid){
						 $(fieldObj).parent().removeClass(validOptions.errorParentClass);
						 //This has been refactor to used ids so that it is -specific- to the particular
						 //error element we want to remove.\
						 $("#field-error-"+fieldId).remove();
                }
                return fieldValid;
            },

				//I've refactored the validation method to extract this portion.
				//This is because this is now needed to be re-run by the new CG_checkOther
				//method but without the 'required' check which is dictated by an external
				//value.
				CG_runChecks = function(fieldObj, forceType) {
					var fieldTyp = forceType;
					if(!forceType) {
						fieldTyp = $(fieldObj).attr("itype") || $(fieldObj).attr("data-validation");
					}
					var fieldValid = true;

					switch(fieldTyp){
						case "require": 
							fieldValid = CG_checkFilled(fieldObj);
							if(!fieldValid) { CG_showInlineError($(fieldObj), fieldTyp); }
							break;
						case "alpha":
							fieldValid = CG_checkAlpha(fieldObj);
							if(!fieldValid){ CG_showInlineError($(fieldObj),fieldTyp); }
							break;
						case "digits":
							  fieldValid = CG_checkDigits(fieldObj);
							  if(!fieldValid){ CG_showInlineError($(fieldObj),fieldTyp); }
							  break;
						 case "decimal":
							  fieldValid = CG_checkDecimal(fieldObj);
							  if(!fieldValid){ CG_showInlineError($(fieldObj),fieldTyp); }
							  break;
						 case "email":
							  fieldValid = CG_checkEmail(fieldObj);
							  if(!fieldValid){ CG_showInlineError($(fieldObj),fieldTyp); }
							  break;
						 case "money":
							  fieldValid = CG_checkMoney(fieldObj);
							  if(!fieldValid){ CG_showInlineError($(fieldObj),fieldTyp); }
							  break;
						 case "phone":
							  fieldValid = CG_checkPhone(fieldObj);
							  if(!fieldValid){ CG_showInlineError($(fieldObj),fieldTyp); }
							  break;
						 case "select":
							  fieldValid = CG_checkSelect(fieldObj);
							  if(!fieldValid){ CG_showInlineError($(fieldObj),fieldTyp); }
							  break;
						 case "abn":
							  fieldValid = CG_checkABN(fieldObj);
							  if(!fieldValid){ CG_showInlineError($(fieldObj),fieldTyp); }
							  break;
						 case "au_state":
							  fieldValid = CG_checkState(fieldObj);
							  if(!fieldValid) { CG_showInlineError($(fieldObj),fieldTyp); }
							  break;
						 case "exclude":
							  fieldValid = CG_checkExcludeCharacter(fieldObj);
							  if(!fieldValid) { CG_showInlineError($(fieldObj),fieldTyp); }
							  break;
						 case "other":
							  //This check will be different from the others above...?
							  //This checks to see if another field has been provided, 
							  //this is based on a condition on this field.
							  //
							  fieldValid = CG_checkOther(fieldObj);
							  if(!fieldValid) { CG_showInlineError($(fieldObj),fieldTyp); }
							  break;
						 default:
							  break;
					}

					return fieldValid;
	 			},
					 
            CG_checkForErrorsOnSubmit = function(formObj){
					CG_clearErrors();
                var errorsFound = false,
                    formFields = $(formObj).find(":input");

                $(formFields).each(function(){
						 var valid = CG_checkFieldValidInline($(this))
                    if(valid == false){
                        errorsFound = true;
                    }
                });
                if(errorsFound){
                    return false;
                }else{
                    return true;
                }
            },

            rules = validOptions.rules;

        //Handle the submit
        $(this).submit(function(){
			  validOptions.submitAttempted = true;
            //Check all the fields are valid and only submit if OK
            if(validOptions.ajaxSubmit){
                CG_ajaxFormValid = CG_checkForErrorsOnSubmit($(this));
					 $(document).scrollTop(50);
                return false;
            }else{
                if(!CG_checkForErrorsOnSubmit($(this))) {
                    $(document).scrollTop(50);
                    return false;
                } else {
                    if(validOptions.submitCallback) {
                        return validOptions.submitCallback();
                    }
                  return true;
                }
            }
        });

		  //This is a replacement for the 'rules' option.
		  //This will automatically scan all form input elements
		  //including text area etc and read their attributes for 
		  //errors.
		  $(zForm).find(":input").each(function (count,el) {
			  var $el = $(el);
				if(validOptions.useKeyUpTrigger) {
				  $el.keyup(function () {
					  CG_checkFieldValidInline($(this));
				  });
				}
				if(validOptions.mapEnterToTab) {
					$el.keyup(function(e) {
						if(e.keyCode == 13) {
							$(this).next('input').focus();
							return false;
						}
					});
				}



				if($el.attr("type") == "checkbox") {
					$el.click(function() {
						CG_checkFieldValidInline($(this));
					});
				} else {
					$el.change(function(){
					CG_checkFieldValidInline($(this));
					});
				}
		  });

		  //Make sure the errors panel (if it exists) is hidden.
		  var ePanel = validOptions.errorsPanel;
		  if(ePanel) {
			  $(ePanel).hide();
				if($(ePanel).children(".error-list")) {
				}
		  }

		  //This will execute when the plugin is attached to a form element.
        //Use the rules and the messages to determine the errors
        jQuery.each(rules,function(fieldID,fieldRules){
				//Probably need to check here that the element
				//we are attaching to is a form element...

			  //Here I want an alternative approach. Which is to look up each
			  //sub form element (input, textarea, select, checkbox, radio etc)
			  //and to extract the rules from the data- elements.
			  
			  //Selects all 'form' elements that are in this form.

            //Loop through the fieldRules and apply the events to the field object
            $("#"+fieldID).eq(0).attr({
                "required":"false",
                "minlength":"",
                "maxfldlength":"",
                "zeroallowed":"true",
                "itype":""
            });

            jQuery.each(fieldRules,function(ruleID,ruleVal){
                switch(ruleID){
                    case "required":
                        $("#"+fieldID).attr("required",ruleVal);
                        break;
                    case "minlength":
                        $("#"+fieldID).attr("minlength",ruleVal);
                        break;
                    case "maxlength":
                        $("#"+fieldID).attr("maxfldlength",ruleVal);
                        break;
                    case "zeroallowed":
                        $("#"+fieldID).attr("zeroallowed",ruleVal);
                        break;
                    case "digits":
                        $("#"+fieldID).attr("itype","digits");
                        break;
                    case "decimal":
                        $("#"+fieldID).attr("itype","decimal");
                        break;
                    case "alpha":
                        $("#"+fieldID).attr("itype","alpha");
                        break;
                    case "email":
                        $("#"+fieldID).attr("itype","email");
                        break;
                    case "money":
                        $("#"+fieldID).attr("itype","money");
                        break;
                    case "phone":
                        $("#"+fieldID).attr("itype","phone");
                        break;
                    case "select":
                        $("#"+fieldID).attr("itype","select");
                        break;
                }
            });

            $("#"+fieldID).blur(function(){
                CG_checkFieldValidInline($(this));
            });
        });
    });
};


