/**
 * Copyright (c) 2009 Miguel Guerreiro (miguel.guerreiro@gmail.com)
 * Licensed under the GPL (http://www.opensource.org/licenses/gpl-license.php) license.
 *
 * @author: Miguel Guerreiro
 * @revision: 0091
 * @version: 0.9.1
 * @requires: jQuery 1.4+
 */

(function($) {
	$.event.mousewheel = {
		giveFocus: function(el,up,down,preventDefault) {
			if (el._handleMousewheel) {
				$(el).unmousewheel();
			}
			if (preventDefault==window.undefined && down && down.constructor!=Function) {
				preventDefault=down;
				down=null;
			}
			el._handleMousewheel=function(ev) {
				if (!ev) {
					ev = window.event;
				}
				if (preventDefault) {
					if (ev.preventDefault) {
						ev.preventDefault();
					} else {
						ev.returnValue=false;
					}
				}
				var delta=0;
				if (ev.wheelDelta) {
					delta=ev.wheelDelta/120;
				} else {
					if (ev.detail) {
						delta=-ev.detail/3;
					}
				}
				if (up && (delta > 0 || !down)) {
					up.apply(el, [ev, delta]);
				} else {
					if (down && delta < 0) {
						down.apply(el, [ev, delta]);
					}
				}
			};
			if (window.addEventListener) {
				window.addEventListener('DOMMouseScroll', el._handleMousewheel, false);
			}
			window.onmousewheel=document.onmousewheel=el._handleMousewheel;
		},
		removeFocus: function(el) {
			if (!el._handleMousewheel) {
				return;
			}
			if (window.removeEventListener) {
				window.removeEventListener('DOMMouseScroll', el._handleMousewheel, false);
			}
			window.onmousewheel=document.onmousewheel=null;
			el._handleMousewheel=null;
		}
	},
	$.fn.scrollbar = function(options) {
		var $parentElem = this,
			originalHTML = $parentElem.html();
		$parentElem.html('');
		var defaultSettings = {
				width: $parentElem.width(),
				height: $parentElem.height(),
				url: '',
				background: false,
				style: {
					padding: {
						top: 0,
						right: 0,
						bottom: 0,
						left: 0
					}
				},
				arrow: {
					width: 0,
					height: 0,
					color: 'transparent',
					imageUp: false,
					imageDown: false
				},
				scroller: {
					width: 0,
					height: 0,
					color: 'transparent',
					image: false
				},
				scrollbar: {
					width: 0,
					height: $parentElem.height(),
					step: 0
				}
			};
		var settings = $.extend(true, defaultSettings, options);
		var parentID = $parentElem.attr('id');
		var $container = $('<div/>',{
				id: parentID+'_scrollbar_wrap',
				css: {
					float: 'left',
					width: settings.width+'px',
					height: settings.height+'px',
					overflow: 'hidden'
				}
			}).appendTo($parentElem);
		var $containerHtml = $('<div/>',{
				id: parentID+'_scrollbar_html',
				css: {
					float: 'left',
					width: (settings.width-
							settings.scrollbar.width-
							settings.style.padding.left-
							settings.style.padding.right)+'px',
					padding: settings.style.padding.top+'px '+
						settings.style.padding.right+'px '+
						settings.style.padding.bottom+'px '+
						settings.style.padding.left+'px'
				},
				html: originalHTML 
			}).appendTo($container);
		var $scrollbar = $('<div/>',{
				id: parentID+'_scrollbar_scroll',
				css: {
					float: 'right',
					width: settings.scrollbar.width+'px',
					height: settings.scrollbar.height+'px'
				}
			}).appendTo($container);
		var $scrollbarUp = $('<div/>',{
				id: parentID+'_scrollbar_scroll_up',
				css: {
					float: 'left',
					width: settings.arrow.width+'px',
					height: settings.arrow.height+'px',
					background: 'transparent '+(settings.arrow.imageUp?'url(\''+settings.url+'/'+settings.arrow.imageUp+'\')':'none')+' scroll no-repeat '+(settings.arrow.imageUp?'-'+settings.arrow.width+'px':'0')+' 0',
					cursor: 'pointer',
					overflow: 'hidden'
				}
			}).appendTo($scrollbar);
		var $scrollbarTrack = $('<div/>',{
				id: parentID+'_scrollbar_scroll_track',
				css: {
					float: 'left',
					width: settings.scrollbar.width+'px',
					height: (settings.height-(settings.arrow.height*2))+'px',
					background: 'transparent '+(settings.background?'url(\''+settings.url+'/'+settings.background+'\')':'none')+' scroll repeat-y 0px 0px'
				}
			}).appendTo($scrollbar);
		var $scrollbarDown = $('<div/>',{
				id: parentID+'_scrollbar_scroll_dn',
				css: {
					float: 'left',
					width: settings.arrow.width+'px',
					height: settings.arrow.height+'px',
					background: settings.arrow.color+' '+(settings.arrow.imageDown?'url(\''+settings.url+'/'+settings.arrow.imageDown+'\')':'none')+' scroll no-repeat 0px 0px',
					cursor: 'pointer',
					overflow: 'hidden'
				}
			}).appendTo($scrollbar);
		var $scrollbarPos = $('<div/>',{
				id: parentID+'_scrollbar_scroll_pos',
				css: {
					float: 'left',
					width: settings.scroller.width+'px',
					height: settings.scroller.height+'px',
					position: 'relative',
					top: '0',
					left: ((settings.scrollbar.width-settings.scroller.width)/2)+'px',
					background: settings.scroller.color+' '+(settings.scroller.image?'url(\''+settings.url+'/'+settings.scroller.image+'\')':'none')+' scroll no-repeat 0px 0px',
					cursor: 'pointer'
				}
			}).appendTo($scrollbarTrack);
		var mHeight=($containerHtml.height()-settings.height);
		var mScroll=settings.height-(settings.arrow.height*2)-settings.scroller.height;
		var mStep=Math.ceil(mHeight/settings.scrollbar.step);
		var nStep=0;
		var scrollPos=0;
		var minOffset=$scrollbarTrack.offset().top+(settings.scroller.height/2);
		var maxOffset=minOffset+mScroll;
		var mouseEvent;
		var getPos=function(event, c) {
				var p=c=='X'?'Left':'Top';
				return event['page'+c]||
					(event['client'+c]+(document.documentElement['scroll'+p]||
					document.body['scroll'+p]))||0;
			};
		var scrollUp=function() {
				if (nStep>0) {
					nStep--;
					var dPercent=nStep/mStep;
					$containerHtml.css({
						marginTop: '-'+(dPercent*mHeight)+'px'
					});
					$scrollbarPos.css({
						top: (dPercent*mScroll)+'px'
					});
					if (settings.arrow.imageDown) {
						$scrollbarDown.css({
							backgroundPosition: '0 0'
						});
					} else {
						$scrollbarDown.css({
							backgroundColor: settings.arrow.color
						});
					}
					if (settings.arrow.imageUp) {
						$scrollbarUp.css({
							backgroundPosition: '0 0'
						});
					} else {
						$scrollbarUp.css({
							backgroundColor: settings.arrow.color
						});
					}
				} else {
					if (settings.arrow.imageUp) {
						$scrollbarUp.css({
							backgroundPosition: '-'+settings.arrow.width+'px 0'
						});
					} else {
						$scrollbarUp.css({
							backgroundColor: 'transparent'
						});
					}
				}
			};
		var scrollDown=function() {
				if (nStep<mStep) {
					nStep++;
					var dPercent = nStep/mStep;
					$containerHtml.css({
						marginTop: '-'+(dPercent*mHeight)+'px'
					});
					$scrollbarPos.css({
						top: (dPercent*mScroll)+'px'
					});
					if (settings.arrow.imageUp) {
						$scrollbarUp.css({
							backgroundPosition: '0 0'
						});
					} else {
						$scrollbarUp.css({
							backgroundColor: settings.arrow.color
						});
					}
					if (settings.arrow.imageDown) {
						$scrollbarDown.css({
							backgroundPosition: '0 0'
						});
					} else {
						$scrollbarDown.css({
							backgroundColor: settings.arrow.color
						});
					}
				} else {
					if (settings.arrow.imageDown) {
						$scrollbarDown.css({
							backgroundPosition: '-'+settings.arrow.width+'px 0'
						});
					} else {
						$scrollbarDown.css({
							backgroundColor: 'transparent'
						});
					}
				}
			};
		var dragMeNot=function() {
				return false;
			};
		var dragUpdate=function(e) {
				var toPos=getPos(e, 'Y');
				// if it is in range
				if (toPos>=minOffset && toPos<=maxOffset) {
					// if it is near enough to the top...
					if (toPos<(minOffset+10)) {
						if (settings.arrow.imageUp) {
							$scrollbarUp.css({
								backgroundPosition: '-'+settings.arrow.width+'px 0'
							});
						} else {
							$scrollbarUp.css({
								backgroundColor: 'transparent'
							});
						}
						toPos = minOffset;
					} else {
						if (settings.arrow.imageUp) {
							$scrollbarUp.css({
								backgroundPosition: '0 0'
							});
						} else {
							$scrollbarUp.css({
								backgroundColor: settings.arrow.color
							});
						}
					}
					// if it is near enough to the bottom
					if (toPos>(maxOffset-10)) {
						if (settings.arrow.imageDown) {
							$scrollbarDown.css({
								backgroundPosition: '-'+settings.arrow.width+'px 0'
							});
						} else {
							$scrollbarDown.css({
								backgroundColor: 'transparent'
							});
						}
						toPos = maxOffset;
					} else {
						if (settings.arrow.imageDown) {
							$scrollbarDown.css({
								backgroundPosition: '0 0'
							});
						} else {
							$scrollbarDown.css({
								backgroundColor: settings.arrow.color
							});
						}
					}
					// update the text & scroll
					scrollPos = (toPos-minOffset);
					dPercent = scrollPos/(maxOffset-minOffset);
					nStep = Math.round(dPercent*mStep);
					$containerHtml.css({
						marginTop: '-'+(dPercent*mHeight)+'px'
					});
					$scrollbarPos.css({
						top: (dPercent*mScroll)+'px'
					});
				} else {
					if (toPos<minOffset) {
						if (settings.arrow.imageUp) {
							$scrollbarUp.css({
								backgroundPosition: '-'+settings.arrow.width+'px 0'
							});
						} else {
							$scrollbarUp.css({
								backgroundColor: 'transparent'
							});
						}
					}
					if (toPos>maxOffset) {
						if (settings.arrow.imageDown) {
							$scrollbarDown.css({
								backgroundPosition: '-'+settings.arrow.width+'px 0'
							});
						} else {
							$scrollbarDown.css({
								backgroundColor: 'transparent'
							});
						}
					}
				}
				
			};
		var dragStart=function(e) {
				$('html').bind('mouseup', dragStop).bind('mousemove', dragUpdate);
				if ($.browser.msie) {
					$('html').bind('dragstart', dragMeNot).bind('selectstart', dragMeNot);
				}
				dragUpdate(e);
				return false;
			};
		var dragStop=function() {
				$('html').unbind('mouseup', dragStop).unbind('mousemove', dragUpdate);
				if ($.browser.msie) {
					$('html').bind('dragstart', dragMeNot).bind('selectstart', dragMeNot);
				}
				return false;
			};
		if (mHeight<=0) {
			if (settings.arrow.imageUp) {
				$scrollbarUp.css({
					backgroundPosition: '-'+(settings.arrow.width*2)+'px 0',
					cursor: 'default'
				});
			} else {
				$scrollbarUp.css({
					backgroundColor: 'transparent',
					cursor: 'default'
				});
			}
			if (settings.arrow.imageDown) {
				$scrollbarDown.css({
					backgroundPosition: '-'+(settings.arrow.width*2)+'px 0',
					cursor: 'default'
				});
			} else {
				$scrollbarDown.css({
					backgroundColor: 'transparent',
					cursor: 'default'
				});
			}
			$scrollbarPos.remove();
		} else {
			$scrollbarUp.click(scrollUp);
			$scrollbarUp.mousedown(function() {
				mouseEvent = setInterval(scrollUp,100);
			}).mouseup(function() {
				mouseEvent = clearInterval(mouseEvent);
			});
			$scrollbarDown.click(scrollDown);
			$scrollbarDown.mousedown(function() {
				mouseEvent = setInterval(scrollDown,100);
			}).mouseup(function() {
				mouseEvent = clearInterval(mouseEvent);
			});
			$scrollbarTrack.bind('mousedown', dragStart);
			$container.hover(function() {
				$.event.mousewheel.giveFocus(this, scrollUp, scrollDown, true);
			},function() {
				$.event.mousewheel.removeFocus(this);
			});
		};
		return this;
	}
})(jQuery);

