// JavaScript Document

/*
	Scrollbar - a class for creating a customisable Javascript scrollbar
	
	CURRENTLY DOESN'T WORK IN IE6!!
	
	Requires
		mootools 1.2
		mootools Fx.Scroll addon
	
	Usage Example
	
	No HTML or CSS required.  You just need a div with a scrolable content and overflow:auto
	
	JAVASCRIPT
	
	new Scrollbar('news-container-inner', { 
		sliderStyles : {
			'width' : 12,
			'height' : 500,
			'background-color' : '#000000'
		},
		knobStyles : {
			'background-color' : '#666666',
			'width' : 12,
			'height' : 25
		}
	});
*/
	
	
	
	



var Scrollbar = new Class({
						  
	slider : '',  // holds slider element
	knob : '', // holds knob element
	scroller : '', // holds Fx.Scroll instance
	element : '', // holds scrollable element
	conversion : '', // holds figure return by calculateConversion used to determine scroll ratios
	dragger : '', // holds Drag.Move instance
	
	options : {
		sliderStyles  : {}, // styles object to apply to the slider
		knobStyles : {}, // styles object to apply to the knob
		variableHeight : true, // if true, knob height will reflect amount of scroll
		mouseWheel : true, // if true, scrolling is possible using mousewheel
		scrollSpeed : 20, // speed of scrolling when using keys or mousewheel
		sliderContainer : 'body', // container for scrollbar to be positioned relative to
		debug : false
	},
		
/*
	CONSTRUCTOR
	
	new Scrollbar(element:string|Element [, options:object):object
		creates new Srollbar
		Params:
			element - the element you want to scroll
			options - see above
*/
		
		
	initialize: function(element, options){
		if( Browser.Engine.trident && Browser.Engine.version == '4' ) return
		this.setOptions(options);
		this.addConsole();
		this.element = $(element);
		this.scroller = new Fx.Scroll(this.element, {onComplete: this.setKnob.bind(this) } );
		this.scroller.set(0,0);
		
		//create, position and inject html
		var coords = this.element.getCoordinates( $(this.options.sliderContainer) );
		this.slider = new Element('div', {styles : this.options.sliderStyles} );
		this.knob = new Element('div', {styles : this.options.knobStyles} );
		this.knob.inject(this.slider);
		var width = this.options.sliderStyles.width || 10;
		this.element.setStyle('padding-right', this.element.getStyle('padding-right').toInt() + width);
		this.element.setStyle('position', 'relative');
		this.element.setStyle('overflow', 'hidden');
		this.slider.setStyles({
			'position' : 'absolute',
			'left' : coords.left + coords.width - width,
			'top' : coords.top,
			'height' : coords.height
		});
		this.knob.setStyles({
			'cursor' :'n-resize'
		});
		this.slider.inject($(this.options.sliderContainer), 'bottom');
		
		this.calculateKnobHeight();
		this.calculateConversion();
		
		// create Draggable
		this.dragger = new Drag.Move(this.knob, {container:this.slider, 
		  	onDrag: function(el, ev){ this.performScroll(el.getStyle('top') ); }.bind(this)
		});
		
		//add key and smousewheel events
		$(document).addEvent('keydown', function(ev){ this.keyScroll(ev);}.bind(this) );
		if(this.options.mouseWheel) this.element.addEvent('mousewheel', this.mouseWheelScroll.bind(this) );
		
		// scroll to element, if possible
		var id = this.parseUrl();
		if(id){
			try{
				var el = $(id);
				this.scroller.toElement(el);
			}catch(e){
			}
		}
		
	},
	
/*
	addConsole():void
		If debug is set to true, opens debuggin window
*/

	addConsole: function(){
		try{	
			window.console.log();
		}catch(e){
			if( this.options.debug ){
				var console = {};
				console.win = window.open('', 'Debugger', 'width=250,height=500,scrollbars=1,resizable=1');
				console.win.document.write('<h2>Debugging Console</h2>');
				console.log = function(m){
					try{console.win.document.write(m + '<br />');}catch(e){}
				}
			}
		}
	},
		
	
/*
	trace(message:string):void
		outputs debugging info to console, or debugging window
*/
	trace: function(message){
		if(this.debug){
			console.log(message);
		}
	},

/*
	mouseWheelScroll(ev:Event):void
		received mouseWheel event and passes correct value to autoScroll
		Called by: Event(mousewheel)
		Calls: autoScroll
*/
	mouseWheelScroll: function(ev){
		var e = new Event(ev);
		e.stop();
		e.wheel = e.wheel == 1 ? -1 : 1;
		this.autoScroll(e.wheel);
	},
/*
	parseUrl():void
		returns id from url, if present
		Called by: initialize
*/
	parseUrl: function(){
		return window.location.hash ? window.location.hash.replace('#', '') : '';
	},
/*
	keyScroll(ev:Event):void
		receives keyboard event and, if right keys are pressed, starts scrolling
		Called by: Event(keydown)
		Calls: autoscroll
*/
	keyScroll: function(ev){
		var e = new Event(ev);
		e.stop();
		if( e.alt && e.key == 'up' ){
			this.autoScroll(-1);
		}else if( e.alt && e.key == 'down'){
			this.autoScroll(1);
		}
	},
/*
	setKnob():void
		sets knob to correct position when window is scrolled
		Called by: Event(scroller.onComplete)
*/		
	setKnob: function(){
		var scroll = this.element.getScroll().y;
		var s = this.element.getScroll().y / this.conversion;
		this.knob.setStyle('top', s);
	},
/*
	autoScroll(p:Integer):void
		transforms figure from keys/mouse into something that can be passed to performScroll
		Called by: mouseWheelScroll, keyScroll
		Calls: performScroll
*/	
	autoScroll : function(p){
		p = p * this.options.scrollSpeed;
		var s = this.knob.getStyle('top').toInt() + p;
		if( s < 0 ) s = 0; 
		if( s > (this.slider.getSize().y - this.knob.getSize().y ) ) s = (this.slider.getSize().y - this.knob.getSize().y )
		this.knob.setStyle('top', s);
		this.performScroll(s);
	},
/*	
	performScroll(step:Integer):void
		sets scroll amount
		Called by: autoScroll, Event(dragger.onDrag)
*/
	performScroll: function(step){
		step = step.toInt() * this.conversion;
		this.scroller.set(0, step );
	},
/*
	calculateConversion():void
		calculate conversion factor to be used when comparing knob position with scroll position
		Called by: initialize
*/
	calculateConversion: function(){
		var slideSize = this.slider.getSize();
		var knobSize = this.knob.getSize();
		var elementSize = this.element.getSize();
		elementSize.s = this.element.getScrollSize().y;
		this.conversion = (elementSize.s - elementSize.y) / (slideSize.y - knobSize.y);
	},
/*
	calculateKnobHeight():void
		set height of knob relative to amount of scroll, if wanted.  NOT SUPPORTED IN IE6
		Called By: initialize
*/
	calculateKnobHeight: function(){
		if(this.options.variableHeight == false ||( Browser.Engine.trident &&  Browser.Engine.version == 4 ) ) return;
		var obj = this.element.getSize();
		obj.s = this.element.getScrollSize().y;
		var s = obj.y / (obj.s  /100);
		this.knob.setStyle( 'height', s.round() + '%' );
	}
});
		
Scrollbar.implement(new Options);			
			
			