(function(jQuery){
	/**
	 * Decorates an invalid element accordiong to the values supplied in the options
	 * @param {Object} val_elem - a jquery object containg the element to validate
	 * @param {Object} options - options given to the validation function
	 * 
	 * TODO: need to add onFail handler for compare and regex validation
	 */
	jQuery.valTools = {
		logError: function(message, options){
			if (typeof log != 'undefined') 
				log.error(message)
			else {
				if (options.debug) 
					alert(message);
			}
		},
		requiredFieldBlur: function(e){
			var jElem = jQuery(this);
			var options = e.data;
			if (jElem.val() != '') {
				jElem.css('background-color', options.validBackgroundColor);
				jElem.unbind('blur', jQuery.valTools.requiredFieldBlur);
			}
		},
		regexBlur: function(e){
			var jElem = jQuery(this);
			var options = e.data;
			var regexp = new RegExp(options.regex);
			if (jElem.val().match(regexp)) {			
				jElem.tooltip().get().remove();
				jElem.css('background-color', options.validBackgroundColor);
				jQuery(this).unbind('blur', jQuery.valTools.regexBlur);
			}
		},
		compareBlur: function(e){
			var options = e.data;
			var val_to_match = null;
			var compare_is_valid = true;
			options.validate.each(function(){
				if (!(compare_is_valid)) 
					return;
				var val_elem = jQuery(this);
				if (val_to_match == null) 
					val_to_match = val_elem.val();
				else {
					if (val_elem.val() != val_to_match) {
						compare_is_valid = false;
						return;
					}
				}
			});
			if (compare_is_valid) {
				options.validate.each(function(i){
					var jElem = jQuery(this);
					jElem.tooltip().get().remove();
					jElem.css('background-color', options.validBackgroundColor);
					jElem.unbind('blur', jQuery.valTools.compareBlur);
				});
				
			}
		},
		decorateInvalid: function(val_elem, options){
			var un_validation_i = 0;
			var un_validationInterval = setInterval(function(){
				if (!(options.flash)) {
					val_elem.css('background-color', options.backgroundColor);
					clearInterval(un_validationInterval);
					return;
				}
				
				if (un_validation_i % 2 == 0) 
					val_elem.css('background-color', options.flashColor);
				else 
					val_elem.css('background-color', options.backgroundColor);
				
				if (++un_validation_i > 3) 
					clearInterval(un_validationInterval);
			}, options.flashIntervalDuration);
			
			if (typeof options.regex != 'undefined') {
				val_elem.unbind('blur', jQuery.valTools.requiredFieldBlur);
				val_elem.bind('blur', options, jQuery.valTools.regexBlur);
			}
			else 
			{
				if (typeof options.invalidCompareMsg != 'undefined') 
				{
					val_elem.unbind('blur', jQuery.valTools.requiredFieldBlur);
					val_elem.bind('blur', options, jQuery.valTools.compareBlur);
				}
				else 
				{
					val_elem.bind('blur', options, jQuery.valTools.requiredFieldBlur);
				}
			}				
		}
	};
	
	/**
	 * required field validator on text and password inputs
	 * @param {Object} useroptions
	 * option notes<br />
	 * <b>validate:</b> an array or jquery element that has text inputs or password inputs somewhere as a child.<br />
	 * <b>validBackgroundColor:</b> the color that the background element should be when in a valid state<br />
	 * <b>backgroundColor:</b> bg color when the element is invalid<br />
	 * <b>flashColor:</b> the element will flash between this color and backgroundColor if flash = true<br />
	 * <b>flash:</b> tells the validator whether to cause the element to flash or just show the backgroundColor<br />
	 * <b>flashIntervalDuration:</b> the interval between flashes<br />
	 * <b>debug:</b> if true and blackbirdjs not present, show an alert box on errors<br />
	 */
	 
	jQuery.fn.enableValidation = function(useroptions){
		// Determine what options have been supplied
		var defaults = {
			regexOptions: null,
			compareOptions: null,
			validate: null,
			validBackgroundColor: '#ffffff',
			backgroundColor: '#f7fd55',
			flashColor: '#ff0000',
			flash: true,
			flashIntervalDuration: 100,
			debug: false,
			onFail: null,
			onSuccess: function() {}
		};
		var propnames = ['onSuccess', 'onFail', 'regexOptions', 'compareOptions', 'validate', 'validBackgroundColor', 'backgroundColor', 'flashColor', 'flash', 'flashIntervalDuration', 'debug'];
		var options = defaults;
		
		for (i = 0; i < propnames.length; i++) 
			setIfNull(propnames[i]);
		
		if (typeof options.validate == 'undefined' || options.validate == null || options.validate.length == 0) 
			jQuery.valTools.logError("No elements found in the validate collection", options);
		
		this.each(function(i){
			var thisobj = jQuery(this);
			thisobj.click(function(){
				try {
					var required_val_result = new Array();
					
					jQuery(options.validate).add(jQuery(options.validate).find('input[@type=text]')).add(jQuery(options.validate).find('input[@type=password]')).add(jQuery(options.validate).find('textarea')).each(function(i){
						required_val_result[i] = true;
						
						var val_elem = jQuery(this);
						// start large stupid if statement :( if anyone figures out a better way here (without nested if statements), by all means...change it!!!
						if 
						(
							(
								typeof val_elem[0].tagName == 'undefined' || val_elem[0].tagName.toLowerCase() != 'textarea'
							) 
							&& 
							(
								(
									val_elem.attr('type') == null
								) 
								|| 
								(
									val_elem.attr('type').toString().toLowerCase() != 'text' && val_elem.attr('type').toString().toLowerCase() != 'password'
								)
							)
						) 
							return;
						// end large stupid if statement
						
						if (val_elem.val() == '') {
							jQuery.valTools.decorateInvalid(val_elem, options);
							required_val_result[i] = false;
						}
					});
					
					return (function(){
						for (i = 0; i < required_val_result.length; i++) {
							if (!(required_val_result[i])) 
							{
					            // execute onFail providing the object that was clicked
					            if (options.onFail != null) options.onFail(thisobj);
							    return false;
							}								
						}
						options.onSuccess();
						return true;
					})();
				} 
				catch (e) {
					for (x in e) 
						log.info(x + ": " + e[x]);
					return false;
				}
			});
		});
		
		function setIfNull(propname){
			if (typeof useroptions[propname] != 'undefined' && useroptions[propname] != null) 
				options[propname] = useroptions[propname];
		}
		return this;
	};
	
	/**
	 * validates a collection of fields based on a regular expression
	 * @param {Object} useroptions
	 */
	jQuery.fn.enableCompareValidation = function(useroptions){
		// Determine what options have been supplied
		var defaults = {
			validate: null,
			invalidCompareMsg: '',
			showToolTip: true,
			tipRelativeLeft: 0,
			tipRelativeTop: 0,
			validBackgroundColor: '#ffffff',
			backgroundColor: '#f7fd55',
			flashColor: '#ff0000',
			flash: true,
			flashIntervalDuration: 100,
			debug: false,
			ignoreIfEmpty: false,
			onFail: null
		};
		var propnames = ['onFail', 'validate', 'tipRelativeLeft', 'tipRelativeTop', 'invalidCompareMsg', 'showToolTip', 'validBackgroundColor', 'backgroundColor', 'flashColor', 'flash', 'flashIntervalDuration', 'debug', 'ignoreIfEmpty'];
		var options = defaults;
		
		for (i = 0; i < propnames.length; i++) 
			setIfNull(propnames[i]);
		
		if (typeof options.validate == 'undefined' || options.validate == null || options.validate.length == 0) 
			jQuery.valTools.logError("No elements found in the validate collection", options);
		
		this.each(function(i){
			var thisobj = jQuery(this);
			thisobj.click(function(){
				var compare_val_result = true;
				var elem_collection = jQuery(options.validate).add(jQuery(options.validate).find('input[@type=text]')).add(jQuery(options.validate).find('input[@type=password]')).add(jQuery(options.validate).find('textarea'));
				var valToMatch = null;
				elem_collection.each(function(i){
					if (!(compare_val_result)) 
						return;
					var val_elem = jQuery(this);
					
					if (valToMatch == null) 
					{
						if (val_elem.val() == '' && options.ignoreIfEmpty) return;
						valToMatch = val_elem.val();
					}
					else 
					{
						if (val_elem.val() != valToMatch) {
							elem_collection.each(function(i){
								var curr_val_elem = jQuery(this);
								jQuery.valTools.decorateInvalid(curr_val_elem, options);
								if (typeof jQuery.fn.tooltip != 'undefined') {
									if (curr_val_elem.tooltip().get() != null)
										curr_val_elem.tooltip().get().remove();
									curr_val_elem.tooltip().create({
										content: function(){
											return options.invalidCompareMsg;
										},
										css: {
											backgroundColor: '#f7fd55',
											padding: '0px 3px 1px 3px',
											fontFamily: 'tahoma',
											fontSize: '10px',
											color: 'blue'
										},
										relativeTop: options.tipRelativeTop,
										relativeLeft: options.tipRelativeLeft,
										showTail: false,
										static: true,
										showClickToClose: false
									});
								}
								else
								{
									if (typeof log != 'undefined')
										log.info('tooltip plugin not found!');
								}
							});
							compare_val_result = false;
						}
					}
				});
				return compare_val_result;
			});
		});
		
		function setIfNull(propname){
			if (typeof useroptions[propname] != 'undefined' && useroptions[propname] != null) 
				options[propname] = useroptions[propname];
		}
		return this;
	};
	/**
	 * validates a collection of fields based on a regular expression
	 * @param {Object} useroptions
	 */
	jQuery.fn.enableRegexValidation = function(useroptions){
		// Determine what options have been supplied
		var defaults = {
			validate: null,
			regex: null,
			failMsg: '',
			showToolTip: true,
			tipRelativeLeft: 0,
			tipRelativeTop: 0,
			validBackgroundColor: '#ffffff',
			backgroundColor: '#f7fd55',
			flashColor: '#ff0000',
			flash: true,
			flashIntervalDuration: 100,
			debug: false
		};
		var propnames = ['validate', 'tipRelativeLeft', 'tipRelativeTop', 'regex', 'failMsg', 'showToolTip', 'validBackgroundColor', 'backgroundColor', 'flashColor', 'flash', 'flashIntervalDuration', 'debug'];
		var options = defaults;
		
		for (i = 0; i < propnames.length; i++) 
			setIfNull(propnames[i]);
		
		if (typeof options.validate == 'undefined' || options.validate == null || options.validate.length == 0) 
			jQuery.valTools.logError("No elements found in the validate collection", options);
		
		this.each(function(i){
			var thisobj = jQuery(this);
			thisobj.click(function(){
				var regex_val_result = true;
				
				jQuery(options.validate).add(jQuery(options.validate).find('input[@type=text]')).add(jQuery(options.validate).find('input[@type=password]')).add(jQuery(options.validate).find('textarea')).each(function(i){
					var val_elem = jQuery(this);
					if (options.regex == null) {
						regex_val_result = false;
						jQuery.valTools.logError("No regular expression supplied!", options);
						return;
					}
					var regex = new RegExp(options.regex);
					if (!(val_elem.val().match(regex))) {
						jQuery.valTools.decorateInvalid(val_elem, options);
						if (typeof jQuery.fn.tooltip != 'undefined') {
							if (val_elem.tooltip().get() != null)
								val_elem.tooltip().get().remove();
							val_elem.tooltip().create({
								content: function(){
									return options.failMsg;
								},
								css: {
									backgroundColor: '#f7fd55',
									padding: '0px 3px 1px 3px',
									fontFamily: 'tahoma',
									fontSize: '10px',
									color: 'blue'
								},
								relativeTop: options.tipRelativeTop,
								relativeLeft: options.tipRelativeLeft,
								showTail: false,
								static: true,
								showClickToClose: false
							});
						}
						else
						{
							if (typeof log != 'undefined')
								log.info('tooltip plugin not found!');
						}
						regex_val_result = false;
					}
				});
				return regex_val_result;
			});
		});
		
		function setIfNull(propname){
			if (typeof useroptions[propname] != 'undefined' && useroptions[propname] != null) 
				options[propname] = useroptions[propname];
		}
		return this;
	}
}
)(jQuery);

