(function($)
{
	/* 
	 * Usage:
	 * 
	 * $('#search').defaultText('Search the site');
	 * $('.required').defaultText('Required');
	 * $('#myfield').defaultText("Don't replace this text", false);
	 * $('#otherfield').defaultText("Don't submit this text as blank", true, false);
	 */
	$.fn.defaultText = function(text, replace, blank)
	{
		if (typeof replace == 'undefined')
		{
			replace = true;
		}
		
		if (typeof blank == 'undefined')
		{
			blank = true;
		}
		
		var $fo = $(this).parents('form');
		
		return this.each(function()
		{
			var $fi = $(this);
			
			// Set the default text if not already
			if ($.trim($fi.val()) == '')
			{
				$fi.val(text);
			}
			
			if (!!replace)
			{
				// React depending on presence of default text
				$fi.focus(function()
				{
					if ($.trim($fi.val()) == text)
					{
						$fi.val('');
					}
				}).blur(function()
				{
					if ($.trim($fi.val()) == '')
					{
						$fi.val(text);
					}
				});
			}
			
			if (!!blank)
			{
				// Make sure default text gets sent as nothing instead
				$fo.each(function()
				{
					$(this).submit(function()
					{
						if ($.trim($fi.val()) == text)
						{
							$fi.val('');
						}
					});
				});
			}
		});
	};
	
	/* 
	 * Usage:
	 * 
	 * $('.myfadingelement').hoverFade({
	 *     opacityIn: opacityOnMouseOver, 
	 *     opacityOut: opacityOnMouseOut, 
	 *     speed: fadeSpeed
	 * });
	 * 
	 * $('.mylink').hoverFade({
	 *     opacityIn: opacityOnMouseOver, 
	 *     opacityOut: opacityOnMouseOut, 
	 *     speed: fadeSpeed, 
	 *     target: '.myfadingelement'
	 * });
	 */
	$.fn.hoverFade = function(options)
	{
		var settings = $.extend({
			opacityIn: 1.0, 
			opacityOut: 0.5, 
			speed: 100, 
			target: null
		}, options);
		
		return this.each(function()
		{
			var $t = $(this), 
				$u = settings.target ? $t.find(settings.target) : $t;
			
			$t.hover(function()
			{
				$u.animate({ opacity: settings.opacityIn }, settings.speed);
			}, function()
			{
				$u.animate({ opacity: settings.opacityOut }, settings.speed);
			});
			
			$u.css('opacity', settings.opacityOut);
		});
	};
	
	/* 
	 * Usage:
	 * 
	 * $('#myelm')
	 *     .animate(fancyAnimationObject)
	 *     .idle(timeMilliseconds)
	 *     .animate(anotherFancyAnimationObject);
	 */
	$.fn.idle = function(time)
	{ 
		return this.each(function()
		{
			var $t = $(this);
			
			$t.queue(function()
			{
				setTimeout(function()
				{
					$t.dequeue();
				}, time);
			});
		});
	};
	
	/* 
	 * Usage:
	 * 
	 * $(document).konamiCode(enableEgg, disableEgg, anotherCode);
	 */
	$.fn.konamiCode = function(activate, deactivate, code)
	{
		var konamiCode = code ? code : '38, 38, 40, 40, 37, 39, 37, 39, 66, 65', 
			keyDnStack = [], 
			reactivate = eval('[' + activate.toString() + ']')[0];
		
		return this.each(function()
		{
			var $t = $(this);
			
			$t.bind('keydown.konamiCode', function(e)
			{
				keyDnStack.push(e.keyCode);
				
				if (keyDnStack.toString().indexOf(konamiCode) != -1)
				{
					activate();
					
					if (typeof deactivate == 'function')
					{
						activate = activate != deactivate ? deactivate : reactivate;
					}
					else if (deactivate != 'repeat')
					{
						$t.unbind('keydown.konamiCode');
					}
					
					keyDnStack = [];
				}
			});
		});
	};
	
	/* 
	 * Usage:
	 * 
	 * $.preloadImages('path/to/image.png', 'path/to/another-image.gif');
	 */
	$.preloadImages = function()
	{
		var imgCache = [];
		
		for (var i = arguments.length; i--;)
		{
			var img = document.createElement('img');
			img.src = arguments[i];
			imgCache.push(img);
		}
		
		return this;
	};
// I think self-invoking closures are cute
})(jQuery);
