(function($) {

$.jScrollPane = {
	active : []
};
$.fn.jScrollPane = function(settings)
{
	settings = $.extend({}, $.fn.jScrollPane.defaults, settings);

	var rf = function() { return false; };
	
	return this.each(
		function()
		{
			var jqe = $(this);
			var paneEle = this;
			jqe.addClass('jscroll');
			jqe.css({overflow:'hidden'});
			
			var jsout = $('<div class="jsout"><div class="jsin"></div></div>');
			var jsin = $('.jsin', jsout);
						
			jqe.append(jsout);
			
			var redo = function() {
				var ofp = jqe.offsetParent();
				if (!jqe.is('*:visible')) {
					display = jsout.css("display");
					if ( display !== "none" ) {					
						jsout.hide();
					}
					jqe.scrollTop(0);
					jqe.scrollLeft(0);
					return;
				}
				var pos = jqe.offset();
				var ofppos = ofp.offset();
				pos.left -= ofppos.left;
				pos.top -= ofppos.top;
				
				var ih = settings.horizontal ? jqe.innerWidth() : jqe.innerHeight(); 
				var iw = settings.horizontal ? jqe.innerHeight() : jqe.innerWidth();
				
				var oh = settings.horizontal ? jqe[0].scrollWidth : jqe[0].scrollHeight;
				var sp = settings.horizontal ? jqe.scrollLeft() : jqe.scrollTop();
				
				if (ih == 0 || ih/oh > 0.99 || !jqe.is('*:visible')) {
					display = jsout.css("display");
					jqe.scrollTop(0);
					jqe.scrollLeft(0);
					if ( display !== "none" ) {					
						jsout.hide();
					}
				} else {
					var inh = Math.max(settings.dragMinHeight,(ih/oh)*ih);
					jsout.show();
					if (settings.horizontal) {
						jsout.css({
							left: pos.left + settings.scrollbarMargin,
							top: pos.top + iw - jsout.outerHeight() + settings.scrollbarMargin,
							width: ih - (settings.scrollbarMargin * 2)
						});
						
						jsin.css({
							left: (sp/oh)*(ih - (settings.scrollbarMargin * 2)),
							width: inh
						});						
					} else {
						jsout.css({
							left: pos.left + iw - jsout.outerWidth() - settings.scrollbarMargin,
							top: pos.top + settings.scrollbarMargin,
							height: ih - (settings.scrollbarMargin * 2)
						});
						
						jsin.css({
							top: (sp/oh)*(ih - (settings.scrollbarMargin * 2)),
							height: inh
						});
					}
										
				}
			};
			
			var toredo = function() {
			    if (!jQuery.contains(document.documentElement,jqe[0])) {
			    	return;
			    }
				redo();
				setTimeout(toredo, 500);				
			}
			
			setTimeout(toredo,500);
			
			jqe.scroll(function() {
				redo();
			});
			

			var pu = function() {
				if (settings.horizontal) {
					jqe.scrollLeft(jqe.scrollLeft() - jqe.innerWidth());
				} else {
					jqe.scrollTop(jqe.scrollTop() - jqe.innerHeight());
				}
				redo();
			};
			
			var pd = function() {
				if (settings.horizontal) {
					jqe.scrollLeft(jqe.scrollLeft() + jqe.innerWidth());
				} else {
					jqe.scrollTop(jqe.scrollTop() + jqe.innerHeight());
				}
				redo();				
			};
			
			jqe.bind(
					'mousewheel',
					function (event, delta) {
						if (!jQuery.browser.webkit) delta *= 10;
						if (settings.horizontal) {
							jqe.scrollLeft(jqe.scrollLeft() - delta);
						} else {
							jqe.scrollTop(jqe.scrollTop() - delta);
						}
						redo();				
					}
				);
			
			
			jsout.mousedown(function(event){
				if (settings.horizontal) {
					var x = event.pageX;
					if (x < jsin.offset().left) {
						pu();
					} else {
						pd();
					}
				} else {
					var y = event.pageY;
					if (y < jsin.offset().top) {
						pu();
					} else {
						pd();
					}					
				}
			});
			
			jsin.mousedown(function(event){
				jsin.dragging = true;
				jsin.sy = event.pageY;
				jsin.sx = event.pageX;
				event.preventDefault();
				event.stopPropagation();
				return false;
			});
			$(document).mouseup(function(event){
				if (!jsin.dragging) return;
				jsin.dragging = false;
				event.preventDefault();
				event.stopPropagation();
				return false;
			});
			$(document).mousemove(function(event){
				if (!jsin.dragging) return;
				if (settings.horizontal) {
					var cx = event.pageX;
					var mv = cx - jsin.sx;
					jsin.sx = cx;
					var iw = jqe.innerWidth();
					var ow = jqe[0].scrollWidth;
					mv = (mv / iw) * ow;
					jqe.scrollLeft(jqe.scrollLeft() + mv);					
				} else {
					var cy = event.pageY;
					var mv = cy - jsin.sy;
					jsin.sy = cy;
					var ih = jqe.innerHeight();
					var oh = jqe[0].scrollHeight;
					mv = (mv / ih) * oh;
					jqe.scrollTop(jqe.scrollTop() + mv);
				}
				redo();
				event.preventDefault();
				event.stopPropagation();
				return false;
			});
			
		}
	)
};

$.fn.jScrollPane.defaults = {
	scrollbarMargin : 2,
	wheelSpeed : 18,
	dragMinHeight : 10,
	horizontal: false
};

// clean up the scrollTo expandos
$(window)
	.bind('unload', function() {
		var els = $.jScrollPane.active; 
		for (var i=0; i<els.length; i++) {
			els[i].scrollTo = els[i].scrollBy = null;
		}
	}
);

})(jQuery);	
