(function($) {
	
	var Scroll = function(content, options) {
		this.html = {};
		this.init(content, options);
	};
	
	Scroll.prototype = {
		
		// options
		increment : 10,
		scrolltype : 'incremental', // [incremental,position]
		axis : {y:true,x:false},
		
		// systems
		topInterval : null,
		leftInterval : null,
		percent : [0,0,0,0,0,0], 
		
		init : function(content, options) {

			if (content == document || content == window || content == $("body").get(0))
				content = $("body")./*css({overflow:'hidden'}).*/wrapInner("<div/>").children(":eq(0)")
			
			var self = $.extend(this, options),
			html = self.html,
			both = self.axis.x && self.axis.y;
			
			html.conteiner = $('<div/>')
				.addClass('wrapperEl')
				.insertBefore(content);
			
			html.content = $('<div/>')
				.addClass('contentEl')
				.append(content)
				.appendTo(html.conteiner);
				
			if (both){
				html.tambour = $('<div/>')
					.addClass('tambour')
					.appendTo(html.conteiner)
			}
				
			if (self.axis.y){
				html.content.mousewheel(function(e,delta){
						self.doScrollTop(delta, 1);
						setTimeout(function(){
							clearInterval(self.topInterval);
						},250);
						return false;
					});
			
				self.build(0)
			}
			
			if (self.axis.x){
				self.build(1)
			}
			
			$(window).bind('load resize', function(e) {
				// I 'love' IE 8 it fires resize before load
				self.loaded = self.loaded ? true : e.type == 'load';
				if (!self.loaded) 
					return;
				
				self.percent = [];
				
				html.content.css({
					height:html.conteiner.height()-(self.axis.x?html.scrollBarHorizontal.height():0),
					width:html.conteiner.width()-(self.axis.y?html.scrollBarVertical.width():0)
				})
				
				if (self.axis.y) {
					self.calc(0)
				}
			
				if (self.axis.x) {
					self.calc(1)
				}
				
							
			});		
		},
		
		calc : function (x) {
	        	var self = this, html = self.html,
	        	tl  = ['top','left'][x],
	        	ctl = ['Top','Left'][x],
	        	dr  = ['down','right'][x],
	        	cdr = ['Down','Right'][x],
	        	hw  = ['height','width'][x],
	        	chw = ['Height','Width'][x],
	        	cvh = ['Vertical','Horizontal'][x],
			
			haTL = html['scrollHandle'+ctl][hw](),
			haDR = html['scrollHandle'+cdr][hw](),
			midS = html['scrollHandleMiddle'+cvh][hw](),
			barS = html.content[hw]()-html[tl+'Btn'][hw]()-html[dr+'Btn'][hw](),
			content = html.content.get(0),
			realS = Math.round(barS * content['client'+chw] / content['scroll'+chw]),
			size = Math.max(realS, haTL + midS + haDR);
			
			// set real heights
			html['scrollHandleBG'+cvh][hw](size - haTL - haDR)
			html['scrollHandle'+cvh][hw](size);
			html['scrollBar'+cvh][hw](barS)
			html['scrollHandle'+cvh].toggle(size<barS);
			html['grey'+cvh].toggle(size>=barS);				
			
			// store values
			self.percent[0+(x?3:0)] = (content['scroll'+chw] - content['client'+chw]) / (barS - size)
			self.percent[1+(x?3:0)] = (barS - size) / (content['scroll'+chw] - content['client'+chw])
			self.percent[2+(x?3:0)] = Math.round(content['scroll'+chw] * size / barS / self.increment)
			
		},

	        
	        build : function(x){
	        	var self = this, html = self.html,
	        	tl  = ['top','left'][x],
	        	ctl = ['Top','Left'][x],
	        	dr  = ['down','right'][x],
	        	cdr = ['Down','Right'][x],
	        	hw  = ['height','width'][x],
	        	chw = ['Height','Width'][x],
	        	cvh = ['Vertical','Horizontal'][x];
	        	
			html['scroll'+cvh] = $('<div/>')
				.addClass('scroll'+cvh)
				.appendTo(html.conteiner)
				.mouseup(function(e){
					clearInterval(self[tl+'Interval']);
				});
		
			html[tl+'Btn'] = $('<div/>')
				.addClass(tl+'Btn')
				.appendTo(html['scroll'+cvh])
				.mousedown(function(e){
					e.preventDefault(); // dragging
					self['doScroll'+ctl](1, 1);
					html[tl+'Btn'].addClass(tl+"Btn-Active");
				}).mouseup(function(e){
					html[tl+'Btn'].removeClass(tl+"Btn-Active");
				}).mouseenter(function(e){
					html[tl+'Btn'].addClass(tl+"Btn-Highlighted");
				}).mouseleave(function(e){
					html[tl+'Btn'].removeClass(tl+"Btn-Highlighted "+tl+"Btn-Active");
					clearInterval(self[tl+'Interval']);
				});
		
			html[dr+'Btn'] = $('<div/>')
				.addClass(dr+'Btn')
				.appendTo(html['scroll'+cvh])
				.mousedown(function(e){
					e.preventDefault(); // dragging
					self['doScroll'+ctl](-1, 1);
					html[dr+'Btn'].addClass(dr+"Btn-Active");
				}).mouseup(function(e){
					html[dr+'Btn'].removeClass(dr+"Btn-Active");
				}).mouseenter(function(e){
					html[dr+'Btn'].addClass(dr+"Btn-Highlighted");
				}).mouseleave(function(e){
					html[dr+'Btn'].removeClass(dr+"Btn-Highlighted "+dr+"Btn-Active");
					clearInterval(self[tl+'Interval']);
				}).css(self.axis.x&&self.axis.y?x?{right:html.tambour[hw]()}:{bottom:html.tambour[hw]()}:{});
			
			
			html['scrollBar'+cvh] = $('<div/>')
				.addClass('scrollBar'+cvh)
				.appendTo(html['scroll'+cvh])
				.mousedown(function(e){
					if (self.scrolltype == 'incremental'){
						var sign = (x?e.pageX:e.pageY) - html['scrollHandle'+cvh].offset()[tl] < 0 ? 1 : -1;
						self['doScroll'+ctl](sign, self.percent[x?2:5]);
					}else{ // position
						var point = (x?e.pageX:e.pageY) - html['scrollHandle'+cvh].offset()[tl];
						self['setContentTo'+ctl](point);
						self['doJump'+ctl](point);
					}
				})
			
			html['grey'+cvh] = $("<div/>")
				.addClass("greyEl")
				.appendTo(html['scroll'+cvh]);
			
			html['scrollHandle'+cvh] = $('<div/>')
				.addClass('scrollHandle'+cvh)
				.appendTo(html['scrollBar'+cvh])
				.mousedown(function(e){
					e.stopPropagation();
					html['scrollBar'+cvh].addClass("scrollBar"+cvh+"-Active");
				}).mouseup(function(e){
					html['scrollBar'+cvh].removeClass("scrollBar"+cvh+"-Active");
				}).mouseover(function(e){
					clearInterval(self[tl+'Interval']);
				}).bind("mouseleave mouseenter",function(e){
					html['scrollBar'+cvh].toggleClass("scrollBar"+cvh+"-Highlighted");
				}).draggable({
					axis: x?'x':'y', 
					containment: 'parent',
					drag: function(e, ui) { 
						self['setContentTo'+ctl](ui.position[tl]);
					},
					stop : function(){
						html['scrollBar'+cvh].removeClass("scrollBar"+cvh+"-Active");
					}
				});
		
			html['scrollHandle'+ctl] = $('<div/>')
				.addClass('scrollHandle'+ctl)
				.appendTo(html['scrollHandle'+cvh]);
			html['scrollHandleBG'+cvh] = $('<div/>')
				.addClass('scrollHandleBG'+cvh)
				.appendTo(html['scrollHandle'+cvh]);
			html['scrollHandleMiddle'+cvh] = $('<div/>')
				.addClass('scrollHandleMiddle'+cvh)
				.appendTo(html['scrollHandle'+cvh]);
			html['scrollHandle'+cdr] = $('<div/>')
				.addClass('scrollHandle'+cdr)
				.appendTo(html['scrollHandle'+cvh]);
	
	        },
	        
		setContentToTop : function(point){
			this.html.content.get(0).scrollTop = Math.round(point * this.percent[0]);
		},
		
		setScrollerToTop : function(point){
			this.html.scrollHandleVertical.css({top:Math.round(point * this.percent[1])});
		},
		
		doJumpTop : function(point){
			var html = this.html,
			c = html.scrollHandleVertical.height() / 2,
			top = Math.min(Math.max(point - c, 0), html.scrollBarVertical.height() - 2 * c);
			html.scrollHandleVertical.css({top:top});
		},
		
	        doScrollTop : function(sign, multiplier){
	        	
			var self = this;
			clearInterval(self.topInterval); 
			self.topInterval = setInterval(function(){
				var elt = self.html.content.get(0);
				elt.scrollTop -= self.increment * sign * multiplier;
				self.setScrollerToTop(elt.scrollTop);
			},50);
			
	        },
	        
		setContentToLeft : function(point){
			this.html.content.get(0).scrollLeft = Math.round(point * this.percent[3]);
		},
		
		setScrollerToLeft : function(point){
			this.html.scrollHandleHorizontal.css({left:Math.round(point * this.percent[4])});
		},
		
		doJumpLeft : function(point){
			var html = this.html,
			c = html.scrollHandleHorizontal.width() / 2,
			left = Math.min(Math.max(point - c, 0), html.scrollBarHorizontal.width() - 2 * c);
			html.scrollHandleHorizontal.css({left:left});
		},
		
	        doScrollLeft : function(sign, multiplier){
			var self = this;
			clearInterval(self.leftInterval); 
			self.leftInterval = setInterval(function(){
				var elt = self.html.content.get(0);
				elt.scrollLeft -= self.increment * sign * multiplier;
				self.setScrollerToLeft(elt.scrollLeft);
			},50);
	        }
	}

	$.fn.jscroll = function(options) {
		this.each(function() {
			new Scroll(this, options);
		});
		return this;
	};

})(jQuery);


