// Note this appears to be an old and heavily customised version of the plugin, DO NOT UPGRADE

(function($) { 

$.fn.validate = function(options) {
	var validator = new $.validator(options, this);
	if( validator.settings.onsubmit ) {
		this.submit(function(event) {
			if(validator.settings.debug) {event.preventDefault();
			}
			return validator.validateForm();
		});
	}
	if( validator.settings.event ) {
		validator.elements.bind(validator.settings.event, function() {
			validator.errorList = {};
			validator.hideElementErrors(this);
			validator.validateElement(this);
			validator.showErrors();
		});
	}
	return validator;
};

var v = $.validator = function(options, form) {
	this.errorList = {};

	var settings = this.settings = $.extend({}, v.defaults, options);
	
	this.elements = $(":input:not(:submit):not(:reset)", form);

	this.currentForm = form[0];
	this.errorContainer = settings.errorLabelContainer.length && settings.errorLabelContainer
		|| settings.errorContainer.length && settings.errorContainer
		|| $([])
	this.errorContext = this.errorContainer.length && this.errorContainer || form;

	var instance = this;
	this.elements.focus(function() {
		instance.lastActive = this;
	});

};

v.defaults = {
	errorClass: "error",
	focusInvalid: true,
	errorContainer: $([]),
	errorLabelContainer: $([]),
	onsubmit: true
};

v.prototype = {

	validateForm: function() {

		this.errorList = {};

		this.settings.errorLabelContainer.hide();
		this.settings.errorContainer.hide();

		var labels = $("label." + this.settings.errorClass, this.errorContext).hide();
		if( this.settings.errorWrapper ) {
			labels.parents(this.settings.errorWrapper).hide();
		}
		var instance = this;
		this.elements.each(function() {
			instance.validateElement(this);
		});
		return this.isFormValid();
	},
	validateElement: function(element) {
		//Toyota.log('  validateElement(', element, ')');
		//Toyota.log('mandatoryvalue = '+$('input[@name="mandatoryFields"]').attr("value"));
		$(element).removeClass(this.settings.errorClass);
		var rules = this.findRules(element);
		for( var i=0, rule; rule = rules[i]; i++ ) {
			try {
				var method = v.methods[rule.name];
				if( !method)
					throw("validateElement() error: No method found with name " + rule.name);
				if( !method( $(element).val(), element, rule.parameters ) ) {
					var id = this.findId(element);
					if(!id && this.settings.debug) {
						console.error("could not find id/name for element, please check the element %o", element);
					}
					var list = this.errorList[id] || (this.errorList[id] = []);
					list[list.length] = this.formatMessage(method, rule, id);
					//Toyota.log('    validation failed! message is ' + this.formatMessage(method, rule, id));
				} else {
					//Toyota.log('    validation passed!');
				}
			} catch(e) {
				if(this.settings.debug) {
					console.error("exception occured when checking element " + element.id
						 + ", check the '" + rule.name + "' method");
				}
				throw e;
			}
		}
	},
	formatMessage: function(method, rule, elementID) {
		var m = this.settings.messages,
			param = rule.parameters,
			first = param.constructor == Array ? param[0] : param;
		if(m && m[elementID])
			if(m[elementID].constructor == String)
				message = m[elementID];
			else
				message = m[elementID][rule.name];
		else
			message = method.message;
		return message && message.replace("{0}", first || "").replace("{1}", param[1] || "");
	},
	hideElementErrors: function(element) {
		var errorLabel = $("label." + this.settings.errorClass + "[@for=" + this.findId(element) + "]", this.errorContext).hide();
		if( this.settings.errorWrapper ) {
			errorLabel.parent(this.settings.errorWrapper).hide();
		}
	},
	isFormValid: function() {
		var count = 0;
		for( var i in this.errorList ) {
			count++;
		}
		if(count) {
			this.showErrors();
			return false;
		} else {
			if(this.settings.submitHandler) {
				this.settings.submitHandler(this.currentForm);
				return false;
			}
			return true;
		}
	},
	showErrors: function() {
		// CUSTOM
		window.scroll(0,0);
		// END CUSTOM
		$(".errorNote").show();
		this.settings.errorContainer.show();
		this.settings.errorLabelContainer.show();
		var first = true;
		for(var elementID in this.errorList) {
			if( first && this.settings.focusInvalid ) {
				if( this.lastActive && this.errorList[this.lastActive.id])
					this.lastActive.focus();
				else {
					try {
						var element = $("#"+elementID);
						if(!element.length)
							element = $('[@name='+elementID+']', this.currentForm);
						element[0].focus();
					} catch(e) { if( this.settings.debug ) console.error(e); }
				}
				first = false;
			}
			this.showError(elementID, this.errorList[elementID][0]);
		}
	},
	showError: function(elementID, message) {
		var element = $("#" + elementID).addClass(this.settings.errorClass),
			message = element.attr('title') || message || "<strong>Warning: No message defined for " + elementID + "</strong>",
			errorLabel = $("label." + this.settings.errorClass, this.errorContext).filter("[@for=" + elementID + "]"),
			wrapper = this.settings.errorWrapper;
		if( errorLabel.length ) {
			if( errorLabel.attr("generated") ) {
				errorLabel.text(message);
			}
			errorLabel.show();
			if(wrapper) {
				errorLabel.parents(wrapper).show();
			}
		} else {
			var errorLabel = $("<label>").attr({"for": elementID, generated: true}).addClass("error").html(message);
			if(wrapper) {
				errorLabel = errorLabel.show().wrap("<" + wrapper + "></" + wrapper + ">").parent();
			}
			if(!this.errorContainer.append(errorLabel).length) 
				errorLabel.insertAfter(element);
			errorLabel.show();
		}
	},

	findRules: function(element) {
		var data;
		if(this.settings.rules) {
			data = this.settings.rules[this.findId(element)];
		} else {
			data = $(element).data();
			var metaWrapper = this.settings.metaWrapper;
			if(metaWrapper)
				data = data[metaWrapper];
		}
		var rules = [];
		if(!data)
			return rules;
		$.each(data, function(key, value) {
			var rule = rules[rules.length] = {};
			rule.name = key;
			rule.parameters = value;
		});
		return rules;
	},
	
	findId: function(element) {
		var id = ( /radio|checkbox/i.test(element.type) ) ? element.name : element.id;
		// generate id when none is found
		if(!id) {
			var formId = element.form.id,
				idcleanup = /[^a-zA-Z0-9\-_]/g;
			id = element.id = (formId ? formId.replace(idcleanup, "") : "") + element.name.replace(idcleanup, "");
		}
		return id;
	}
	
};

function getLength(value, element) {
	switch( element.nodeName.toLowerCase() ) {
	case 'select':
		return $("option:selected", element).length;
	case 'input':
		if( /radio|checkbox/i.test(element.type) )
			return $(element.form || document).find('[@name=' + element.name + ']:checked').length;
	}
	return value.length;
};

v.methods = {
	required: function(value, element, callback) {
		// If callback is a function, call it to checck if element is required or not
		if (typeof callback == 'function') {
			if(!callback()) {
				return true; // If callback says is not required, anything goes
			}
		}		
		switch( element.nodeName.toLowerCase() ) {
		case 'select':
			var options = $("option:selected", element);
			return options.length > 0 && ( element.type == "select-multiple" || options[0].value.length > 0);
		case 'input':
			switch( element.type.toLowerCase() ) {
			case 'checkbox':
			case 'radio':
				return getLength(value, element) > 0;
			}
		default:
			return $.trim(value).length > 0;
		}
	},
	minLength: function(value, element, param) {
		var length = getLength(value, element);
		return !v.methods.required(value, element) || length >= param;
	},
	maxLength: function(value, element, param) {
		var length = getLength(value, element);
		return !v.methods.required(value, element) || length <= param;
	},
	rangeLength: function(value, element, param) {
		var length = getLength(value, element);
		return !v.methods.required(value, element) || ( length >= param[0] && length <= param[1] );
	},
	minValue: function( value, element, param ) {
		return !v.methods.required(value, element) || value >= param;
	},
	maxValue: function( value, element, param ) {
		return !v.methods.required(value, element) || value <= param;
	},
	rangeValue: function( value, element, param ) {
		return !v.methods.required(value, element) || ( value >= param[0] && value <= param[1] );
	},
	email: function(value, element) {
		return !v.methods.required(value, element) || /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/i.test(value);
	},
	url: function(value, element) {
		return !v.methods.required(value, element) || /^(https?|ftp):\/\/[A-Z0-9](\.?[A-Z0-9ÄÜÖ][A-Z0-9_\-ÄÜÖ]*)*(\/([A-Z0-9ÄÜÖ][A-Z0-9_\-\.ÄÜÖ]*)?)*(\?([A-Z0-9ÄÜÖ][A-Z0-9_\-\.%\+=&ÄÜÖ]*)?)?$/i.test(value);
	},
	date: function(value, element) {
		return !v.methods.required(value, element) || !/Invalid|NaN/.test(new Date(value));
	},
	dateISO: function(value, element) {
		return !v.methods.required(value, element) || /^\d{4}[/-]\d{1,2}[/-]\d{1,2}$/.test(value);
	},
	toThisDate: function(value, element) {
		// TWF-11 make sure selected date more or equal to Today date
		var today = new Date();
		var year = today.getFullYear();
		var todayMonth = today.getMonth();
		
		if ($("#morethan18months").attr("checked")) {
			return true;
		} else {
			if($("#year").attr("value") == year) {
				if ($("#month").attr("value") == "Month") {
					return false;
				} else if ($("#month").attr("value") <= todayMonth) {
					return false;
				};
			} else {
				return false;
			}	
		};
		
		return true;
	},
	PhoneEmail: function(value, element) {
		if ($("#emailAddress").attr("checked")) {
			return true;
		} else {
			return v.methods.required(value, element) && /^[0-9-\s]+$/.test(value); 
		}
	},
	dateDE: function(value, element) {
		return !v.methods.required(value, element) || /^\d\d?\.\d\d?\.\d\d\d?\d?$/.test(value);
	},
	number: function(value, element) {
		return !v.methods.required(value, element) || /^-?[,0-9]+(\.\d+)?$/.test(value); 
	},
	phoneNo: function(value, element) {
		return !v.methods.required(value, element) || /^[0-9-\s]+$/.test(value); 
	},
	postCD: function(value, element) {
		return !v.methods.required(value, element) || /^[0-9]{4}/.test(value); 
	},
	numberDE: function(value, element) {
		return !v.methods.required(value, element) || /^-?[\.0-9]+(,\d+)?$/.test(value);
	},
	digits: function(value, element) {
		return !v.methods.required(value, element) || /^\d+$/.test(value);
	},
	equalTo: function(value, element, param) {
		return value == $(""+param).val();
	},
	monthandyear: function(value, element) {
		if ($("#purchaseWhen").attr("checked")) {
			return true;
		} else if ($('#year').get(0).isVisible == 1) {
        		return ($('#month').attr("value") != null) && ($('#year').attr("value") != null);
        	} else {
        		return true;
        	}
	}
};

var messages = {
	required: "This field is required.",
	maxLength: "Please enter a value no longer then {0} characters.",
	minLength: "Please enter a value of at least {0} characters.",
	rangeLength: "Please enter a value between {0} and {1} characters long.",
	email: "Please enter a valid email address.",
	url: "Please enter a valid URL.",
	date: "Please enter a valid date.",
	dateISO: "Please enter a valid date (ISO).",
	dateDE: "Bitte geben Sie ein gültiges Datum ein.",
	number: "Please enter a valid number.",
	numberDE: "Bitte geben Sie eine Nummer ein.",
	digits: "Please enter only digits",
	equalTo: "Please enter the same value again.",
	rangeValue: "Please enter a value between {0} and {1}.",
	maxValue: "Please enter a value less than or equal to {0}.",
	minValue: "Please enter a value greater than or equal to {0}."
};
for(var key in messages) {
	v.methods[key].message = messages[key];
}

v.addMethod = function(name, method, message) {
	(v.methods[name] = method).message = message;
};

})(jQuery);
