//+ Carlos R. L. Rodrigues
//@ http://jsfromhell.com/
ScrollBar = function(o, cn, sb, pT, pS){
	var pT = pT || "bottom", pS = pS || "right";
	var getStyle = function(o, p, n){
		var v = o.currentStyle ? o.currentStyle[p] : window.getComputedStyle ?
			document.defaultView.getComputedStyle(o, null).getPropertyValue(p) : null;
		return n ? parseInt(v, 10) : v;
	},
	cr = function(s, p){
		var o = document.createElement("div");
		return !p && (o.style.position = "absolute"), o.className = s, o;
	},
	pos = function(o){
		for(var p = {l: o.offsetLeft, t: o.offsetTop, w: o.offsetWidth, h: o.offsetHeight};
			o = o.offsetParent; p.l += o.offsetLeft, p.t += o.offsetTop);
		return p;
	},
	gW = function(o){return getStyle(o, "width", 1) || o.offsetWidth;},
	gH = function(o){return getStyle(o, "height", 1) || o.offsetHeight;}
	var s_, s, _ = (s = cr(cn.trackV)).style, $ = {sa:1, sl:1}, bar, bs = (bar = cr(cn.barV)).style, up = cr(cn.up), dw = cr(cn.down);
	var __ = (s_ = cr(cn.trackH)).style, bar_, bs_ = (bar_ = cr(cn.barH)).style, lf = cr(cn.left), rt = cr(cn.right);
	var a, as = (a = cr("scrollArea", true)).style;
	var ow = gW(o), oh = gH(o), sbox = o.style, ie = getStyle(o, "styleFloat") ? true : false, prop, f;
	for(var p in f = {"styleFloat" : "none", "float" : "none", "margin-top" : 0, "margin-bottom" : 0, "margin-left" : 0, "margin-right" : 0}){
		var propName = p.replace(/\-(\w)/g, function(a, l){return l.toUpperCase()});
		if((prop = getStyle(o, ie ? propName : p))){
			if(!ie && p == "float")
				sbox.cssFloat = f[p], a.style.cssFloat = prop;
			else
				sbox[propName] = f[p], a.style[propName] = prop;
		}
	}
	o.parentNode.replaceChild(a, o), a.appendChild(o);
	a.appendChild(s).appendChild(bar), s.appendChild(up), s.appendChild(dw);
	a.appendChild(s_).appendChild(bar_), s_.appendChild(lf), s_.appendChild(rt);
	sbox.width = ow - (sb == ScrollBar.HORIZONTAL ? 0 : s.offsetWidth) + "px",
	sbox.height = oh - (sb == ScrollBar.VERTICAL ? 0 : s_.offsetHeight) + "px";
	sbox.overflow = "hidden", sbox.position = as.position = "relative";
	var kW = getStyle(bar_, "width", 1), kH = getStyle(bar, "height", 1), tH = getStyle(s, "height", 1), tW = getStyle(s_, "width", 1);
	this.refresh = function(){
		o.scrollHeight > o.offsetHeight && (_.display = "");
		o.scrollWidth > o.offsetWidth && (__.display = "");
		$.w = tW || o.offsetWidth, $.ow = o.scrollWidth, $.lW = lf.offsetWidth, $.rW = rt.offsetHeight, $.owu = $.ow - o.offsetWidth;
		$.ow > $.w && sb != ScrollBar.VERTICAL && (sbox.height = gH(o) - (oh == gH(o) ? bar_.offsetHeight : 0) + "px");
		$.h = tH || o.offsetHeight, $.oh = o.scrollHeight, $.uH = up.offsetHeight, $.dH = dw.offsetHeight, $.ohu = $.oh - o.offsetHeight;
		if($.oh > o.offsetHeight && sb != ScrollBar.HORIZONTAL){
			_.display = "";
			bs.height = (kH || Math.max(($.h = tH || o.offsetHeight) / Math.max($.h, $.oh) * ($.h - $.uH - $.dH), 15)) + "px";
			as.width = o.offsetWidth + bar.offsetWidth + "px";
			_.height = $.h + "px",
			dw.style.top = $.h - dw.offsetHeight + "px",
			$.sa = $.h - $.uH - $.dH - bar.offsetHeight,
			$.mx = $.h - bar.offsetHeight - $.dH;
			_.left = (pS == "left" ? (sbox.left = bar.offsetWidth + "px", 0) : o.offsetWidth) + "px",
			_.top = (pT == "top" ? bar_.offsetHeight : 0) + "px",
			bs.top = o.scrollTop / $.oh * $.h + $.uH + "px", bs.left = 0;
		}
		else sbox.width = ow + "px", _.display = "none", as.width = o.offsetWidth + "px";
		if($.ow > o.offsetWidth && sb != ScrollBar.VERTICAL){
			__.display = "";
			bs_.width = (kW || Math.max(($.w = tW || o.offsetWidth) / Math.max($.w, $.ow) * ($.w - $.lW - $.rW), 15)) + "px";
			as.height = o.offsetHeight + bar_.offsetHeight + "px";
			__.width = $.w + "px",
			rt.style.left = $.w - rt.offsetWidth + "px",
			$.sl = $.w - $.rW - $.lW - bar_.offsetWidth,
			$.mx_ = $.w - bar_.offsetWidth - $.rW;
			__.left = (pS == "left" ? bar.offsetWidth : 0) + "px";
			__.top = (pT == "top" ? (sbox.top = bar_.offsetHeight + "px", 0) : o.offsetHeight) + "px",
			bs_.left = o.scrollLeft / $.ow * $.w + $.lW + "px", bs_.top = 0;
		}
		else !($.oh > $.h) && (sbox.height = oh + "px"), __.display = "none", as.height = o.offsetHeight + "px";
	};
	this.refresh();
	new function(){
		var d = false, q = 20, x, y, it, _it, im, h, _tk, p = pos(o),
		move = function(p, trk){
			(trk && (h ? (im >= bar_.offsetLeft && im <= bar_.offsetLeft + bar_.offsetWidth) :
				(im >= bar.offsetTop && im <= bar.offsetTop + bar.offsetHeight)) && !cl()) ||
			(h ? (o.scrollLeft += p, bs_.left = Math.ceil(o.scrollLeft / ($.owu / $.sl) + $.lW) + "px") :
				(o.scrollTop += p, $.ohu && (bs.top = Math.ceil(o.scrollTop / ($.ohu / $.sa) + $.uH) + "px")));
		},
		__ = function(q, trk){
			_it = setTimeout(function(){
				it = setInterval(function(){move(q, trk);}, 50);
			}, (move(q, trk), 300));
		},
		_tk = function(e){
			var q = h ? bar_.offsetWidth * ($.owu / $.sl) : bar.offsetHeight * ($.ohu / $.sa), b = document.body,
			a = h ? (im = (e.clientX - p.l + (b.scrollLeft || b.parentNode.scrollLeft || 0))) < bar_.offsetLeft :
				(im = (e.clientY - p.t + (b.scrollTop || b.parentNode.scrollTop || 0))) < bar.offsetTop;
			__(a ? -q : q, 1);
		},
		cl = function(){clearInterval(it), clearTimeout(_it), ip = null}
		addEvent(bar, "mousedown", function(e){
			return e.stopPropagation((y = e.clientY - bar.offsetTop, h = !(d = true))), false;
		});
		addEvent(bar_, "mousedown", function(e){
			return e.stopPropagation((x = e.clientX - bar_.offsetLeft, h = d = true)), false;
		});
		addEvent(o, "mousewheel", function(e){
			return __(q * (e.wheelDelta < (d = h = 0) ? 1 : -1)), cl(), e.preventDefault(), false;
		});
		o.addEventListener && o.addEventListener("DOMMouseScroll", function(e){
			return __(q * (e.detail > (d = h = 0) ? 1 : -1)), cl(), e.preventDefault(), false;
		}, false);
		addEvent(up, "mousedown", function(e){return __((h = 0, -q)), e.stopPropagation(), false});
		addEvent(dw, "mousedown", function(e){return __((h = 0, q)), e.stopPropagation(), false});
		addEvent(lf, "mousedown", function(e){return __(h = -q), e.stopPropagation(), false});
		addEvent(rt, "mousedown", function(e){return __(h = q), e.stopPropagation(), false});
		addEvent(s, "mousedown", function(e){return h = 0, _tk(e), false});
		addEvent(s_, "mousedown", function(e){return h = 1, _tk(e), false});
		addEvent(document, "mouseup", function(){d = cl()});
		addEvent(document, "mousemove", function(p){
			if(!d) return;
			h ? (bs_.left = ((p = p.clientX - x) < $.lW || p > $.mx_ ? (p < $.lW ? $.lW : $.mx_) : p) + "px") :
				(bs.top = ((p = p.clientY - y) < $.uH || p > $.mx ? (p < $.uH ? $.uH : $.mx) : p) + "px");
			return h ? o.scrollLeft = ((bar_.offsetLeft - $.lW) * ($.owu / $.sl)) >> 0:
				o.scrollTop = ((bar.offsetTop - $.uH) * ($.ohu / $.sa)) >> 0, false;
		});
	};
}
ScrollBar.BOTH = 0;
ScrollBar.VERTICAL = 1;
ScrollBar.HORIZONTAL = 2;