(function ($) {
	$.fn.autoResize = function(options) {
		
		// Just some abstracted details,
		// to make plugin users happy:
		var settings = $.extend({
			onResize : function(){},
			animate : true,
			animateDuration : 300,
			animateCallback : function(){},
			extraSpace : 100,
			limit: 300
		}, options);
		
		// Only textarea's auto-resize:
		this.filter('textarea').each(function(){
			
				// Get rid of scrollbars and disable WebKit resizing:
			var textarea = $(this).css({resize:'none','overflow-y':'hidden'}),
			
				// Cache original height, for use later:
				origHeight = textarea.height(),
				
				// Need clone of textarea, hidden off screen:
				clone = (function(){
					
					// Properties which may effect space taken up by chracters:
					var props = ['height','width','lineHeight','textDecoration','letterSpacing'],
						propOb = {};
						
					// Create object of styles to apply:
					$.each(props, function(i, prop){
						propOb[prop] = textarea.css(prop);
					});
					
					// Clone the actual textarea removing unique properties
					// and insert before original textarea:
					return textarea.clone().removeAttr('id').removeAttr('name').css({
						position: 'absolute',
						top: 0,
						left: -9999
					}).css(propOb).attr('tabIndex','-1').insertBefore(textarea);
					
				})(),
				lastScrollTop = null,
				updateSize = function() {
					
					// Prepare the clone:
					clone.height(0).val($(this).val()).scrollTop(10000);
					
					// Find the height of text:
					if (clone.scrollTop() > (origHeight - settings.extraSpace)) {
						var scrollTop = clone.scrollTop() + settings.extraSpace - 1,
						toChange = $(this).add(clone);
					} else {
						var scrollTop = origHeight,
						toChange = $(this).add(clone);
					}
						
					// Don't do anything if scrollTip hasen't changed:
					if (lastScrollTop === scrollTop) { return; }
					lastScrollTop = scrollTop;
					
					// Check for limit:
					if ( scrollTop >= settings.limit ) {
						$(this).css('overflow-y','');
						return;
					}
					// Fire off callback:
					settings.onResize.call(this);
					
					// Either animate or directly apply height:
					settings.animate && textarea.css('display') === 'block' ?
						toChange.stop().animate({height:scrollTop}, settings.animateDuration, settings.animateCallback)
						: toChange.height(scrollTop);
				};
			
			// Bind namespaced handlers to appropriate events:
			textarea
				.unbind('.dynSiz')
				.bind('click.dynSiz', updateSize)
				.bind('keyup.dynSiz', updateSize)
				.bind('keydown.dynSiz', updateSize)
				.bind('change.dynSiz', updateSize);
		});
		
		// Chain:
		return this;
	};
})(jQuery);

