/*
    By James Lin. Me!
*/

if (typeof Control == 'undefined') 
	throw("scrollable.js requires including script.aculo.us' slider.js library!");

var Scrollable = Class.create();
Scrollable.prototype = {
    options : null,
    containerWidth : 0,
    contentWidth : 0,
    containerHeight : 0,
    contentHeight : 0,
    scrollBar : null,
    eventCache : null,
    
    initialize : function(mask, options) {      
        var container = (typeof mask == 'string') ? $(mask) : mask;

        if(!container) {
            throw(mask + " doesn't exist!");
            return false;
        }
        
        var content = container.firstDescendant();
        this.content = content;
        this.container = container;
        
        if(!content) {
            throw(mask + " does not have content!");
            return false;
        }
		
        content.setStyle({position:'static'});
        
		this.options = Object.extend({
            grabber : {
                className: '',
                width: 20,
                height: 20            
            },
            upArrow : {
                className: '',
                width: 20,
                height: 20
            },
            downArrow : {
                className: '',
                width: 20,
                height: 20
            },
            scrubBar : {
                className: '',
                width: 20,
                height: null
            },
            direction : 'vertical',            
            containerHeight: null
		}, options || {});
        

        this.containerWidth = container.getWidth();
        this.containerHeight = this.options.containerHeight || container.getHeight();
        this.contentWidth = this.containerWidth - this.options.scrubBar.width -12;
        this.contentHeight = content.getHeight();
			
		//if(this.containerHeight < this.contentHeight || this.options.containerHeight) {
			container.setStyle({overflow:'hidden', position:'absolute'});
	        content.setStyle({width:this.contentWidth + "px"});
		//}
		         
            var sb = new Element('div');
            sb.setStyle({width:this.options.scrubBar.width+"px",position:'absolute',left:this.contentWidth-20+"px",top:'0'});
            
            var up = new Element('div',{className:this.options.upArrow.className});
            var dn = new Element('div',{className:this.options.downArrow.className});
            var bar = new Element('div',{className:this.options.scrubBar.className});
            var scb = new Element('div',{className:this.options.grabber.className});
            
            var barHeight = this.options.scrubBar.height || (this.containerHeight - this.options.upArrow.height - this.options.downArrow.height);
			
			if(barHeight < 0) return;
			
            bar.setStyle({height:barHeight + "px"});
            scb.setStyle({width:this.options.grabber.width + "px",height:this.options.grabber.height + "px"});
            
            sb.insert(up);
            bar.insert(scb);
            sb.insert(bar);        
            sb.insert(dn);
            
            this.slider = new Control.Slider(scb, bar, {axis: 'vertical',onSlide:this.scrollContent.bind(this),onChange:this.scrollContent.bind(this)});

            this.eventCache = new Object();
            this.eventCache['mousewheel'] = {func:this.wheel.bind(this),obj:container.parentNode};
            this.eventCache['DOMMouseScroll'] = {func:this.wheel.bind(this),obj:container};
            this.eventCache['up_mousedown'] = {func:this.mouseAction.bind(this,1,'down'),obj:up};
            this.eventCache['up_mouseup'] = {func:this.mouseAction.bind(this,1,'up'),obj:up};
            this.eventCache['up_mouseout'] = {func:this.mouseAction.bind(this,1,'up'),obj:up};
            this.eventCache['dn_mousedown'] = {func:this.mouseAction.bind(this,-1,'down'),obj:dn};
            this.eventCache['dn_mouseup'] = {func:this.mouseAction.bind(this,-1,'up'),obj:dn};
            this.eventCache['dn_mouseout'] = {func:this.mouseAction.bind(this,-1,'up'),obj:dn};
            
            this.enableEvents(this.contentHeight > this.containerHeight);
            
            container.insert(sb);
            this.scrollBar = sb;
			
	        if(this.contentHeight <= this.containerHeight) {
	            this.scrollBar.setStyle({display:'none'});
	        } else {
	            this.scrollBar.setStyle({display:'block'});
	        }

    },
    //javascript:_scrollers['comments'].update();
    update : function() {
        var content = this.container.firstDescendant();
        this.contentHeight = content.getHeight();
				
        if(this.contentHeight <= this.containerHeight) {
            this.enableEvents(false);
            this.scrollBar.setStyle({display:'none'});
        } else {
            this.enableEvents(true);
            this.scrollBar.setStyle({display:'block'});
        }
        
        this.slider.setValue(0);
    },
    
    enableEvents : function(enabled) {
        if(enabled) {
            Event.observe(this.eventCache['mousewheel'].obj, 'mousewheel', this.eventCache['mousewheel'].func, false); 
            Event.observe(this.eventCache['DOMMouseScroll'].obj, 'DOMMouseScroll', this.eventCache['DOMMouseScroll'].func, false); 
            
            Event.observe(this.eventCache['up_mousedown'].obj, 'mousedown', this.eventCache['up_mousedown'].func, false);
            Event.observe(this.eventCache['up_mouseup'].obj, 'mouseup', this.eventCache['up_mouseup'].func, false);
            Event.observe(this.eventCache['up_mouseout'].obj, 'mouseout', this.eventCache['up_mouseout'].func, false);
            
            Event.observe(this.eventCache['dn_mousedown'].obj, 'mousedown', this.eventCache['dn_mousedown'].func, false);
            Event.observe(this.eventCache['dn_mouseup'].obj, 'mouseup', this.eventCache['dn_mouseup'].func, false);
            Event.observe(this.eventCache['dn_mouseout'].obj, 'mouseout', this.eventCache['dn_mouseout'].func, false);
        } else {
            Event.stopObserving(this.eventCache['mousewheel'].obj, 'mousewheel', this.eventCache['mousewheel'].func, false); 
            Event.stopObserving(this.eventCache['DOMMouseScroll'].obj, 'DOMMouseScroll', this.eventCache['DOMMouseScroll'].func, false); 
            
            Event.stopObserving(this.eventCache['up_mousedown'].obj, 'mousedown', this.eventCache['up_mousedown'].func, false);
            Event.stopObserving(this.eventCache['up_mouseup'].obj, 'mouseup', this.eventCache['up_mouseup'].func, false);
            Event.stopObserving(this.eventCache['up_mouseout'].obj, 'mouseout', this.eventCache['up_mouseout'].func, false);
            
            Event.stopObserving(this.eventCache['dn_mousedown'].obj, 'mousedown', this.eventCache['dn_mousedown'].func, false);
            Event.stopObserving(this.eventCache['dn_mouseup'].obj, 'mouseup', this.eventCache['dn_mouseup'].func, false);
            Event.stopObserving(this.eventCache['dn_mouseout'].obj, 'mouseout', this.eventCache['dn_mouseout'].func, false);
        }
    },
    
    tmrResource : 0,
    
    mouseAction : function(delta,action) {
        if(action=='down') {
            this.tmrResource = setInterval(this.handle.bind(this, delta),75);
        } else {
            clearInterval(this.tmrResource);
        }
    },    
    
    scrollContent : function(v) {
        this.content.setStyle({top:(-v*(this.contentHeight-this.containerHeight+10))+"px"});
    },
    
    handle : function(delta) {
		this.slider.setValueBy(-delta*24/this.contentHeight);        
	},
    
    /** Event handler for mouse wheel event. */
    wheel : function(event){
        var delta = 0;
        if (!event) /* For IE. */
            event = window.event;
        if (event.wheelDelta) { /* IE/Opera. */
            delta = event.wheelDelta/120;
            /** In Opera 9, delta differs in sign as compared to IE. */
            if (window.opera)
                delta = -delta;
        } else if (event.detail) { /** Mozilla case. */
            /** In Mozilla, sign of delta is different than in IE.
            * Also, delta is multiple of 3.
            */
            delta = -event.detail/3;
        }

        /** If delta is nonzero, handle it.
        * Basically, delta is now positive if wheel was scrolled up,
        * and negative, if wheel was scrolled down.
        */
        if (delta)
            this.handle(delta);

        /** Prevent default actions caused by mouse wheel.
        * That might be ugly, but we handle scrolls somehow
        * anyway, so don't bother here..
        */
        if (event.preventDefault)
            event.preventDefault();
        
        event.returnValue = false;
    }
}