//////////// ELEMENT SCROLLER /////////
//Author:     Ondrej Jaura
//Date:       1. May 2008
//Version:    1.0
//Prototype:  v1.6+
//Please leave this note here 
///////////////////////////////////////

Object.extend(Event, {
	wheel:function (event){
	  Event.stop(event);
		var delta = 0;
		if (!event) event = window.event;
		if (event.wheelDelta) {
			delta = event.wheelDelta/120; 
			if (window.opera) delta = -delta;
		} else if (event.detail) { delta = -event.detail/3;	}
		if (window.opera) delta*=(-1); // Opera flip
		return Math.round(delta); //Safari Round
	}
});

var Scroller = Class.create({
  initialize: function(element,options) {
    this.element=$(element);
    this.options = Object.extend({
      barWidth: 12,
      elementPadding: (this.element.getStyle("padding"))?parseInt(this.element.getStyle("padding")):0,
      scrollSpeed: 0.05,
      scrollSteps: 15
    }, options || {});
    if (this.element.getStyle('borderWidth')==""||this.element.getStyle('borderWidth')=="medium") this.element.style.borderWidth='0px';
    if (this.element.getStyle('padding')=="") this.element.style.padding='0px';
    var sh=this.element.scrollHeight;
    //if (navigator.appName=="Netscape") sh=this.element.scrollHeight-parseInt(this.element.getStyle("padding"))*2;
    var h=parseInt(this.element.style.height);
    if (sh>h&&sh!=h) {this.createScroller();}    
  },
  createScroller: function () {
    this.content=$(document.createElement("div"));
    this.content.innerHTML=this.element.innerHTML;
    this.content.scrollTop=0;
    this.element.innerHTML="";
    this.element.appendChild(this.content);
    
    this.element.setStyle({
      position: 'relative',
      overflow: 'hidden',
      padding: '0',
      width: (this.element.getWidth()-parseInt(this.element.getStyle('borderWidth'))*2)+"px",
      height: (this.element.getHeight()-parseInt(this.element.getStyle('borderWidth'))*2)+"px"
    });
      
    this.content.setStyle({
      position: 'absolute',
      overflow: 'hidden',
      padding: this.options.elementPadding+"px",
      margin: '0',
      width: (this.element.getWidth()-this.options.barWidth-this.options.elementPadding*2-parseInt(this.element.getStyle('borderWidth'))*2)+'px',
      height: (this.element.getHeight()-this.options.elementPadding*2-parseInt(this.element.getStyle('borderWidth'))*2)+'px'
    });
    Event.observe(this.content, "mousewheel", this.onWheel.bindAsEventListener(this));
    Event.observe(this.content, "DOMMouseScroll", this.onWheel.bindAsEventListener(this));

    if (navigator.appName=="Opera") this.content.scrollHeight+=this.options.elementPadding*2;
    
    // ARROW UP
    this.arrowUp=$(document.createElement("div"));
    this.arrowUp.addClassName('scrollUp');
    this.element.appendChild(this.arrowUp);
    this.arrowUp.setStyle({
      width: this.options.barWidth+'px', 
      height: this.options.barWidth+'px',
      position: 'absolute',
      top: '0px', 
      left: (this.element.getWidth()-this.options.barWidth-parseInt(this.element.getStyle('borderWidth'))*2)+"px"
    });
    
    Event.observe(this.arrowUp, 'mousedown', this.startScrolling.bindAsEventListener(this,'up'));
    Event.observe(this.arrowUp, 'mouseup', this.stopScrolling.bindAsEventListener(this));
    Event.observe(this.arrowUp, 'mouseout', this.stopScrolling.bindAsEventListener(this));
    
    //ARROW DOWN
    this.arrowDown=$(document.createElement("div"));
    this.arrowDown.addClassName('scrollDown');
    this.element.appendChild(this.arrowDown);
    this.arrowDown.setStyle({
      width: this.options.barWidth+'px', 
      height: this.options.barWidth+'px', 
      position: 'absolute',
      top: (this.element.getHeight()-this.options.barWidth-parseInt(this.element.getStyle('borderWidth'))*2)+"px", 
      left: (this.element.getWidth()-this.options.barWidth-parseInt(this.element.getStyle('borderWidth'))*2)+"px"
    });
    
    Event.observe(this.arrowDown, 'mousedown', this.startScrolling.bindAsEventListener(this,'down'));
    Event.observe(this.arrowDown, 'mouseup', this.stopScrolling.bindAsEventListener(this));
    Event.observe(this.arrowDown, 'mouseout', this.stopScrolling.bindAsEventListener(this));
    
    //SCROLL BAR
    this.scrollBar=$(document.createElement("div"));
    this.scrollBar.addClassName('scrollBar');
    this.element.appendChild(this.scrollBar);
    
    this.setScrollSize();
    
    this.scrollBar.setStyle({
      width: this.options.barWidth+'px', 
      position: 'absolute', 
      top: (this.options.barWidth)+"px", 
      left: (this.element.getWidth()-this.options.barWidth-parseInt(this.element.getStyle('borderWidth'))*2)+"px"
    });
    
    this.barMouseDownEvent=this.barMouseDown.bindAsEventListener(this);
    this.barMouseMoveEvent=this.barMouseMove.bindAsEventListener(this);
    this.barMouseUpEvent=this.barMouseUp.bindAsEventListener(this);
    Event.observe(this.scrollBar, 'mousedown', this.barMouseDownEvent);
  },
  scroll: function(direction,steps) {
    var cont=false;
    if (steps) var t=steps;
    else var t=1;
    for (var i=0;i<t;i++) {
      if (this.content.scrollTop<this.options.scrollSteps&&direction=="up") this.content.scrollTop=0;
      else if (this.content.scrollTop>this.content.scrollHeight-this.content.getHeight()-this.options.scrollSteps&&direction=="down") this.content.scrollTop=this.content.scrollHeight-this.content.getHeight();
      else {
        switch (direction) {
          case "up": this.content.scrollTop-=this.options.scrollSteps; break;
          case "down": this.content.scrollTop+=this.options.scrollSteps; break;
        }
        cont=true;
      }
    }
    this.updateBarPosition();
    return cont;
  },
  startScrolling: function(e,direction) {
    if (this.element) {
      this.setScrollSize();
      this.delayExponent=0
      var cont=this.scroll(direction);
      if (cont) this.scrollTimer = this.startScrolling.delay(this.options.scrollSpeed, this, direction);
    } else {
      if (e.options.scrollSpeed-e.delayExponent>0.01) e.delayExponent+=0.001;
      var cont=e.scroll(direction);
      if (cont) e.scrollTimer = e.startScrolling.delay(e.options.scrollSpeed-e.delayExponent, e, direction);
    }
  },
  stopScrolling: function() {
    if (this.scrollTimer) {
      window.clearTimeout(this.scrollTimer);
    }
  },
  barMouseDown: function(e) {
    Event.stop(e);
    this.setScrollSize();
    Event.observe(document, 'mousemove', this.barMouseMoveEvent);
    Event.observe(document, 'mouseup', this.barMouseUpEvent);
    this.mouseY=Event.pointerY(e);
    this.barTop=parseInt(this.scrollBar.getStyle('top'));
  },
  barMouseMove: function(e) {
    Event.stop(e);
    var newMouseY=Event.pointerY(e);
    var top=parseInt(this.barTop+newMouseY-this.mouseY);
    if (top<this.options.barWidth) top=this.options.barWidth;
    else if (top>this.slideScrollHeight+this.options.barWidth) top=this.slideScrollHeight+this.options.barWidth;
    this.scrollBar.setStyle({top: top+"px"});
    this.content.scrollTop=(top-this.options.barWidth)*this.scrollRatio;
  },
  barMouseUp: function(e) {
    Event.stop(e);
    Event.stopObserving(document, 'mousemove', this.barMouseMoveEvent);
    Event.stopObserving(document, 'mouseup', this.barMouseUpEvent);
  },
  onWheel: function(e) {
    this.setScrollSize();
    var direction=Event.wheel(e);
    if (direction>0) this.scroll("up",direction*2);
    else this.scroll("down",direction*(-2));
  },
  setScrollSize: function() {
    this.slideHeight=this.element.getHeight()-this.options.barWidth*2-parseInt(this.element.getStyle('borderWidth'))*2;
    this.scrollRatio=this.content.scrollHeight/this.slideHeight;
    this.barHeight=Math.round(this.content.getHeight()/this.scrollRatio);
    this.slideScrollHeight=this.slideHeight-this.barHeight;
    this.scrollBar.setStyle({height: (this.barHeight-2)+'px'});
    this.updateBarPosition();
  },
  updateBarPosition: function() {
    var cSH=this.content.scrollHeight;
    var cST=this.content.scrollTop;
    var bSH=this.slideHeight;
    var bST=parseInt(this.scrollBar.getStyle('top'))-this.options.barWidth;
    var ratio=cSH/cST;
    this.scrollBar.style.top=Math.round(this.options.barWidth+(bSH/ratio))+"px";
  }
});
