jQuery.validator.addMethod("zendCheckboxRequired",
		function(value, element, param) {
			if($(element).attr('type') == 'hidden') {
				element = $('#'+element.name);
			}
			return $(element).is(':checked');
		}, "This element is required."
	);

jQuery.validator.addMethod("notEqualTo",
		function(value, element, param) {
			if($.isArray(param)) {
				return $.inArray(value, param) == -1;
			} else {
				return value != param;
			}
		}, "Please choose a different value."
	); 

jQuery.validator.addMethod("urlCode",
		function(value, element) {
        	return this.optional(element) || /^[a-z0-9\-]+$/i.test(value);
		}, "Url code should consist of letters, digits and dashes only."
	);

jQuery.validator.addMethod("laterThan",
		function(value, element, param) {
			if(param == false) { // turn off the validation
				return true;
			}
			param = $(param).val();
			var ok = false;
            var re = /^\d{1,2}\/\d{1,2}\/\d{4}$/;
            
            if(re.test(value) && re.test(param)){
            	var date1 = value.split('/');
            	var date2 = param.split('/');
            	date1 = new Date(parseInt(date1[2],10), parseInt(date1[1],10) - 1, parseInt(date1[0],10)); 
            	date2 = new Date(parseInt(date2[2],10), parseInt(date2[1],10) - 1, parseInt(date2[0],10));
            	ok = date1 > date2;
            }
            
            return ok;
		}, "Please enter a later date."
	);

// requires a param that has no external // boundaries, eg "^\d$"
jQuery.validator.addMethod("regex",
		function(value, element, regexp) {
			var re = new RegExp(regexp);
			return this.optional(element) || re.test(value);
		}, "Please check that your input is formatted correctly."
	);

jQuery.validator.addMethod("url-optional-protocol",
		function(value, element) {
			if(value != '' && !/^http:\/\//.test(value) && !/^https:\/\//.test(value)) {
				value = 'http://' + value;
				$(element).val(value);
			}
			return this.optional(element) || jQuery.validator.methods.url.call(this, value, element);
		}, jQuery.validator.messages.url
	);

/**
 * Original code taken from:
 * http://www.mail-archive.com/jquery-en@googlegroups.com/msg14067.html
 * 
 */

jQuery.validator.addMethod("postcode",
	  function(value) {
	    return value == '' || /\b([a-pr-uwyzA-PR-UWYZ][a-hk-yA-HK-Y0-9][a-hjkstuwA-HJKSTUW0-9]?[abehmnprvwxyABEHMNPRVWXY0-9]?) *[0-9][abd-hjln-uw-zABD-HJLN-UW-Z]{2}\b/.test(value);
	  }, "Please specify a valid postcode"
	);

/***
 * Original code taken from:
 * http://code.google.com/p/jqueryjs/source/browse/trunk/plugins/validate/additional-methods.js?spec=svn6159&r=6159
 *
 * This is a modification, because \b is defined as not-\w
 */


//
//jQuery.validator.addMethod("maxWords", 
//	  function(value, element, params) { 
//	    return this.optional(element) || value.match(/\S+\s*/g).length <= params; 
//	  }, $.format("Please enter {0} words or less.")
//	);

// Jonathan - Workaround for the difference between word counts in Word and JQuery.
// Added an optional array parameter - where the second parameter is the actual comparison,
// whilst the first is the reported parameter

jQuery.validator.addMethod("maxWords", 
  function(value, element, params) { 
	if($.isArray(params)) {
		// If an array - check against the second value, but report about the first
		return this.optional(element) || value.match(/\S+\s*/g).length <= params[1];
	} else {
		return this.optional(element) || value.match(/\S+\s*/g).length <= params;
	}
    return this.optional(element) || value.match(/\S+\s*/g).length <= params; 
 }, $.format("Please enter {0} words or less."));
 
jQuery.validator.addMethod("minWords", function(value, element, params) { 
    return this.optional(element) || value.match(/\S+\s*/g).length >= params; 
}, $.format("Please enter at least {0} words.")); 
 
jQuery.validator.addMethod("rangeWords", function(value, element, params) { 
    return this.optional(element) || value.match(/\S+\s*/g).length >= params[0] && value.match(/\S+\s*/g).length < params[1]; 
}, $.format("Please enter between {0} and {1} words."));


/*
jQuery.validator.addMethod("maxWords", 
	  function(value, element, params) { 
	    return this.optional(element) || value.match(/\b\w+\b/g).length <= params; 
	  }, $.format("Please enter {0} words or less.") 
	);
 
jQuery.validator.addMethod("minWords", function(value, element, params) { 
    return this.optional(element) || value.match(/\b\w+\b/g).length >= params; 
}, $.format("Please enter at least {0} words.")); 
 
jQuery.validator.addMethod("rangeWords", function(value, element, params) { 
    return this.optional(element) || value.match(/\b\w+\b/g).length >= params[0] && value.match(/bw+b/g).length < params[1]; 
}, $.format("Please enter between {0} and {1} words."));
*/

jQuery.validator.addMethod("letterswithbasicpunc", function(value, element) {
        return this.optional(element) || /^[a-z-.,()'\"\s]+$/i.test(value);
}, "Letters or punctuation only please");  

jQuery.validator.addMethod("alphanumeric", function(value, element) {
        return this.optional(element) || /^\w+$/i.test(value);
}, "Letters, numbers, spaces or underscores only please");  

jQuery.validator.addMethod("lettersonly", function(value, element) {
        return this.optional(element) || /^[a-z]+$/i.test(value);
}, "Letters only please"); 

jQuery.validator.addMethod("nowhitespace", function(value, element) {
        return this.optional(element) || /^\S+$/i.test(value);
}, "No white space please"); 

/**
  * Return true, if the value is a valid date, also making this formal check dd/mm/yyyy.
  *
  * @example jQuery.validator.methods.date("01/01/1900")
  * @result true
  *
  * @example jQuery.validator.methods.date("01/13/1990")
  * @result false
  *
  * @example jQuery.validator.methods.date("01.01.1900")
  * @result false
  *
  * @example <input name="pippo" class="{dateITA:true}" />
  * @desc Declares an optional input element whose value must be a valid date.
  *
  * @name jQuery.validator.methods.dateITA
  * @type Boolean
  * @cat Plugins/Validate/Methods
  */
jQuery.validator.addMethod(
        "dateITA",
        function(value, element) {
                var check = false;
                var re = /^\d{1,2}\/\d{1,2}\/\d{4}$/
                if( re.test(value)){
                        var adata = value.split('/');
                        var gg = parseInt(adata[0],10);
                        var mm = parseInt(adata[1],10);
                        var aaaa = parseInt(adata[2],10);
                        var xdata = new Date(aaaa,mm-1,gg);
                        if ( ( xdata.getFullYear() == aaaa ) && ( xdata.getMonth () == mm - 1 ) && ( xdata.getDate() == gg ) )
                                check = true;
                        else
                                check = false;
                } else
                        check = false;
                return this.optional(element) || check;
        }, 
        "Please enter a correct date"
);

// TODO check if value starts with <, otherwise don't try stripping anything
jQuery.validator.addMethod("strippedminlength", function(value, element, param) {
        return jQuery(value).text().length >= param;
}, jQuery.format("Please enter at least {0} characters"));

// same as email, but TLD is optional
jQuery.validator.addMethod("email2", function(value, element, param) {
        return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)*(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test(value); 
}, jQuery.validator.messages.email);

// same as url, but TLD is optional
jQuery.validator.addMethod("url2", function(value, element, param) {
        return this.optional(element) || /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)*(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value); 
}, jQuery.validator.messages.url);

