// Create scrolling variable if it doesn't exist
if (!Scrolling) var Scrolling = {};

//Scroller constructor
Scrolling.Scroller = function (o, w, h, t, d, sw, sh) {
	//get the container
	var list = o.getElementsByTagName("div");
//	alert(list.length);
	for (var i = 0; i < list.length; i++) {
		if (list[i].className.indexOf("Scroller" + d + "-Container") > -1) {
			o = list[i];
		}
	}
	
	//private variables
	var self  = this;
	var _vwidth   = w;
	var _vheight  = h;
	var _stwidth = sw; // Scroll Track width
	var _stheight = sh; // Scroll Track width
	var _twidth   = o.offsetWidth
	var _theight  = o.offsetHeight;
	
	var _hasTween = t ? true : false;
	var _timer, _x, _y;
	var direction = d;
	
	//public variables
	this.onScrollStart = function (){};
	this.onScrollStop  = function (){};
	this.onScroll      = function (){};
	this.scrollSpeed   = 30;
	
	
	this.update = function()
	{
		_twidth   = o.offsetWidth
		_theight  = o.offsetHeight;
	}
	
	//private functions
	function setPosition (x, y) {
		if (x < _vwidth - _twidth) 
			x = _vwidth - _twidth;
		if (x > 0) x = 0;
		if (y < _vheight - _theight) 
			y = _vheight - _theight;
		if (y > 0) y = 0;
		
		
		_x = isNaN(x) ? 0 : x;
		_y = y;
		
		o.style.left = _x +"px";
		o.style.top  = _y +"px";
	};
	
	//public functions
	this.scrollBy = function (x, y) { 
		setPosition(_x - x, _y - y);
		this.onScroll();
	};
	
	this.scrollTo = function (x, y) { 
		setPosition(-x, -y);
		this.onScroll();
	};
	
	this.startScroll = function (x, y) {
		this.stopScroll();
		this.onScrollStart();
		_timer = window.setInterval(
			function () { self.scrollBy(x, y); }, this.scrollSpeed
		);
	};
		
	this.stopScroll  = function () { 
		if (_timer) window.clearInterval(_timer);
		
		this.onScrollStop();
	};
	
	this.reset = function () {
		_twidth  = o.offsetWidth
		_theight = o.offsetHeight;
		_x = 0;
		_y = 0;
		
		o.style.left = "0px";
		o.style.top  = "0px";
		
		if (_hasTween) t.apply(this);
	};
	
	this.swapContent = function (c, w, h) {
		o = c;
		var list = o.getElementsByTagName("div");
		for (var i = 0; i < list.length; i++) {
			if (list[i].className.indexOf("Scroller-Container") > -1) {
				o = list[i];
			}
		}
		
		if (w) _vwidth  = w;
		if (h) _vheight = h;
		reset();
	};
	
	this.getDimensions = function () {
		return {
			vwidth  : _vwidth,
			vheight : _vheight,
			twidth  : _twidth,
			theight : _theight,
			stwidth  : _stwidth,
			stheight : _stheight,
			x : -_x, y : -_y
		};
	};
	
	this.getContent = function () {
		return o;
	};
	
	this.reset();
};

// Create scrolling variable if it doesn't exist
if (!Scrolling) var Scrolling = {};

//Scrollbar constructor
Scrolling.Scrollbar = function (o, s, t, d) {
	//private variables
	var self = this;
	var _components = {};
	var _dimensions = {};
	var _temporary  = {};
	var _hasTween   = t ? true : false;
	var _timer, _ratio_y, _ratio_x;
	var direction = d;
	var scroller = s;
	
	//public variables
	this.onMouseDown   = function (){};
	this.onMouseUp     = function (){};
	this.onScroll      = function (){};
	this.scrollAmount  = 5;
	this.scrollSpeed   = 30;
	this.disabled      = false;
	
	//private functions
	function initialize () {
		var c = _components;
		var d = _dimensions;
		var g = s.getDimensions();
		
		c.up     = findComponent("Scrollbar" + direction + "-Up", o);
		c.down   = findComponent("Scrollbar" + direction + "-Down", o);
		c.track  = findComponent("Scrollbar" + direction + "-Track", o);
		c.handle = findComponent("Scrollbar" + direction + "-Handle", c.track);
		
		
		if (direction == "Vertical" || direction == "VerticalSlide")
		{
			var scrollbar_height = Math.min(g.stheight, g.stheight * Math.exp( (- g.theight + g.vheight)/100));
			c.handle.style.height = scrollbar_height + "px";
			if (parseInt(c.handle.style.top) + scrollbar_height > g.stheight)
			{
				c.handle.style.left = (g.stheight - scrollbar_height) + px;
				this.scrollTo(g.stheight - scrollbar_height);
			}	
		}
		else
		{
			var scrollbar_width = Math.min(g.stwidth, g.stwidth * Math.exp( (- g.twidth + g.vwidth)/1000));
			c.handle.style.width = scrollbar_width + "px";
			if (parseInt(c.handle.style.left) + scrollbar_width > g.stwidth)
			{
				c.handle.style.left = (g.stwidth - scrollbar_width) + px;
				this.scrollTo(g.stwidth - scrollbar_width);
			}
		}
		
				
		d.trackTop     = findOffsetTop(c.track);
		d.trackLeft    = findOffsetLeft(c.track);
		d.trackHeight  = c.track.offsetHeight;
		d.handleHeight = c.handle.offsetHeight;
		d.trackWidth  = c.track.offsetWidth;
		d.handleWidth = c.handle.offsetWidth;
		d.x = 0;
		d.y = 0
		
		
		if (_hasTween) t.apply(self);
		
		addEvent(s.getContent(), "mousewheel", scrollbarWheel);
		addEvent(o, "mousedown", scrollbarClickPrimer);

		
		self.reset();
		
		
	};
	
	//
	// Updates the scrollbar dimension according to the dimension of underlying
	this.update = function()
	{
		s.update();
		var g = s.getDimensions();
		var c = _components;
		
		if (direction == "Vertical" || direction == "VerticalSlide")
		{
			var scrollbar_height = Math.min(g.stheight, g.stheight * Math.exp( (- g.theight + g.vheight)/100));
			c.handle.style.height = scrollbar_height + "px";
			if (parseInt(c.handle.style.top) + scrollbar_height > g.stheight)
			{
				c.handle.style.top = (g.stheight - scrollbar_height) + "px";
				this.scrollTo(g.stheight - scrollbar_height);
			}
		}
		else
		{
			var scrollbar_width = Math.min(g.stwidth, g.stwidth * Math.exp( (- g.twidth + g.vwidth)/1000));
			c.handle.style.width = scrollbar_width + "px";
			if (parseInt(c.handle.style.left) + scrollbar_width > g.stwidth)
			{
				c.handle.style.left = (g.stwidth - scrollbar_width) + "px";
				this.scrollTo(g.stwidth - scrollbar_width);
			}
		}
		
		var d = _dimensions;
		d.trackHeight  = c.track.offsetHeight;
		d.handleHeight = c.handle.offsetHeight;
		d.trackWidth  = c.track.offsetWidth;
		d.handleWidth = c.handle.offsetWidth;
		
		_ratio_y = (g.theight - g.vheight) / (d.trackHeight - d.handleHeight);
		_ratio_x = (g.twidth - g.vwidth) / (d.trackWidth - d.handleWidth);

	}
	
	function findOffsetTop (o) {
		var t = 0;
		if (o.offsetParent) {
			while (o.offsetParent) {
				t += o.offsetTop;
				o  = o.offsetParent;
			}
		}
		return t;
	};

	function findOffsetLeft (o) {
		var t = 0;
		if (o.offsetParent) {
			while (o.offsetParent) {
				t += o.offsetLeft;
				o  = o.offsetParent;
			}
		}
		return t;
	};
	
	function addEvent (o, t, f) {
		if (o.attachEvent) o.attachEvent('on'+ t, f);
		else o.addEventListener(t, f, false);
	};
	
	function removeEvent (o, t, f) {
		if (o.detachEvent) o.detachEvent('on'+ t, f);
		else o.removeEventListener(t, f, false);
	};
	
	function findComponent (c, o) {
		var kids = o.childNodes;
//		alert(kids + " " + o.childNodes + " " + o + " " + c);
		for (var i = 0; i < kids.length; i++) {
			if (kids[i].className && kids[i].className.indexOf(c) >= 0) {
				return kids[i];
			}
		}
		return document.getElementById(c);
	};
	
	function scroll (y) {
		if (direction == "Vertical" || direction == "VerticalSlide")
		{
			if (y < 0) y = 0;
			if (y > _dimensions.trackHeight - _dimensions.handleHeight)
				y = _dimensions.trackHeight - _dimensions.handleHeight;
			
//			alert("y: " + y);
			
			_components.handle.style.top = y +"px";
			_dimensions.y = y;
//			alert(Math.round( _ratio_y));
			s.scrollTo(0, Math.round(_dimensions.y * _ratio_y));
		}
		else
		{
			x = y;
			if (x < 0 || isNaN(x)) x = 0;
			if (x > _dimensions.trackWidth - _dimensions.handleWidth)
				y = _dimensions.trackWidth - _dimensions.handleWidth;

			_components.handle.style.left = x +"px";
			_dimensions.x = x;
		
			s.scrollTo(Math.round(_dimensions.x * _ratio_x), 0);
		}
		self.onScroll();
	};
	
	function scrollbarClickPrimer (e) {
		if (self.disabled) return false;
		
		e = e?e:event;
		if (!e.target) e.target = e.srcElement;

		scrollbarClick(e.target.className, e);
	};
	
	function scrollbarClick (c, e) {
		var d  = _dimensions;
		var t  = _temporary;
		var cy = e.clientY + document.body.scrollTop;
		var cx = e.clientX + document.body.scrollLeft;
		
		
		if (c.indexOf("Scrollbar" + direction + "-Up") >= 0)
			startScroll(-self.scrollAmount);
		
		if (c.indexOf("Scrollbar" + direction + "-Down") >= 0) 
		{
			startScroll(self.scrollAmount);
		}
			
		if (c.indexOf("Scrollbar" + direction + "-Track") >= 0)
		{
			if (direction == "Vertical" || direction == "VerticalSlide")
			{
				//alert((cy - d.trackTop - d.handleHeight / 2) * _ratio_y);
				if (_hasTween) self.tweenTo((cy - d.trackTop - d.handleHeight / 2) * _ratio_y);
				else scroll(cy - d.trackTop - d.handleHeight / 2);	
			}
			else
			{
				if (_hasTween) self.tweenTo((cx - d.trackLeft - d.handleWidth / 2) * _ratio_x);
				else scroll(cx - d.trackLeft - d.handleWidth / 2);	
			}
		}
		
		if (c.indexOf("Scrollbar" + direction + "-Handle") >= 0) 
		{
			if (direction == "Vertical" || direction == "VerticalSlide")
			{
				t.grabPoint = cy - findOffsetTop(_components.handle);
			}
			else
			{
				t.grabPoint = cx - findOffsetLeft(_components.handle);
			}
			addEvent(document, "mousemove", scrollbarDrag, false);	

		}
		
		t.target = e.target;
		t.select = document.onselectstart;
		
		document.onselectstart = function (){ return false; };
		self.onMouseDown(e.target, c, e);
		
		addEvent(document, "mouseup", stopScroll);
	};
	
	function scrollbarDrag (e) {
		e = e?e:event;
		var d = _dimensions;
		
		if (direction == "Vertical" || direction == "VerticalSlide")
		{
			var t = parseInt(_components.handle.style.top);
			var v = e.clientY + document.body.scrollTop - d.trackTop;
		
			if (v >= d.trackHeight - d.handleHeight + _temporary.grabPoint)
				v = d.trackHeight - d.handleHeight;
			
			else if (v <= _temporary.grabPoint)
				v = 0;
			
			else v = v - _temporary.grabPoint;
			
			scroll(v);
		}
		else
		{
			var t = parseInt(_components.handle.style.left);
			var v = e.clientX + document.body.scrollLeft - d.trackLeft;
		
			if (v >= d.trackWidth - d.handleWidth + _temporary.grabPoint)
				v = d.trackWidth - d.handleWidth;
			
			else if (v <= _temporary.grabPoint)
				v = 0;
			
			else v = v - _temporary.grabPoint;
			
			scroll(v);
		}
	};
	
	function scrollbarWheel (e) {
		if (self.disabled) return false;
		
		e = e ? e : event;
		var dir = 0;
		if (e.wheelDelta >= 120) dir = -1;
		if (e.wheelDelta <= -120) dir = 1;

		self.scrollBy(dir * 20);
		e.returnValue = false;
	};
	
	function startScroll (y) {
		if (direction == "Vertical" || direction == "VerticalSlide")
		{
			_temporary.disty = y;
			_timer = window.setInterval(function () {
				self.scrollBy(_temporary.disty);
			}, self.scrollSpeed);
		}
		else
		{
			x = y;
			_temporary.distx = x;
			_timer = window.setInterval(function () {
				self.scrollBy(_temporary.distx);
			}, self.scrollSpeed);
		}
	};
	
	function stopScroll (e) {
		e = e?e:event;
		
		removeEvent(document, "mousemove", scrollbarDrag);
		removeEvent(document, "mouseup", stopScroll);
		
		document.onselectstart = _temporary.select;
		if (_timer) window.clearInterval(_timer);
		
		self.onMouseUp(_temporary.target, _temporary.target.className, e);
	};
	
	//public functions
	this.reset = function () {
		var d = _dimensions;
		var c = _components;
		var g = s.getDimensions();
		
		
		if (d.trackHeight - d.handleHeight == 0)
			_ratio_y = 0;
		else
			_ratio_y = (g.theight - g.vheight) / (d.trackHeight - d.handleHeight);
		
		if (d.trackWidth - d.handleWidth == 0)
			_ratio_x = 0;
		else
			_ratio_x = (g.twidth - g.vwidth) / (d.trackWidth - d.handleWidth);
		
		c.handle.ondragstart = function (){ return false; };
		c.handle.onmousedown = function (){ return false; };
		c.handle.style.top   = "0px";
		c.handle.style.left   = "0px";
		d.y = 0;
		d.x = 0;
		

		s.reset();

		scroll(0);

		var z = s.getDimensions();
//		alert("Z: " + z.y);
		
		if (direction == "Vertical" || direction == "VerticalSlide")
		{
			if (g.theight < g.vheight) {
				//this.disabled = true;
				o.className  += " Scrollbar-Disabled";
			}
		}
		else
		{
			if (g.twidth < g.vwidth) {
				//this.disabled = true;
				o.className  += " Scrollbar-Disabled";
			}
		}
	};
	
	this.scrollTo = function (y) {
		if (direction == "Vertical" || direction == "VerticalSlide")
		{	
			if (_ratio_y == 0)
				scroll(0);
			else
				scroll(y / _ratio_y);
		}
		else
		{
			if (_ratio_x == 0)
				scroll(0);
			else
				scroll(y / _ratio_x);
		}
	};
	
	this.scrollBy = function (y) {
		if (direction == "Vertical" || direction == "VerticalSlide")
		{
			if (_ratio_y == 0)
				scroll(0);
			else
				scroll((s.getDimensions().y + y) / _ratio_y);
		}
		else
		{
			x = y;
			if (_ratio_x == 0)
				scroll(0);
			else
				scroll((s.getDimensions().x + x) / _ratio_x);
		}
	};
	
	this.swapContent = function (n, w, h) {
		o = n;
		s.swapContent(o, w, h);
		initialize();
	};
	
	this.disable = function () {
		this.disabled = true;
		o.className  += "Scrollbar-Disabled";
	};
	
	this.enable = function () {
		this.disabled = false;
		o.className = o.className.replace(/Scrollbar\-Disabled/, "");
	};
	
	this.getContent = function () {
		return s.getContent();
	};
	
	this.getComponents = function () {
		return _components;
	};
	
	this.getDimensions = function () {
		var d = s.getDimensions();
		d.trackHeight  = _dimensions.trackHeight;
		d.handleHeight = _dimensions.handleHeight;
		d.trackWidth  = _dimensions.trackWidth;
		d.handleWidth = _dimensions.handleWidth;
		
		return d;
	};
	
	initialize();
};

// Create scrolling variable if it doesn't exist
if (!Scrolling) var Scrolling = {};

//ScrollTween constructor
Scrolling.ScrollTween = function (d) {
	//private variables
	var self    = this;
	var _steps  = [0,25,50,70,85,95,97,99,100];
	var _values = [];
	var _idle   = true;
	var o, _inc, _timer;
	var direction = d;
	
	//private functions
	function tweenTo (y) {
		if (!_idle) return false;
		
		var d = o.getDimensions();
		
		if (direction == "Vertical" || direction == "VerticalSlide")
		{
			if (y < 0) y = 0;
			if (y > d.theight - d.vheight)
				y = d.theight - d.vheight;
				
			var dist = y - d.y;
			_inc     = 0;
			_timer   = null;
			_values  = [];
			_idle    = false;
			
			for (var i = 0; i < _steps.length; i++) {
				_values[i] = Math.round(d.y + dist * (_steps[i] / 100));
			}

			_timer = window.setInterval(function () {
				o.scrollTo(_values[_inc]); 
				if (_inc == _steps.length - 1) {
					window.clearInterval(_timer);
					_idle = true;
				} else _inc++;
			}, o.stepSpeed);
		}
		else
		{
			x = y;
			if (x < 0) x = 0;
			if (x > d.twidth - d.vwidth)
				x = d.twidth - d.vwidth;
				
			var dist = x - d.x;
			_inc     = 0;
			_timer   = null;
			_values  = [];
			_idle    = false;
			
			for (var i = 0; i < _steps.length; i++) {
				_values[i] = Math.round(d.x + dist * (_steps[i] / 100));
			}

			_timer = window.setInterval(function () {
				o.scrollTo(_values[_inc]); 
				if (_inc == _steps.length - 1) {
					window.clearInterval(_timer);
					_idle = true;
				} else _inc++;
			}, o.stepSpeed);
		}
	};
	
	function tweenBy (y) {
		if (direction == "Vertical" || direction == "VerticalSlide")
			o.tweenTo(o.getDimensions().y + y);
		else
			o.tweenTo(o.getDimensions().x + y);
	};
	
	function setSteps (s) {
		_steps = s;
	};
	
	//public functions
	this.apply = function (p) {
		o = p;
		o.tweenTo   = tweenTo;
		o.tweenBy   = tweenBy;
		o.setSteps  = setSteps;
		o.stepSpeed = 30;
	};
};


