(function($) {    
    $.widget("ui.scrollbar", $.extend({}, $.ui.mouse, {
        _init: function() {                        
            this.scrollContent = this.element;
            this.scrollContent.css("overflow", "hidden");

            this.scrollPane = this.scrollContent.wrap("<div class='scrollView'></div>")
            .parent().css({width: this.options.scrollViewWidth, 
            height: this.options.scrollViewHeight, 
            overflow: "hidden"})
            .wrap("<div class='scrollPane'></div>")
            .parent().append("<div class='vScrollbar'></div>")
			
            this.scrollbar = $(".vScrollbar", this.scrollPane)            
            .append("<div class='vScrollbarHandle'></div>")
            .append("<div class='vScrollbarBackgroundTop'></div>")
            .append("<div class='vScrollbarBackgroundMiddle'></div>")
            .append("<div class='vScrollbarBackgroundBottom'></div>");                       
            
            this.handleElement = $(".vScrollbarHandle", this.scrollPane)            
            .css("position", "absolute")
            .append("<div class='vScrollbarHandleBackgroundTop'></div>")
            .append("<div class='vScrollbarHandleBackgroundMiddle'></div>")
            .append("<div class='vScrollbarHandleBackgroundBottom'></div>");

			this.vArrowHeight = 0;
			this.vArrowWidth = 0;
			if (this.options.showArrows) {
				this.scrollBarInclArrows = this.scrollbar.wrap("<div class='vScrollNavigation'></div>").parent().prepend("<div class='vScrollbarUpArrow'></div>").append("<div class='vScrollbarDownArrow'></div>");
				this.vArrowHeight = $('.vScrollbarUpArrow').height();
				this.vArrowWidth = $('.vScrollbarUpArrow').width();				
			}
			
			this.scrollbar.height(this.options.scrollViewHeight - 2*this.vArrowHeight);
			$('.vScrollbarBackgroundMiddle', this.scrollPane).height(this._calculateVScrollbarBackgroundMiddleHeight());
			
            this.vHandleFixedHeights = this._calculateHandleFixedHeights();
            
            this.resizeHandle();
			
            // Allows mouseInit to place mouse listeners on the scrollbar instead of the whole view.
            if (this.scrollBarInclArrows != null)
                this.element = this.scrollBarInclArrows;
            else
                this.element = this.scrollbar;
            this._mouseInit();
            
            this._setScrollbarVisibility();            
        },
		
		/*
		 * public: Moves the handle and content so target is at the top of the view.
		*/
		scrollTo: function(categoryTarget) {		    		        		    
			var categoryPosition = (($(categoryTarget, this.scrollContent).offset().top - this.scrollContent.offset().top) / this.scrollContent.outerHeight() ) * this.scrollbar.height();
			this._scrollTo(categoryPosition);			
		},
		
		/*
		 * public: Slowly moves the handle and content so target is at the top of the view. Steps and factor for movement is configurable through options.
		*/		
		slowScrollTo:function(categoryTarget){
		    var categoryPosition = (($(categoryTarget, this.scrollContent).offset().top - this.scrollContent.offset().top) / this.scrollContent.outerHeight() ) * this.scrollbar.height();
			this._slowScrollTo(categoryPosition);
		},		
		
        /*
			* public: Resizes handle after height of content has changed.
		*/
        resizeHandle: function() {                                  
            this.handleHeight = this._calculateHandleHeight();
            this.handleElement.height(this.handleHeight);
            $('.vScrollbarHandleBackgroundMiddle', this.handleElement).height(this.handleHeight - this.vHandleFixedHeights.topHeight - this.vHandleFixedHeights.bottomHeight);
                        
            this._scrollTo(this._calculateHandlePosition());
			
            this._setScrollbarVisibility();            
        }, 
        
        /*
			Fix problem in safari, truncated accordion menu.        
		*/
        safariFix: function () {
            this.scrollContent.css("margin-top", "1px");
            this._scroll();            
        },				
        
		_scrollTo: function(targetPos) {
			this._moveHandle(targetPos);
			this._scroll();
			this.handleAt = this._calculateHandlePosition();			
		},
		
		_slowScrollTo: function(targetPos) {						
			var diff = targetPos - this.handleAt;
			var oldHandleAt = this.handleAt;
			this._scrollTo(this.handleAt + diff * (Math.abs(diff) < 1 ? 1 : this.options.slowScrollFactor));
			
			if (Math.abs(diff) < 1 || this.handleAt == oldHandleAt)
				return;
				
			var self = this;
			this.slowScrollTimer = setTimeout(function() { self._slowScrollTo(targetPos); }, this.options.slowScrollTimestep);
		},
		
		_calculateVScrollbarBackgroundMiddleHeight: function() {
			return this.scrollbar.height() - $('.vScrollbarBackgroundTop', this.scrollPane).height() - $('.vScrollbarBackgroundBottom', this.scrollPane).height();
		},
		
		_calculateHandleFixedHeights: function() {
			return {topHeight: $('.vScrollbarHandleBackgroundTop', this.handleElement).height(), bottomHeight: $('.vScrollbarHandleBackgroundBottom', this.handleElement).height()};
		},
	
        _setScrollbarVisibility: function() {
            if (!this._scrollbarNeeded())
                this.scrollBarInclArrows.css("visibility", "hidden");            
            else
                this.scrollBarInclArrows.css("visibility", "visible");
        },
    
        _scrollbarNeeded: function() {
            return this.scrollContent.outerHeight() > this.options.scrollViewHeight;
        },       
    
        _calculateHandleHeight: function() {    		
			return ( this.options.scrollViewHeight / this.scrollContent.outerHeight() ) * this.scrollbar.height();
        },        
    
        _isMouseOverHandle: function() {
            var handleTop = this.handleElement.offset().top;      
            return ( handleTop < this.mouseCapturedAt && this.mouseCapturedAt < handleTop + this.handleHeight);
        },
        
        _isMouseOverDownArrow: function() {
            var downArrowTopPos = this.scrollbar.offset().top+this.scrollBarInclArrows.height()-(2*this.vArrowHeight);                      
            return this.mouseCapturedAt>downArrowTopPos;                        
        },
        
        _isMouseOverUpArrow: function() {
            var upArrowBottomPos = this.scrollbar.offset().top;                      
            return this.mouseCapturedAt<upArrowBottomPos;                        
        },
    
        _calculateHandlePosition: function() {
            return this.handleElement.offset().top - this.scrollbar.offset().top;    
        },
    
        _moveHandle: function(marginTop) {
            this.handleElement.css("margin-top", Math.min(Math.max(0, marginTop), Math.max(0, this.scrollbar.height() - this.handleHeight)));  
        },
    
        _scroll: function() {      
	        var currentScroll = this.handleElement.offset().top - this.scrollbar.offset().top;	    	    	    
	        var scrollPercentage = currentScroll / this.scrollbar.height();
	        var scrollTop = scrollPercentage * this.scrollContent.outerHeight();	    
	        this.scrollContent.css("margin-top", -scrollTop);	        
	    },
    
        _mouseCapture: function(event) {
			if (this.slowScrollTimer)
				clearTimeout(this.slowScrollTimer);
			
			this.mouseCapturedAt = event.pageY;			
            
            if (this._isMouseOverHandle())
			    return true;
			
			if (this._isMouseOverDownArrow())
			    this._moveHandle(this.handleAt+10)
			
			if (this._isMouseOverUpArrow())
			    this._moveHandle(this.handleAt-10)
			    
            if (!this._isMouseOverUpArrow() && !this._isMouseOverDownArrow())
                this._moveHandle(this.mouseCapturedAt - this.scrollbar.offset().top - this.handleHeight/2);
            this._scroll();
            this.handleAt = this._calculateHandlePosition();
			return false;
	    },
    
        _mouseStart: function(event) {
            if (!this.handleAt)
                this.handleAt = this._calculateHandlePosition();
			return true;
		},
		
		_mouseDrag: function(event) {		  		  
		    this._moveHandle(this.handleAt + ( event.pageY - this.mouseCapturedAt ));
		    this._scroll();
		    return false;
	    },

	    _mouseStop: function(event) {      
            this.handleAt = this._calculateHandlePosition();
		    return false;
	    }
    }));
  
    $.extend($.ui.scrollbar, {  	
  	    version: "1.6rc6",  	
  	    defaults: {  		  		
  		    scrollViewHeight: 200,
  		    scrollViewWidth: 200,
  		    distance: 0,
			showArrows: false,
			slowScrollFactor: 1/25,
			slowScrollTimestep: 10
  	    }
    });
}) (jQuery) // Call with jQuery as argument so $ inside will refer to the jQuery object even if $ is overridden.