/*
 
 -----------------------------------------
   Validation.js
 -----------------------------------------

 * @version 0.1
 * @author LBi - http://www.lbi.com/en
 * @requires jQuery Core 1.3.2 - http://www.jquery.com/
 * @requires jQuery Validation plugin 1.5.1 - http://plugins.jquery.com/project/validate

*/

/*jslint eqeqeq: true, undef: true */
/*global $, jQuery, BTT, window, document, swfobject, confirm, prompt  */


/**
 * BT Tradespace validation functions
 * @namespace BT Tradespace validation functions
 * @member BTT
 */



BTT.Validation = {

	
	// A list of all validation rules	
	rules: [
		
		/*Format:
			[
				0.	"Validation class name",
				1.	{ Rules for validation class },  // These are defined in the jQuery.Validate plugin & custom rules at end of document
				2.	({ Optional error messages for each specific rule })
			]
		*/
		
		
		// Generic required field
		[".VAL_required", {
			required: true
		}, {
			required: BTT.Messages.Validation.required
		}],
		
		// Email
		["input.VAL_email", {
			required: true,
			email: true
		}, {
			required: BTT.Messages.Validation.required,
			email: BTT.Messages.Validation.email
		}],
		
		// Email
		["input.VAL_emailNotRequired", {
			email: true
		}, {
			email: BTT.Messages.Validation.email
		}],
		
		// Verify email
		["input.VAL_verifyEmail", {
			required: true,
			email: true,
			equalTo: "input.VAL_email"
		}, {
			equalTo: BTT.Messages.Validation.verifyEmail
		}],
		
		// Old email
		["input.VAL_oldEmail", {
			required: true,
			email: true
		}, {
			required: BTT.Messages.Validation.email
		}],

		// Phone
		["input.VAL_phone", {
			required: true,
			phone: true
		}, {
			required: BTT.Messages.Validation.required,
			phone: BTT.Messages.Validation.phone
		}],

		// Phone not required
		["input.VAL_phoneNotRequired", {
			phone: true
		}, {
			phone: BTT.Messages.Validation.phone
		}],


		// Image
		["input.VAL_image", {
			accept: "tiff?|png|jpe?g|gif|bmp"
		}],

		// Media
		["input.VAL_media", {
			required: true,
			accept: "tiff?|png|jpe?g|gif|bmp|avi|dv|mov|qt|mpg|mpe?g2|mpeg4|mp4|3gp|3g2|asf|wmv|flv"
		}, {
			required: BTT.Messages.Validation.media,
			accept: BTT.Messages.Validation.accept
		}],

		// Number
		["input.VAL_number", {
			number: true
		}],
		
		// Required number
		["input.VAL_requiredNumber", {
			required: true,
			number: true
		}, {
			required: BTT.Messages.Validation.required
		}],		
		
		// Integer
		["input.VAL_integer", {
			digits: true
		}],	
		
		// Required integer
		["input.VAL_requiredInteger", {
			required: true,
			digits: true
		}, {
			required: BTT.Messages.Validation.required
		}],	
		
		// Domain
		["input.VAL_domain", {
			required: true,
			validDomainChars: true,
			checkDomainName: true // Remote check for domain name availability
		}, {
			required: BTT.Messages.Validation.required,
			validDomainChars: BTT.Messages.Validation.validChars,
			checkDomainName: BTT.Messages.Validation.checkDomainName
		}],
		
		// Password
		[".VAL_password", {
			required: true,
			checkPassword: true
		}, {
			required: BTT.Messages.Validation.required,
			checkPassword: BTT.Messages.Validation.password
		}],
		
		// Verify Password
		["input.VAL_verifyPassword", {
			required: true,
			equalTo: "input.VAL_password"
		}],
		
		// Display name
		["input.VAL_displayName", {
			required: true,
			checkDisplayName: true // Remote check for display name availability
		}, {
			required: BTT.Messages.Validation.required,
			checkDisplayName: BTT.Messages.Validation.checkDisplayName
		}],
		
		// PostCode
		["input.VAL_postCode", {
			required: true,
			checkPostCode: true
		}, {
			required: BTT.Messages.Validation.required,
			checkPostCode: BTT.Messages.Validation.postCode
		}],
		
		// Check Google analytics ID
		["input.VAL_googleAnalyticsId", {
			required: true,
			checkGoogleAnalytics: true
		}, {
			required: BTT.Messages.Validation.required,
			checkGoogleAnalytics: BTT.Messages.Validation.googleAnalyticsId
		}],

		// Required parent (returns false if a parent is checked)
		["input[class*=VAL_requiredChild(]", {
			required: function (el) {
				var classname = $(el).attr("class"),
					regexSelector1 = new RegExp(/VAL_requiredChild\(/g),
					regexSelector2 = new RegExp(/\).*/g),
					requiredName = (classname.replace(regexSelector1, "")).replace(regexSelector2, "");
				
				if ( $('.VAL_requiredParent(' + requiredName +')').attr("checked") ) {
					return false;
				} else {
					return true;
				}
			}
		}, {
			required: BTT.Messages.Validation.required
		}],
		
		// Date of birth
		["input.VAL_date", {
			dateCheck: true
		}, {
			dateCheck: BTT.Messages.Validation.dateCheck
		}],

		// Quantity
		["input.VAL_quantity", {
			required: true,
			min: 1
		}, {
			required: BTT.Messages.Validation.required,
			min: BTT.Messages.Validation.quantity
		}],
		
		//Keyword
		["input.VAL_keyword", {
			required: true,
			maxlength: 150
		}, {
			required: BTT.Messages.Validation.keyword,
			maxlength: BTT.Messages.Validation.maxLength
		}],

		//Keyword
		["input.VAL_keywordNotRequired", {
			maxlength: 150
		}, {
			maxlength: BTT.Messages.Validation.maxLength
		}],

		//Title
		["input.VAL_title", {
			required: true,
			maxlength: 150
		}, {
			required: BTT.Messages.Validation.required,
			maxlength: BTT.Messages.Validation.maxLength
		}],

		//Checkboxes set
		["input.VAL_checkboxesSet", {
			required:true,
			minlength: 1
		}, {
			required: BTT.Messages.Validation.checkboxSet
		}]

	],	
	
	// Returns a list of all rule definitions in a format required by the Validation plugin
	//   This format is: { HTML element name: { list of rules for that element } }
	ruleSet: function(){
		
		var tempRules = {};
		
		for (var rule in BTT.Validation.rules) {
			var	ruleClass = BTT.Validation.rules[rule][0],
				ruleSpecs = BTT.Validation.rules[rule][1];
			
			$(ruleClass).each(function() {
				
				if($(this).attr("name")) {
					tempRules[$(this).attr("name")] = ruleSpecs;
				} 
				
			});
		}
	
		return(tempRules);
	},


	// Returns a list of all message definitions in a format required by the Validation plugin
	//   This format is: { HTML element name: { list of message for each rule definition for that element } }
	messageSet: function(){
		var tempMessages = {};
		for (var rule in BTT.Validation.rules) {
			var	ruleClass = BTT.Validation.rules[rule][0],
				ruleSpecs = BTT.Validation.rules[rule][1],
				ruleMessages = BTT.Validation.rules[rule][2];
			
			$(ruleClass).each(function(){
				
				if($(this).attr("name")) {
					tempMessages[$(this).attr("name")] = ruleMessages;
				} 
				
			});
		}

		return(tempMessages);
	},


	// Validation functions
	init: function() {
		var formToValidate = "form.JS_validateForm",
			defaultSubmitButton = '<input type="submit" id="decoySubmit" style="display:none;" />',
			JS_formElement = ".JS_formElement",
			formElementErrorClass = "formError",
			tabsParent = ".JS_tabsParent",
			tabsPanes = ".JS_tabsChild",
			groupPanes = ".JS_groupPane",
			outstandingLabels = ".JS_outstandingLabel",
			tabsErrorList = [];
		// Insert a decoy submit button to ensure form always validates	on form submit
			// JH: Needs to be 'prepend', 'append' causes page to submit even when errors are found
			// This form button becomes the default submit button on page when a form is submitted,
			// it doesn't have the 'cancel' class on it which otherwise allows submission of a form
		$(formToValidate).prepend(defaultSubmitButton);

		
		// Run the validation function
		$(formToValidate).each(function(){
			$(this).validate({
			
				// Allows use of rules such as '{validate:{required:true}'} inside the class attribute with metadata plugin
				meta: "validate",
		
				// Rules
				
				// accepts rules inside an object whose name equals the 'name' attribute
				// on input element to be validated
				rules: BTT.Validation.ruleSet(),
				
				// Messages
				messages: BTT.Validation.messageSet(),
				
				
				// Error panel related settings
				errorElement: "p",
				errorPlacement: function(error, element) {
					var currentElement = $(element);
					if (currentElement.hasClass('JS_uploadFile')) {
						currentElement = currentElement.closest('.buttonInputFile');
					}
					if (currentElement.siblings(".layoutAreaContextulInfo").length !== 1) {
						error
							.insertBefore( currentElement )
							.wrap("<div class='contentArea contentAreaInfoPanel contentAreaInfoPanelError'>")
							.parent()
							.wrap("<div class='layoutAreaContextulInfo'></div>");
					}
				},
				
							
				// Controls how error information is displayed, typically at top of page
				invalidHandler: function(form, validator) {
					
					
					// If the error summary doesn't exist, create it
					var errorMessage = BTT.Messages.Validation.commonError,
						errorContainer = $('<div/>')
							.addClass('contentArea')
							.addClass('contentAreaPanel')
							.addClass('contentAreaErrorPanel')
							.append($('<p/>')
								.addClass('textLarge')
							);
					
					
					// Only add the error panel once
					var existingErrorContainer = $(form.target).find(".contentAreaErrorPanel");
					if ( existingErrorContainer.length < 1 ) {
							$(form.target).prepend(errorContainer);
					}
					
					// If there are errors, show them
					if (validator.numberOfInvalids() > 0) {

						// If there is just 1 error, say so 
						if (validator.numberOfInvalids() === 1) {
							errorMessage = $.validator.format(errorMessage,validator.numberOfInvalids(),'');

						// If there is more than 1 error, say so
						} else {
							errorMessage = $.validator.format(errorMessage,validator.numberOfInvalids(),'s');
						}
						$(formToValidate + ' div.contentAreaErrorPanel')
							.hide()
							.slideDown(500, function() {
								//reposition the lightbox if the form is in it
								if (BTT.Lightboxes !== undefined) {
									if ($('.'+BTT.Lightboxes.classNames.lightboxActiveClass).length > 0) {
										BTT.Lightboxes.positionLightbox($('.'+BTT.Lightboxes.classNames.lightboxActiveClass), BTT.Lightboxes.lightboxParams.minWidth, false);
									}
								}
							});
						$('p:first',errorContainer).html(errorMessage);
					
					}	
					
				},
				
				
				showErrors: function(errorMap, errorList) {
					var errorMessage = BTT.Messages.Validation.commonError;

					if (this.numberOfInvalids() > 0) {
					// If there is just 1 error, say so 
						if (this.numberOfInvalids() === 1) {
							errorMessage = $.validator.format(errorMessage,this.numberOfInvalids(),'');

					// If there is more than 1 error, say so
						} else {
							errorMessage = $.validator.format(errorMessage,this.numberOfInvalids(),'s');
						}
						$('p:first','.contentAreaErrorPanel').html(errorMessage);
					}
			
					// If there are no errors, hide the error summary
					else {
						$(formToValidate + ' div.contentAreaErrorPanel')
							.slideUp(500, function() {
								//reposition the lightbox if the form is in it
								if (BTT.Lightboxes !== undefined) {
									if ($('.'+BTT.Lightboxes.classNames.lightboxActiveClass).length > 0) {
										BTT.Lightboxes.positionLightbox($('.'+BTT.Lightboxes.classNames.lightboxActiveClass), BTT.Lightboxes.lightboxParams.minWidth, false);
									}
								}
							});
					}
					this.defaultShowErrors();
				},
				
				
				// Control how to highlight an invalid field
				highlight: function (element, errorClass) {			

							
					// Remove successfully filled text
					$(element)
						.closest(JS_formElement)
						.find("span.successfullyCompletedField")
						.each(function(){
							$(this).remove();
						});
					
					// Apply error class
					$(element)
						.closest(JS_formElement)
						.addClass(formElementErrorClass);
	
					// Add error class to the outstanding label
					// check if the current element is inside of a groupPane
					if($(element).parents(groupPanes).length > 0){
						$(element).parents(groupPanes).siblings(outstandingLabels).addClass(formElementErrorClass);
					}

					// Add error class to tab heading
					// check if the current element is inside of a TabPane
					if($(element).parents(tabsPanes).length > 0){
						
						var highlightTab = $(element).parents(tabsPanes).attr("id");
						$('.JS_tabsParent ul li a[href="#' + highlightTab + '"]').parent().addClass(formElementErrorClass);
	
						//Create an tabs array which have have the error fields 
						tabsErrorList.push(highlightTab);							
						$('#tab_1').tabs('select', tabsErrorList[0].split("tabPane_")[1]);
					}

				},
				
				
				// Control how to un-highlight an invalid field
				unhighlight: function (element, errorClass) {
					
					// Remove error class
					$(element)
						.closest(JS_formElement)
						.removeClass(formElementErrorClass);

					// Remove error class from tab heading	
					if($(element).parents(tabsPanes).length > 0){
						
						var highlightTab = $(element).parents(tabsPanes).attr("id");
						$('.JS_tabsParent ul li a[href="#' + highlightTab + '"]').parent().removeClass(formElementErrorClass);
						// Clear the Tabs error list array
						tabsErrorList = [];
	
					}				
					
				},
					
				// Control what happens when a field becomes valid
				success: function (label) {
					
					var parentContainer = $(label).closest(JS_formElement),
						successMessage = $('<span />')
							.addClass('successfullyCompletedField')
							.html(BTT.Messages.Validation.success);

					// Remove error class from outstanding labels	
					if($(parentContainer).parents(groupPanes).length > 0){
						$(parentContainer).parents(groupPanes).siblings(outstandingLabels).removeClass(formElementErrorClass);
					}

					// Remove info panel
					parentContainer
						.find("div.layoutAreaContextulInfo")
						.remove();
						
					// Add success panel	
					if (parentContainer.find('span.successfullyCompletedField').length < 1) {
						
						// Match the first input only
						if ($('input, textarea', parentContainer)[0] !== undefined) {
							$($('input, textarea', parentContainer)[0])
								.before(successMessage);
						}
						$('span.successfullyCompletedField', parentContainer)
							.hide()
							.fadeIn(300);
					}
				},
				
					
				/** This is a custom event created for BT Tradespace **/
				// Control what happens when a field gains focus
				focusEvent: function(element) {
					var parentElement = $(element).closest(JS_formElement);
					if (parentElement.hasClass(formElementErrorClass)) {
						parentElement
							.find("div.contentAreaInfoPanel")
							.addClass("contentAreaInfoPanelActive");
							
						$(element).siblings('div.layoutAreaContextulInfo')
							.fadeIn(300);
					}
				},
						
				/** This is a custom event created for BT Tradespace **/
				// Controls what happens when a field looses focus
				focusOutEvent: function(element) {
					
					// Remove info panel
					$(element)
						.closest(JS_formElement)
						.find("div.layoutAreaContextulInfo")
						.hide()
						.children("div.contentAreaInfoPanel")
						.removeClass("div.contentAreaInfoPanelActive");
				},
				
				/** This is a custom event created for BT Tradespace **/
				// Controls what happens on key up
				keyUpEvent: function(element) {
					var eventTimer;
					if($(element).hasClass('VAL_password') || $(element).hasClass('VAL_domain') || $(element).hasClass('VAL_displayName')) {
						if (eventTimer) {
							clearTimeout(eventTimer);
						}
						eventTimer = setTimeout(function(){$(element).valid();}, 200);
					}
				}
				
			});
		});
	},

	/**
	 * Responsible for the validation of display & domain names.
	 *
	 */
	ajaxValidation: {
		
		// General Variables
		agent: "user",
		result: true,
		timer: "",
		
		// Configuration for the different kinds of AJAX searches. Paths to variables
		// expected on page, to be sent along with AJAX request
		configuration: {
			domainName: {
				url: (BTT.ctx ? BTT.ctx : '/ts') + "/sign-up/utility/suggestDomainNames",
				variables: {
					town: '#town',
					postcode: '#postcode'
				}
			},
			displayName: {
				url: (BTT.ctx ? BTT.ctx : '/ts') + "/sign-up/utility/suggestDisplayNames",
				variables: {
					firstName: '#firstName',
					lastName: '#lastName'
				}
			}
		},
		
		
		/**
		 * Performs the AJAX search, controls what happens with response.
		 * @param elementValue {string} The value of the current field
		 * @param element {html} The HTML element that is the current field
		 * @param searchType {string} Equal to 'displayName' or 'domainName' and is
		 * the same word exactly as is expected to be sent on the AJAX request
		 */
		performAjaxSearch: function(elementValue, element, searchType) {
			
			var formElement = $(element),
				variables = BTT.Validation.ajaxValidation.configuration[ searchType ].variables || {},
				url = BTT.Validation.ajaxValidation.configuration[ searchType ].url || "",
				data = {}
			
			// Fetch the data variables to be sent with AJAX search
			for ( variable in variables) {
				data[variable] = $( variables[variable] ).val() || "";
			}
			
			// Add the current element value to the search type
			if (data !== {}) {
				data[ searchType ] = elementValue;
			}
			
			$.ajax({
				cache: false,
				//async: false,
				type: "get",
				timeout: 3000,
				dataType: "json",
				data: data,
				url: url,
				success: function(response) {
					var isDisplayName = (searchType === "displayName") ? true : false,
						isDomainName = (searchType === "domainName") ? true : false,
						responseContent = response[searchType + 's'],
						availability = (responseContent.length > 0) ? false : true;
					
					// Checks the whether the current field is valid, without doing an AJAX call
					function updateField () { 
						BTT.Validation.ajaxValidation.agent = "browser";
						formElement.valid();
						BTT.Validation.ajaxValidation.agent = "user";
					}
			
					// Responsible for displaying available domain / display names
					function showSuggestions() { 
						var currentElement = $(element),
							message = function(){
									var tempMessage = "";
									if(isDisplayName) {
										tempMessage = BTT.Messages.Validation.displayNamesAvailable;
									} else if (isDomainName) {
										tempMessage = BTT.Messages.Validation.domainsAvailable;
									}
									return tempMessage	
								}(),
							suggestions = $('<div class="layoutArea JS_dropDownMenu">' +
											'<div class="contentArea contentAreaEmphasis">' + 
											'<p>' + message + '</p>'+ 
											'</div></div>'),
							suggestionsList = (function(){
								var list = $('<ul class="list textRegular"></ul>');
								for (var i = 0, j = responseContent.length; i < j; i++) {
									list.append('<li><a>' + responseContent[i] + '</a></li>');
								}
								return list;	
							}());
							
						// the field for domain names needs to be narrow	
						if (isDomainName) {
							suggestions.addClass("widthMedium");
						}
						
						suggestions
							.find('div.contentAreaEmphasis')
							.append(suggestionsList)
							.find('a').each(function(){
								$(this).click(function(){
									currentElement.val($(this).html());
									formElement.valid();
								});	
							});
							
						var existingSuggestions = currentElement.siblings('div.JS_dropDownMenu').find('div.contentAreaEmphasis');

						// create the drop down (different locations for display / domain name)
						if (existingSuggestions.length < 1) {
							
							if (isDomainName) {
								currentElement
									.siblings('p:first')
									.after(suggestions);
							} else {
								currentElement
									.after(suggestions);
							}
							
							suggestions
								.hide()
								.stop()
								.slideDown(500);
						} else {
							existingSuggestions
								.find('ul')
								.stop()
								.slideUp(500, function(){
									$(this).remove();
									existingSuggestions
										.append( suggestionsList );
										
									suggestionsList
										.hide()
										.stop()
										.slideDown(500);
								});
						}
					}
					
					// Hides the suggestions
					function hideSuggestions() { 
						$(element)
							.siblings('div.JS_dropDownMenu')
							.stop()
							.slideUp(500, function(){
								$(this).remove();
							});
					}
					
					// Sets the results of whether the name is available on our global variable
					function setResult( availability ) {
						if( availability ) {
							BTT.Validation.ajaxValidation.result = true;
							hideSuggestions();
							
						} else {
							BTT.Validation.ajaxValidation.result = false;
							showSuggestions();
						}
					}
					
					// Update our store of success
					setResult( availability );
					
					// Update the status of the field
					updateField();

				},
				error: function(){
				},
				complete: function(){
				}
			});
		},
		
		/**
		 * Intitate an AJAX request if the validation request comes from the user
		 * @param elementValue {string} The value of the current field
		 * @param element {html} The HTML element that is the current field
		 * @param searchType {string} Equal to 'displayName' or 'domainName' and is
		 * the same word exactly as is expected to be sent on the AJAX request
		 */
		start: function( elementValue, element, searchType ) {
			
			// Only initiate an AJAX request if the user initates a validation request
			if (BTT.Validation.ajaxValidation.agent === "user") {
				var timer = BTT.Validation.ajaxValidation.timer,
					makeAjaxRequest = function(){
						BTT.Validation.ajaxValidation.performAjaxSearch(elementValue, element, searchType);	
					};
					
				// If the timer is running, clear it before making another ajax request
				if ( typeof timer !== "" ) {
					clearTimeout( timer );
				}
				BTT.Validation.ajaxValidation.timer = setTimeout( makeAjaxRequest, 500 );
			}
			return BTT.Validation.ajaxValidation.result;
		}
	},

	
	getPasswordStrength: function (passwordStr, minLength, minStrength) {
		
		var strength = 0,
			lowLetters = 0,
			capLetters = 0,
			numbers = 0,
			special = 0,
			password = passwordStr.split("");	//IE7 requires an Array
	
		if (password !== undefined) {
			
			for (var i = 0; i < password.length; i++) {
				
					
				var lowChars = new RegExp(/[a-z]/),
					capChars = new RegExp(/[A-Z]/),
					digits = new RegExp(/[0-9]/);
				
				if( password[i].match(lowChars) ) {
					strength += 5;
					lowLetters = 1;
				}
				else if ( password[i].match(capChars) ) {
					strength += 5;
					capLetters = 1;
				}
				else if ( password[i].match(digits) ) {
					strength += 6;
					numbers = 1;
				} else  {
					strength += 7;
					special = 1;
				}
				
				var bonus = lowLetters + capLetters + numbers + special;
				if (bonus >= 2) {
					strength += (bonus - 1) * 10;
				}
			}
		
			if (strength > 100) {
				strength = 100;
			} else if (password.length < minLength) {
				strength = (password.length / minLength) * minStrength;
			} else if (strength < minStrength) {
				strength = minStrength + 1;
			}
		}
		return strength;
	}
};


/* jQuery Validation plugin customisations
-------------------------------- */





/* Check domain name availability
-------------------------------- */
$.validator.addMethod('checkDomainName', function ( elementValue, element ) {
	var checkDomainName = BTT.Validation.ajaxValidation.start;
	return checkDomainName( elementValue, element, "domainName" );
}, 'hello');



/* Check display name availability
-------------------------------- */
$.validator.addMethod('checkDisplayName', function ( elementValue, element ) {
	var checkDisplayName = BTT.Validation.ajaxValidation.start;
	return checkDisplayName( elementValue, element, "displayName" );
}, 'hello');




/* Password strength functionality
-------------------------------- */
$.validator.addMethod('checkPassword', function (password) {
	
	var minLength = 6,
		minStrength = 33,
		goodStength = 66,
		validPassword = false,
		
		passwordBar = $("div.contentAreaPasswordStrength"),
		
		passwordStrongClass = "contentAreaPasswordStrengthStrong",
		passwordOkClass = "contentAreaPasswordStrengthMediocre",
		passwordWeakClass = "contentAreaPasswordStrengthPoor",
		passwordCurrentClass = passwordWeakClass,
		
		passwordStrongText = BTT.Messages.Password.strong,
		passwordOkText = BTT.Messages.Password.ok,
		passwordWeakText = BTT.Messages.Password.weak,
		passwordCurrentText = passwordWeakText,
	
		strength = BTT.Validation.getPasswordStrength(password, minLength, minStrength) || 0;
	
	if (strength > goodStength) {
		passwordCurrentClass = passwordStrongClass;
		passwordCurrentText = passwordStrongText;
	} else if (strength > minStrength) {
		passwordCurrentClass = passwordOkClass;
		passwordCurrentText = passwordOkText;
	}

	// Change colour of password strength indicator
	// Change text of password strength indicator	
	// Animate password strength indicator
	passwordBar
		.removeClass(passwordStrongClass)
		.removeClass(passwordOkClass)
		.removeClass(passwordWeakClass)
		.addClass(passwordCurrentClass)
		.find("p")
		.html(passwordCurrentText)
		.animate({
			width: strength + "%"
		}, {
			queue: false
		});
	
	validPassword = (strength > minStrength) ? true : false;
	
	return validPassword;

}, '');


/* Check for unwanted characters
-------------------------------- */
$.validator.addMethod('validChars', function (value) {
    var result = true;
    // unwanted characters
    var iChars = "!@#$%^&*()+=-[]\\\';,./{}|\":<>?";
    for (var i = 0; i < value.length; i++) {
        if (iChars.indexOf(value.charAt(i)) !== -1) {
            return false;
        }		
    }
	
    return result;
}, '');

/* Check for unwanted characters in Domain name
-------------------------------- */
$.validator.addMethod('validDomainChars', function (value) {
    var result = true;
    // unwanted characters
     var iChars = " !@#$%^&*()+=-[]\\\';,./{}|\":<>?";
    for (var i = 0; i < value.length; i++) {
        if (iChars.indexOf(value.charAt(i)) !== -1) {
            return false;
        }
    }
    return result;
}, '');


/* Checks the value of the parameter for a valid postcode format
-------------------------------- */
$.validator.addMethod('checkPostCode', function (postCode) {
	var result = true;
	result = (/^\s*[A-Z]{1,2}[0-9R][0-9A-Z]? {0,1}[0-9][ABD-HJLNP-UW-Z]{2}\s*$/i).test(postCode);
	return result;
}, '');


/* Checks the value of the parameter for a valid phone number
-------------------------------- */
$.validator.addMethod("phone", function(phoneNumber) {
	var result = true;
	if(phoneNumber.length > 0) {
		// Only allow leading '+', 0-9, spaces, hyphens, dots, brackets
		if( phoneNumber.replace(/^\+?[0-9\s\-\.\(\)]*/g, "").length === 0 ) {
			
			// Remove leading +
			phoneNumber = phoneNumber.replace(/^(\+)?/, "");
			
			// Remove single pair of brackets
			if ( phoneNumber.search(/\(/) !== -1) {
				phoneNumber = phoneNumber.replace(/\([0-9\s\-\.]*\)/, "");
			}
			
			// Remove spaces, hyphens, dots
			phoneNumber = phoneNumber.replace(/[\s\-\.]*/g, "");
			
			// Pass only if remaining characters are digits and there are more than 4 of them
			if ( (phoneNumber.replace(/[0-9]/g, "").length !== 0) || (phoneNumber.length < 4) ) {
				result = false;
			}
			
		} else {
			result = false;
		}	
	}

	return result;
}, '');


/* Checks the value of the parameter for a valid Google Analytics Id
-------------------------------- */
$.validator.addMethod("checkGoogleAnalytics", function(googleAnalyticsId) {
	var result = true;
	result = ((/UA-[0-9]+-[0-9]+/).test(googleAnalyticsId));
	return result;
}, '');


/* Checks the value of the parameter for a valid date format
-------------------------------- */
$.validator.addMethod("dateCheck", function(inputDate) {
	var newDate = new Date(),
		day = null,
		month = null,
		year = null,
		dateRegExp = /^(0?[1-9]|[12][0-9]|3[01])[\-\s\/\.](0?[1-9]|1[012])[\-\s\/\.](\d{4})$/,
		parsedDate = [],
		result = true;
	if ((inputDate !== null) && (inputDate > '')) {
		parsedDate = inputDate.match(dateRegExp);
		result = false;
		if ((parsedDate !== null) && (parsedDate.length === 4)) {
			day = parseInt(parsedDate[1],10);
			month = parseInt(parsedDate[2],10);
			year = parseInt(parsedDate[3],10);
			newDate.setFullYear( year, (month - 1), day );
			result = ((!day && !month && !year) || ((newDate instanceof Date) && ((newDate.getMonth()+1) === month)));
	}
	}
	return result;
}, '');

/* Extend jQuery.Validation with event functions
-------------------------------- */
$.extend(
	$.validator.defaults, {
		
		onfocusin: function(element){
			this.lastActive = element;

			// hide error label and remove error class on focus if enabled
			if ( this.settings.focusCleanup && !this.blockFocusCleanup ) {
				this.settings.unhighlight && this.settings.unhighlight.call( this, element, this.settings.errorClass );
				this.errorsFor(element).hide();
			}
			
			/* BTTR customisation */
			if ( this.settings.focusEvent ) {
				this.settings.focusEvent && this.settings.focusEvent.call( this, element );
			}
		},
		
		onfocusout: function(element) {
			if ( !this.checkable(element) ) {
				this.element(element);
			}
			
			/* BTTR customisation */
			if ( this.settings.focusOutEvent ) {
				this.settings.focusOutEvent && this.settings.focusOutEvent.call( this, element );
			}
		},
		
		onkeyup: function(element) {
			if ( element.name in this.submitted || element === this.lastElement ) {
				this.element(element);
			}
			
			/* BTTR customisation */
			if ( this.settings.keyUpEvent ) {
				this.settings.keyUpEvent && this.settings.keyUpEvent.call( this, element );
			}
		}	
	
	}
);



/* Initialise when the DOM is ready
-------------------------------- */
$(document).ready(function(){
	BTT.Validation.init();
});



