//If the scroll area has images w/o defined widht/height, the scrollpane should be instantiated on window.load to ensure correct dimensions of the scrollpane

(function($){

	var 
		_undefined,
		_document = $(document);
	
	$.ScrollPane = function(_container, params){
		
		if (!_container || !_container.get(0)) 
			throw new Error("$.ScrollPane: container not set");
			
		//start:Init 
			var 
				_self = this,
				_settings = $.extend({},this.defaults,params),
				_size = 0, _knobRatio = 0, _endPosition = 0, _mousePos = 0, _stepDirection = 1, 
				_buttonSize = 0, _ratioCorrection = 1, _scrollOffset = 0,
				_WoH, _LoT, _XoY, _SLoST, _scroller, _items, _scrollbar, _scrollBack, _scrollForward, 
				_scrollTrack, _scrollTrackInner, _knobWrapper, _knobInner, _buttonDown, _trackDown, _tracker;
			
			_container.addClass("scrollpane").attr('dir','ltr');
			
			
			//set properties so don't have to use if else all the time
			if (_settings.horizontal){
				_WoH = "width";
				_LoT = "left";
				_XoY = "pageX";
				_SLoST = "scrollLeft";
				_container.addClass("horizontal");
			}
			else {
				_WoH = "height";
				_LoT = "top";
				_XoY = "pageY";
				_SLoST = "scrollTop";
			}
			
			_container.data("ScrollPane", this);
			_setScroller();
			
			//this is placed here to avoid an IE positioning bug where the width was not getting calculated correctly with the rtl class
			if (_settings.rtl) _container.addClass("rtl");
			
			_container.click(function(e){
				e.stopPropagation();
				_document.bind("keydown", _keyScroll).trigger("click");
			}).scroll(_scrollFix);
			
			if (_settings.mousewheel){
				_container.mousewheel(_mousewheel);
			}
				
			_document.mouseup(function(e){
				_document.unbind("mousemove", _drag);
				_document.unbind("keydown", _keyScroll);
				clearInterval(_buttonDown);
				_clearTrackClick();
				_mousePos = 0;
			});
			
		//start:Public
			//call when items are added or removed from the scroll area
			this.adjustScroller = function(){
				_removeScroller();
				_setScroller();
			}
			
			//accepts number in pixels or $ extended DOM element
			this.scrollTo = function(to){
				if (typeof to == "number"){
					_scrollToPixel(to);
				}
				else if (typeof to == "object"){
					_scrollToItem(to);
				}
			}
		
			this.step = function(direction){
				//Math.round added to fix ie6 issue of overscrolling since pixels are rounded in css for ie6
				_self.scroll(direction * Math.round(_settings.stepSize *_knobRatio)); 
			}
			
			this.scroll = function(velocity){
				
				var 
					pos =  parseFloat(_knobWrapper.css(_LoT)) || 0, //accounts for parse fail on "auto"
					scroll = parseFloat(_scroller.css(_LoT)) || 0;
				
				if (pos + velocity <= 0){
					_knobWrapper.css(_LoT, 0);
					_scroller.css(_LoT, _scrollOffset);
				}
				else if (pos + velocity >= Math.floor(_endPosition)){
					_knobWrapper.css(_LoT, _endPosition);
					_scroller.css(_LoT, _scrollOffset -_endPosition/(_knobRatio*_ratioCorrection));
				}
				else {
					_knobWrapper.css(_LoT, pos + velocity);
					_scroller.css(_LoT, scroll - (velocity/_knobRatio*_ratioCorrection));
				}
			}

		//start:Private
			function _setDimension(){
				
				_scroller.css({
					position: 'absolute',
					top : "-9999em",
					left : "-9999em"
				});
				
				_size = _scroller[_WoH]();
			
				
				var childWidth = 0;
				_items.each(function(){ 
					childWidth += $(this).outerWidth();
				});
				
				if(childWidth > _size) {
					_size = childWidth;
				}				
				
				
				_scroller.css({
					position : "relative",
					top : "auto",
					left : "auto"
				});
			}
			
			function _removeScroller(){
				_items.each(function(){
					_scroller.before($(this));
				});
				_scroller.remove();
				_scrollbar.remove();
				_scrollbar = _undefined;
			}
			
			function _setScroller(){
				_container.wrapInner($("<div class=\"sp_scroller\"></div>"));
				_scroller = _container.children("div.sp_scroller");
				_items = _scroller.children();
				_setDimension();
				_scroller[_WoH](_size);
				_setScrollBar();
			}
			
			function _setScrollKnob(){
				
				var
					scrollDim = _scrollTrack[_WoH](),
					ratio = _container[_WoH]()/_size,
					dimension = scrollDim*ratio, //use calculation instead of knobRatio to account for scrollButtons
					corrected; 
					
				if (dimension >= _settings.minKnobDim){
					corrected = dimension;
					_ratioCorrection = 1;
				}				
				else {
					corrected = _settings.minKnobDim;
					_ratioCorrection = 1 + corrected/scrollDim - ratio;
				}
				
				_knobWrapper[_WoH](corrected);
				_endPosition = scrollDim - corrected;
			}
			
			function _setScrollBar(){
				
				_knobRatio = _container[_WoH]()/_size;
				_scrollOffset = _container[_SLoST]();
				
				if (_knobRatio < 0.99){
					if (_scrollbar == _undefined) _createScrollBar();
					_scrollbar.css("display", "block").css(_LoT, _scrollOffset);
					
					if (_settings.scrollButtons){
						_buttonSize = _scrollBack[_WoH](); //assuming buttons will be the same size!
						_scrollTrack[_WoH](_scrollbar[_WoH]() - _buttonSize * 2).css(_LoT , _buttonSize);
						_knobRatio = _scrollTrack[_WoH]()/_size;
					}
					else {
						_scrollTrack[_WoH]("100%");
					}
					_setScrollKnob();
				}
				else if (_scrollbar != _undefined){
					_scrollbar.css("display", "none");
				}
				
				if (_scrollbar != _undefined){
				
					if (_settings.barLocation == "left"){
						_scrollbar.css({left : _settings.barPosition, right : "auto", height : _container.height()})
					}
					else if (_settings.barLocation == "top"){
						_scrollbar.css({top : _settings.barPosition, bottom : "auto"});
					}
					else {
						if (_settings.horizontal){
							_scrollbar.css({bottom:_settings.barPosition});
						}
						else {
							_scrollbar.css({right:_settings.barPosition});
						}
					}
				}
			}
			
			function _bindScrollEvents(){
				if (_scrollbar != _undefined){
					_scrollTrack.mousedown(function(e){
						clearInterval(_trackDown);
						_trackDown = setInterval(function(){
							_tracker = e;
							_trackClick(e);
						}, 150); 
					}).mouseup(_trackClick);
					
					_knobWrapper.mousedown(function(e){
						e.preventDefault();
						e.stopPropagation();
						_document.bind("mousemove", _drag).bind("keydown", _keyScroll);
						_container.trigger("mousedown"); //since propagation is stopped, register the click event to the container
					});
					
					if (_settings.scrollButtons){
						_scrollBack.mousedown(function(){
							clearInterval(_buttonDown);
							_buttonDown = setInterval(function(){
								_self.step(-1*_stepDirection);
							}, 50);
						});
						
						_scrollForward.mousedown(function(){
							clearInterval(_buttonDown);
							_buttonDown = setInterval(function(){
								_self.step(1*_stepDirection);
							}, 50);
						});
					}
				}
			}
			
			function _createScrollBar(){
				_scrollbar = $("<div class=\"sp_bar\"></div>");		
				_scrollBack = $("<div class=\"sp_back\"></div>");
				_scrollForward = $("<div class=\"sp_forward\"></div>");
				_scrollTrack = $("<div class=\"sp_track\"></div>");
				_scrollTrackInner = $("<div class=\"sp_track_inner\"></div>");
				_knobWrapper = $("<div class=\"sp_knob\"></div>");
				_knobInner = $("<div class=\"sp_knob_inner\"></div>");
				
				_container.append(_scrollbar);
				if (_settings.scrollButtons){
					_scrollbar.append(_scrollBack);
					_scrollbar.append(_scrollForward);
				}
				
				_scrollbar.append(_scrollTrack);
				_scrollTrack.append(_scrollTrackInner);
				_scrollTrack.append(_knobWrapper);
				_knobWrapper.append(_knobInner);
				
				_bindScrollEvents();
			}
			
			function _drag(e){
				e.preventDefault(); //prevents highlighting while dragging the scroller
				var change = 0;				
				
				if (_mousePos == 0){
					_mousePos = e[_XoY];
				}
				
				change = e[_XoY] - _mousePos;
				_mousePos = e[_XoY];
				_self.scroll(change);
			}
			
			function _mousewheel(e, delta){
				e.preventDefault();
				_self.step(delta*-_stepDirection);
			}
			
			function _trackClick(e){
				var 
					pos = e[_XoY] - _scrollbar.offset()[_LoT],
					offset = _knobWrapper.position()[_LoT],
					dim = _knobWrapper[_WoH](),
					direction = 0;
				
				if (pos < offset){
					direction = -1;
				}
				else if (pos > offset + dim){
					direction = 1;
				}
				
				_self.scroll(direction * dim);
			}
			
			function _clearTrackClick(){
				clearInterval(_trackDown);
				
				//this is to account for a quick click on the track where the interval gets cleared before it executes
				if (_tracker){
					_tracker = 0;
				}
				else if ( _tracker == 0 ){
					_trackClick(_tracker);
				}
			}
			
			function _keyScroll(e){
				var dir = 0;
				
				if (e.keyCode == 37 || e.keyCode == 38){ //up/left
					dir = -1;
				}
				else if (e.keyCode == 39 || e.keyCode == 40){ //right/down
					dir = 1;
				}
				dir = dir*_stepDirection; //RTL reverse correction
				
				_self.step(dir);
			}
			
			function _scrollToPixel(pix){
				var num;
				if (pix <= 0){
					num = 0;
				}
				else if (pix >= _endPosition/_knobRatio){
					num = _endPosition;
				}
				else {
					num = pix*_knobRatio;
				}
				_knobWrapper.css(_LoT, num);
				_scroller.css(_LoT, -num/_knobRatio);
			}
			
			function _scrollToItem(el){
				if (!el.get(0)) throw new Error("$.ScrollPane: Element to scroll to does not exist.");
				var num = el.position().left;
				
				_scrollToPixel(num);
			}
			
			//used to account for tabbing through where the container gets scrolled automatically
			function _scrollFix(e){
				_scrollOffset = _container[_SLoST]();
				_scrollbar.css(_LoT, _scrollOffset);
				_knobWrapper.css(_LoT, _scrollOffset*_knobRatio);
			}
			
			//more RTL jazz
			if (_settings.rtl){
				_stepDirection = -1;
				if (_scrollbar != _undefined){
					_scrollToPixel(999999);
				}
			}
	};
	$.ScrollPane.prototype = {
		defaults : {
			horizontal : 1,
			barLocation : 0, //defaults to right for vertical, bottom for horizontal, can use "left" and "top" to override defaults
			barPosition : 0,
			stepSize : 20,
			rtl : 0,
			scrollButtons : 0,
			knobEndDim : 5,
			minKnobDim : 10,
			mousewheel : 0
		}
	};
	
	
})(jQuery);

(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);

