/*
---
description: Unobtrusive modern scrollbar for elements with fixed heights
license: MIT
copyright: Copyright (c) 2011 by Julian Lam (julianlam).
authors:
- Julian Lam (julianlam)
requires:
- core/1.4.1: '*'
- more/1.4.0.1: [Slider, Element.measure]
provides: [Scrollable]
...
*/

var Scrollable = new Class(
	{
		initialize:function(element, options)
		{
			if (typeOf(element) == "elements") {
				var collection = [];
				element.each(function(element)
					{
						collection.push(new Scrollable(element, options));
					});
				return collection;
			} else {
				var scrollable = this;
				this.element = element;
				this.active = false;
		
				// Some default options
				options = options || {};
				options.autoHide = (typeOf(options.autoHide) != "null" ? options.autoHide : .3);
				options.fade = (typeOf(options.fade) != "null" ? options.fade : .7);
				options.className = (typeOf(options.className) != "null" ? options.className : "scrollbar");
				this.options = options;

				// Renders a scrollbar over the given element
				this.container = new Element("div", 
					{
						"class":options.className,
						html:"<div class=\"knob\"></div>"
					}).inject(document.body, "bottom");
				this.slider = new Slider(this.container, this.container.getElement("div"),
					{
						mode:"vertical",
						onChange:function(step)
						{
							element.scrollTop = ((element.scrollHeight - element.clientHeight) * (step / 100));
						}
					});
				this.reposition();
				this.checkexistence();
				if (!options.autoHide) 
					this.container.fade("show");
				else
					this.container.fade(options.autoHide);
				this.knob = this.container.getElement("div");

				// Making the element scrollable via mousewheel
				element.addEvents(
					{
						"mouseover":function()
						{
							if (this.scrollHeight > this.clientHeight) {
								scrollable.showContainer();
							}
						},
						"mouseleave":function(e)
						{
							if (!scrollable.isInside(e) && !scrollable.active) {
								scrollable.hideContainer();
							}
						},
						"mousewheel": function(event)
						{
							if ((event.wheel < 0 && this.scrollTop < (this.scrollHeight - this.offsetHeight)) || (event.wheel > 0 && this.scrollTop > 0)) {
								event.preventDefault();    // Stops the entire page from scrolling
								this.scrollTop = this.scrollTop - (event.wheel * 30);
								scrollable.slider.set(Math.round((this.scrollTop / (this.scrollHeight - element.clientHeight)) * 100));
							}
						}
					});
				this.container.addEvent("mouseleave", function()
					{
						if (!scrollable.active) {
							scrollable.hideContainer();
						}
					});
				this.knob.addEvent("mousedown", function(e)
					{
						scrollable.active = true;
						window.addEvent("mouseup", function(e)
							{
								scrollable.active = false;
								if (!scrollable.isInside(e)) {
									// If mouse is outside the boundaries of the target element
									scrollable.hideContainer();
								}
								this.removeEvents("mouseup");
							});
					});
				window.addEvents(
					{
						"resize":function()
						{
							scrollable.reposition.delay(50, scrollable);
						},
						"mousewheel":function()
						{
							if (scrollable.element.isVisible())
								scrollable.reposition();
						}
					});

				// Initial hiding of the scrollbar
				if (options.autoHide)
					scrollable.container.fade("hide");

				return this;
			}
		},
		reposition:function()
		{
			// Repositions the scrollbar by rereading the container element's dimensions/position
			(function()
				{
					this.size = this.element.getComputedSize();
					this.position = this.element.getPosition();
					var containerSize = this.container.getSize();

					this.container.setStyle("height", this.size["height"] - 14).setPosition(
						{
							x:(this.position.x+this.size["totalWidth"] - containerSize.x - 8),
							y:(this.position.y+this.size["computedTop"] + 7)
						});
					this.slider.autosize();
				}).bind(this).delay(50);
		},
		checkexistence:function()
		{
			if (this.options.innercontainer != undefined && this.container.getElement("div") != undefined) {
				if (this.options.innercontainer.getSize().y < this.element.getSize().y) {
					this.container.getElement("div").setStyle("display", "none");
				} else {
					this.container.getElement("div").setStyle("display", "block");
					this.slider.set(0);
				}
			}
		},
		isInside:function(e)
		{
			if (e.client.x > this.position.x && e.client.x < (this.position.x + this.size.totalWidth) && e.client.y > this.position.y && e.client.y < (this.position.y + this.size.totalHeight))
				return true;
			else
				return false;
		},
		showContainer:function()
		{
			if (this.options.autoHide && this.options.fade && !this.active)
				this.container.fade(this.options.fade);
			else if (this.options.autoHide && !this.options.fade && !this.active)
				this.container.fade("show");    
		},
		hideContainer:function()
		{
			if (this.options.autoHide && this.options.fade && !this.active)
				this.container.fade(this.options.autoHide);
			else if (this.options.autoHide && !this.options.fade && !this.active)
				this.container.fade("hide");
		},
		terminate:function()
		{
			this.container.destroy();
		}
	});
