/* 
 * jQuery UI - Scrollbar plugin
 * Create custom scrollbars that behave like native scrollbars
 *
 * @author Zach Waugh <zwaugh@gmail.com>
 * @version 1.2
 * @requires ui.core.js
 *
 * Last Updated: 1/26/2010 by Zach Waugh
 *
 * Copyright (c) 2009 Zach Waugh MIT License
 */

(function($)
{
	/**
	 * Main plugin function
	 */
	$.widget("ui.scrollbar", 
	{
		_init: function()
		{
			var self = this, options = this.options;
			this._isDragging = false;
			this._handleOffset = 0;
			this._scrollbarContents = this.element.find('.ui-scrollbar-contents');
			this._timer = null;
			this._isVertical = options.vertical;
			
			if (this._isVertical)
			{
				this._initVertical();
			}
			else
			{
				this._initHorizontal();
			}
		}, 
		
		/**
		 * Initialize a vertical scrollbar
		 */
		_initVertical: function ()
		{
			var self = this;
			this._computeSize();
					
			// Only add scrollbar if needed
			if (this._needsScrollbar())
			{
				this.element.addClass('ui-scrollable').css('overflow', this.options.overflow);

				var scrollbar = '<div class="ui-scrollbar ui-scrollbar-vertical">';
				scrollbar += '<a href="#" class="ui-scrollbar-button-up"></a>';
				scrollbar += '<div class="ui-scrollbar-track" style="top:' + this.options.buttonHeight + 'px;height:' + this._trackHeight + 'px;">';
				scrollbar += '<div class="ui-scrollbar-handle" style="height:' + this._handleHeight + 'px;"></div>';
				scrollbar += '</div>'; // .ui-scrollbar-track
				scrollbar += '<a href="#" class="ui-scrollbar-button-down"></a>';
				scrollbar += '</div>'; // .ui-scrollbar
			
				this._scrollbarContents.css({position: 'absolute', top: 0});
				this.element.prepend(scrollbar);

				// cache references to scrollbar pieces
				this._scrollbar = $('.ui-scrollbar', this.element);
				this._scrollbarTrack = $('.ui-scrollbar-track', this.element);
				this._scrollbarHandle = $('.ui-scrollbar-handle', this.element);
		
				// Bind Events
				this._scrollbarTrack.mousedown(function(event) { return self._start(event); });
				this.element.mousewheel(function(event, delta) { return self._scrollWheelVertical(event, delta); });
			
				this.element.find('.ui-scrollbar-button-up').mousedown(function(event) { return self._goUp(); }).mouseup(function() { return self._clearTimer(); }).click(function(){ return false; });
				this.element.find('.ui-scrollbar-button-down').mousedown(function(event) { return self._goDown(); }).mouseup(function() { return self._clearTimer(); }).click(function(){ return false; });
			}
		},
	
		/**
		 * Initialize a horizontal scrollbar
		 */
		_initHorizontal: function ()
		{
			var self = this;

			// Only add scrollbar if needed
			if (this._needsScrollbar())
			{
				this.element.addClass('ui-scrollable').css('overflow', this.options.overflow);
				this._computeSize();
			
				var scrollbar = '<div class="ui-scrollbar ui-scrollbar-horizontal">';
				scrollbar += '<a href="#" class="ui-scrollbar-button-left"></a>';
				scrollbar += '<div class="ui-scrollbar-track" style="left:' + this.options.buttonWidth + 'px;width:' + this._trackWidth + 'px;">';
				scrollbar += '<div class="ui-scrollbar-handle" style="width:' + this._handleWidth + 'px;"></div>';
				scrollbar += '</div>'; // .ui-scrollbar-track
				scrollbar += '<a href="#" class="ui-scrollbar-button-right"></a>';
				scrollbar += '</div>'; // .ui-scrollbar
			
				this._scrollbarContents.css({position: 'absolute', left: 0})
				this.element.prepend(scrollbar);

				// cache references to scrollbar pieces
				this._scrollbar = $('.ui-scrollbar', this.element);
				this._scrollbarTrack = $('.ui-scrollbar-track', this.element);
				this._scrollbarHandle = $('.ui-scrollbar-handle', this.element);
		
				// Bind Events
				this._scrollbarTrack.mousedown(function(event) { return self._start(event); });
				this.element.mousewheel(function(event, delta) { return self._scrollWheelHorizontal(event, delta); });
			
				this.element.find('.ui-scrollbar-button-left').mousedown(function(event) { return self._goLeft(); }).mouseup(function() { return self._clearTimer(); }).click(function(){ return false; });
				this.element.find('.ui-scrollbar-button-right').mousedown(function(event) { return self._goRight(); }).mouseup(function() { return self._clearTimer(); }).click(function(){ return false; });
			}
		},

		/**
		 * Event handler - mousedown
		 * Called when mouse is clicked in scrollbar or scrollbar handle
		 * @params event (jQuery Event Object)
		 */
		_start: function(event)
		{
			var self = this;
		
			$('html').mouseup(function(event) { return self._stop(event); }).mousemove(function(event) { return self._drag(event); }).mouseleave(function(event) { return self._stop(event); });

			// scroll contents if clicked in scrollbar track and not handle
			if (event.target == this._scrollbarTrack.get(0))
			{
				var offset = this._relativeMousePosition(event);

				if (this.options.vertical)
				{
					this._scrollVertical(offset);
				}
				else
				{
					this._scrollHorizontal(offset);
				}
			}
			else
			{
				this._handleOffset = this._calcHandleOffset(event);
			}

			this._isDragging = true;

			return false;
		},

		/**
		 * Event Handler - mousemove
		 * Called while mouse is moving after startDrag event
		 */
		_drag: function(event)
		{
			if (this._isDragging)
			{
				var position = this._relativeMousePosition(event) - this._handleOffset;
			
				if (this.options.vertical)
				{
					this._scrollVertical(position);
				}
				else
				{
					this._scrollHorizontal(position);
				}
			}

			return false;
		},

		/**
		 * Event Handler - mouseup
		 * unbind events and change state
		 */
		_stop: function(event)
		{
			if (this._isDragging)
			{
				// unbind events when dragging ends
				$('html').unbind('mouseup').unbind('mousemove').unbind('mouseleave');

				this._isDragging = false;
			}

			return false;
		},
	
		/**
		 * Function the actually scrolls the content and positions the handle (Vertically)
		 */
		_scrollVertical: function(top)
		{
			if (top < 0)
			{
				top = 0;
			}
			else if (top >= (this._scrollbarTrack.height() - this._scrollbarHandle.height()))
			{
				top = this._scrollbarTrack.height() - this._scrollbarHandle.height();
			}

			// Set handle position
			this._scrollbarHandle.css({top: top});

			// Scroll the contents
			this._scrollContentsVertical(top);
		},
	
		/**
		 * Function the actually scrolls the content and positions the handle (Horizontally)
		 */
		_scrollHorizontal: function(left)
		{
			if (left < 0)
			{
				left = 0;
			}
			else if (left >= (this._scrollbarTrack.width() - this._scrollbarHandle.width()))
			{
				left = this._scrollbarTrack.width() - this._scrollbarHandle.width();
			}

			// Set handle position
			this._scrollbarHandle.css({left: left});

			// Scroll the contents
			this._scrollContentsHorizontal(left);
		},

		/**
		 * Scroll content pane vertically
		 */
		_scrollContentsVertical: function(top)
		{
			var scrollbar_height = this._scrollbarTrack.height() - this._scrollbarHandle.height();
			var percent = top / scrollbar_height;
			var contents_top = (this._contentsHeight - this.element.height()) * percent * -1;

			this._scrollbarContents.css({top: contents_top});
		},

		/**
		 * Scroll content pane horizontally
		 */
		_scrollContentsHorizontal: function(left)
		{
			var scrollbar_width = this._scrollbarTrack.width() - this._scrollbarHandle.width();
			var percent = left / scrollbar_width;
			var contents_left = (this._contentsWidth - this.element.width()) * percent * -1;

			this._scrollbarContents.css({left: contents_left});
		},
	
		/**
		 * Public function
		 * Scroll to the beginning - either top or left - of a scroll pane
		 */
		scrollToBeginning: function()
		{
			if (this._isVertical)
			{
				this._scrollVertical(0);
			}
			else
			{
				this._scrollHorizontal(0);
			}
		},

		/**
		 * Handle moving left by clicking scrollbar arrow
		 */
		_goLeft: function ()
		{
			var self = this;
		
			// Scroll once immediately
			this._scrollHorizontal(parseInt(this._scrollbarHandle.css('left')) - this.options.scrollInterval);
		
			this._timer = setInterval(function() {
				self._scrollHorizontal(parseInt(self._scrollbarHandle.css('left')) - self.options.scrollInterval);
			}, 50);
		
			return false;
		},
	
		/**
		 * Handle moving right by clicking scrollbar arrow
		 */
		_goRight: function ()
		{
			var self = this;
		
			// Scroll once immediately
			this._scrollHorizontal(parseInt(this._scrollbarHandle.css('left')) + this.options.scrollInterval);
		
			// Setup timer to keep scrolling while mouse is down
			this._timer = setInterval(function() {
				self._scrollHorizontal(parseInt(self._scrollbarHandle.css('left')) + self.options.scrollInterval);
			}, 50);
		
			return false;
		},
	
		/**
		 * Handle moving up by clicking scrollbar arrow
		 */
		_goUp: function ()
		{
			var self = this;
		
			// Scroll once immediately
			this._scrollVertical(parseInt(this._scrollbarHandle.css('top')) - this.options.scrollInterval);
		
			this._timer = setInterval(function() {
				self._scrollVertical(parseInt(self._scrollbarHandle.css('top')) - self.options.scrollInterval);
			}, 50);
		
			return false;
		},
	
		/**
		 * Handle moving down by clicking scrollbar arrow
		 */
		_goDown: function ()
		{
			var self = this;
		
			// Scroll once immediately
			this._scrollVertical(parseInt(this._scrollbarHandle.css('top')) + this.options.scrollInterval);
		
			// Setup timer to keep scrolling while mouse is down
			this._timer = setInterval(function() {
				self._scrollVertical(parseInt(self._scrollbarHandle.css('top')) + self.options.scrollInterval);
			}, 50);
		
			return false;
		},
	
		_clearTimer: function ()
		{
			clearInterval(this._timer);
		
			return false;
		},
	
		/**
		 * Event Handler - mousewheel (vertical)
		 * respond to mousewheel moving
		 */
		_scrollWheelVertical: function(event, delta)
		{
			var top;

			if (delta > 0)
			{
				top = parseInt(this._scrollbarHandle.css('top'));
				top -= (delta * this.options.scrollInterval);
			}
			else
			{
				top = parseInt(this._scrollbarHandle.css('top'));
				top += (delta * -1 * this.options.scrollInterval);
			}

			this._scrollVertical(top);

			return false;
		},

		/**
		 * Event Handler - mousewheel (horizontal)
		 * respond to mousewheel moving
		 */
		_scrollWheelHorizontal: function(event, delta)
		{
			var left;

			if (delta > 0)
			{
				left = parseInt(this._scrollbarHandle.css('left'));
				left -= (delta * this.options.scrollInterval);
			}
			else
			{
				left = parseInt(this._scrollbarHandle.css('left'));
				left += (delta * -1 * this.options.scrollInterval);
			}

			this._scrollHorizontal(left);

			return false;
		},
	
		/**
		 * Calculate the absolute mouse position in the window to the relative position in the scrollbar
		 */
		_relativeMousePosition: function(event)
		{
			if (this._isVertical)
			{
				return event.pageY - this.element.offset().top - this.options.buttonWidth;
			}
			else
			{
				return event.pageX - this.element.offset().left - this.options.buttonWidth;
			}
		},

		/**
		 * Calculate where the mouse is clicked within the scroll handle
		 */
		_calcHandleOffset: function(event)
		{
			var position = (this.options.vertical) ? 'top' : 'left';
			return this._relativeMousePosition(event) - parseInt(this._scrollbarHandle.css(position));
		},
	
		/**
		 * Check whether pane needs a scrollbar and the size
		 */
		_needsScrollbar: function()
		{
			if (this._isVertical)
			{
				return (this._contentsHeight > this._windowHeight);
			}
			else
			{	
				return (this._contentsWidth > this._windowWidth);
			}
		},
	
		/**
		 * Compute size of scrollbar track and handle
		 */
		_computeSize: function()
		{
			if (this._isVertical)
			{
				this._windowHeight = this.element.innerHeight();
				this._contentsHeight = this._scrollbarContents.outerHeight(true);
			
				this._trackHeight = this._windowHeight - (this.options.buttonHeight * 2);
				this._handleHeight = (this._windowHeight / this._contentsHeight) * this._trackHeight;
				
				if (this._handleHeight > this._trackHeight)
				{
					this._handleHeight = this._trackHeight;
				}
			}
			else
			{
				// Get width of scrollable area
				this._windowWidth = this.element.innerWidth();

				// Compute actual width of scrollbar contents
				// TODO: code assumes contents is wrapped in a ul - should make option
				this._contentsWidth = this._scrollbarContents.find('li').outerWidth(true) * this._scrollbarContents.find('li').length;
			
				// Update container with actual width
				this._scrollbarContents.css('width', this._contentsWidth);
			
				this._trackWidth = this._windowWidth - (this.options.buttonWidth * 2);
				this._handleWidth = (this._windowWidth / this._contentsWidth) * this._trackWidth;
				
				if (this._handleWidth > this._trackWidth)
				{
					this._handleWidth = this._trackWidth;
				}
			}
		},
	
		/**
		 * Public function
		 * recalculate sizes and update display
		 */
		refresh: function()
		{
			this._computeSize();
		
			if (this._isVertical)
			{
				this._scrollbarTrack.css('height', this._trackHeight);
				this._scrollbarHandle.css('height', this._handleHeight);
				
				if (this._needsScrollbar())
				{
					this._scrollbar.show();
				}
				else
				{
					this._scrollbar.hide();
				}
			}
			else
			{
				this._scrollbarTrack.css('width', this._trackWidth);
				this._scrollbarHandle.css('width', this._handleWidth);
			}
		}
	});
})(jQuery);

$.extend($.ui.scrollbar, {
	version: "1.7.1",
	defaults: {
		vertical: true,
		buttonWidth: 18,
		buttonHeight: 18,
		scrollInterval: 30,
		overflow: 'hidden'
	}
});


/* Copyright (c) 2009 Brandon Aaron (http://brandonaaron.net)
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
 * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
 *
 * Version: 3.0.2
 * 
 * Requires: 1.2.2+
 */
(function(c){var a=["DOMMouseScroll","mousewheel"];c.event.special.mousewheel={setup:function(){if(this.addEventListener){for(var d=a.length;d;){this.addEventListener(a[--d],b,false)}}else{this.onmousewheel=b}},teardown:function(){if(this.removeEventListener){for(var d=a.length;d;){this.removeEventListener(a[--d],b,false)}}else{this.onmousewheel=null}}};c.fn.extend({mousewheel:function(d){return d?this.bind("mousewheel",d):this.trigger("mousewheel")},unmousewheel:function(d){return this.unbind("mousewheel",d)}});function b(f){var d=[].slice.call(arguments,1),g=0,e=true;f=c.event.fix(f||window.event);f.type="mousewheel";if(f.wheelDelta){g=f.wheelDelta/120}if(f.detail){g=-f.detail/3}d.unshift(f,g);return c.event.handle.apply(this,d)}})(jQuery);