/*****************************************

The script is BRUTALY altered to fit some 'special' needs:
Automatic position/size of vertical scroll is disabled and 
vRatio-calculations altered.

/*****************************************

Purplebucket scroller version 0.1
copyright 2009, Timo Pettersson www.purplebucket.com/code

You are allowed to do what ever you want with PB scroller.
Remember that it uses prototype.js wich is licensed under
an MIT-style license. www.prototypejs.org.
Tested with prototypejs version 1.6.0.3


Class that creates a scrollable div.

It takes two paramaters 'nodes' and 'args'
'nodes'
  Either a string of the div or an object of the div
  that you want to be scrollable.
  Or an object with all the nodes needed
    { content, area, container, vBar, hBar }
  If 'vBar' or 'hBar' are omitted they will not exist,

  'content', 'area' and 'container' are needed
  'content':   The div that contains the content
  'area':      This div should contain the 'content' div
  'container': Should contain the 'area' div

'args'
  An object with arguments for the scroller.

  'direction':     What directions shold be scrollable
                   should have 'v' and/or 'h' for the
                   different scrollers.
                   Default: 'v'

  'wheelDistance': The distance the scrollwheel on the
                   mouse should move the content.
                   Default: 10

  'wheelEnabled':  If the wheel scrolling should be enabled.
                   Default: true

  If the args object is omitted the defaults will be used.


  Following code needs to run before wheel scrolling will work

  Object.extend(Event, {
    wheel:function (event){
      return event.detail ? (event.detail * -1) : event.wheelDelta / 40;
    }
  });

******************************************/

if (!window.pb) {
  window.pb = {};
}

pb.scroll = Class.create({
  initialize: function(nodes, args) {
    if (typeof nodes == 'string') {
      this.divToConvert = $(nodes);
    } else if (nodes.tagName) {
      this.divToConvert = nodes;
    } else {
      this.nodes = nodes;
    }

    this.args = !!args ? args : {};

    this.initEvents();

    this.initNodes();
    this.redraw();
  },

  initEvents: function() {
    this.onScrollH     = function(scroller, method) {};
    this.onScrollV     = function(scroller, method) {};
    this.onReachTop    = function(scroller, method) {};
    this.onReachBottom = function(scroller, method) {};
    this.onReachLeft   = function(scroller, method) {};
    this.onReachRight  = function(scroller, method) {};
    this.onVBarHide    = function(scroller) {};
    this.onHBarHide    = function(scroller) {};
  },

  initNodes: function() {
    if (this.divToConvert) {
      this.nodes = {};
      this.nodes.container = document.createElement('div');
      this.nodes.area      = document.createElement('div');

      this.nodes.vBar      = this.args.direction == undefined || this.args.direction.indexOf('v') > -1 ? document.createElement('div') : null;
      this.nodes.hBar      = this.args.direction != undefined && this.args.direction.indexOf('h') > -1 ? document.createElement('div') : null;
      this.nodes.content   = this.divToConvert;

      var position   = Element.positionedOffset(this.nodes.content);
      var dimensions = Element.getDimensions(this.nodes.content);

      this.nodes.container.appendChild(this.nodes.area);
      if (!!this.nodes.vBar) this.nodes.container.appendChild(this.nodes.vBar);
      if (!!this.nodes.hBar) this.nodes.container.appendChild(this.nodes.hBar);
      var parent = this.nodes.content.parentNode;
      parent.insertBefore(this.nodes.container, this.nodes.content);
      this.nodes.area.appendChild(this.nodes.content);

      this.nodes.container.className = this.nodes.content.className;
      this.nodes.content.className = '';

      var cssString = this.nodes.content.style.cssText;
      if( typeof(cssString) != 'string' ) {
        cssString = this.nodes.content.getAttribute('style');
      }

      this.nodes.container.style.cssText = cssString;
      this.nodes.container.setAttribute('style',cssString);

      Element.setStyle(this.nodes.container, { position: 'relative' });
      Element.setStyle(this.nodes.content, { width: 'auto', height: 'auto', position: 'absolute', top: '0px', left: '0px', overflow: 'visible' });

    } else {
      if (!!this.args.direction && this.args.direction.indexOf('v') == -1) this.nodes.vBar = null;
      if (!!this.args.direction && this.args.direction.indexOf('h') == -1) this.nodes.hBar = null;
    }

    Element.addClassName(this.nodes.container, 'scrollContainer');
    Element.addClassName(this.nodes.area,      'scrollArea');
    Element.addClassName(this.nodes.content,   'scrollContent');
    Element.addClassName(this.nodes.vBar,      'vBar');
    Element.addClassName(this.nodes.hBar,      'hBar');

    Element.setStyle(this.nodes.area, { position: 'absolute', overflow: 'hidden' });

    if (!!this.nodes.vBar) {
      this.nodes.vHandle = document.createElement('div');
      Element.addClassName(this.nodes.vHandle, 'vHandle');
      this.nodes.vHandle.innerHTML = '&nbsp;';
      this.nodes.vBar.appendChild(this.nodes.vHandle);

      Drag.init(this.nodes.vHandle, null, 0, 0, 0);

      this.canVDrag = true;
      this.nodes.vHandle.onDragStart = (function(x, y) { this.canVDrag = false; }).bind(this);
      this.nodes.vHandle.onDragEnd   = (function(x, y) {
        if (y <= 0) this.onReachTop(this, 'drag');
        if (y >= this.nodes.vHandle.maxY) this.onReachBottom(this, 'drag');
        setTimeout((function() { this.canVDrag = true; }).bind(this), 100);
      }).bind(this);

      Event.observe(this.nodes.vBar, 'click', (function(event) { this.vBarClick(event); }).bind(this));
    }
    if (!!this.nodes.hBar) {
      this.nodes.hHandle = document.createElement('div');
      Element.addClassName(this.nodes.hHandle, 'hHandle');
      this.nodes.hHandle.innerHTML = '&nbsp;';
      this.nodes.hBar.appendChild(this.nodes.hHandle);

      Drag.init(this.nodes.hHandle, null, 0, null, 0, 0);

      this.canHDrag = true;
      this.nodes.hHandle.onDragStart = (function(x, y) { this.canHDrag = false; }).bind(this);
      this.nodes.hHandle.onDragEnd   = (function(x, y) {
        if (x <= 0) this.onReachLeft(this, 'drag');
        if (x >= this.nodes.hHandle.maxX) this.onReachRight(this, 'drag');
        setTimeout((function() { this.canHDrag = true; }).bind(this), 100);
      }).bind(this);

      Event.observe(this.nodes.hBar, 'click', (function(event) { this.hBarClick(event); }).bind(this));
    }

    if (this.args.wheelEnabled == undefined || this.args.wheelEnabled) {
      Event.observe(this.nodes.area, "mousewheel",     (function(event) { this.wheelScroll(event); }).bind(this));
      Event.observe(this.nodes.area, "DOMMouseScroll", (function(event) { this.wheelScroll(event); }).bind(this));
    }

  },

  redraw: function() {
    var containerDimensions = Element.getDimensions(this.nodes.container);
    var vWidth  = !!this.nodes.vBar ? Element.getWidth(this.nodes.vBar)  : 0;
    var hHeight = !!this.nodes.hBar ? Element.getHeight(this.nodes.hBar) : 0;

    Element.setStyle(this.nodes.area, { width: (containerDimensions.width - vWidth) + 'px', height: (containerDimensions.height - hHeight) + 'px' });
/*
    if (!!this.nodes.vBar) {
      var left   = containerDimensions.width - vWidth;
      var height = containerDimensions.height - hHeight;
      Element.setStyle(this.nodes.vBar, { left: left + 'px' });
    }

    if (!!this.nodes.hBar) {
      var top   = containerDimensions.height - hHeight;
      var width = containerDimensions.width - vWidth;
      Element.setStyle(this.nodes.hBar, { top: top + 'px' });
    }
*/
    var contentPosition = Element.positionedOffset(this.nodes.content);
    var contentDimensions = Element.getDimensions(this.nodes.content);
    var areaDimensions = Element.getDimensions(this.nodes.area);

    if (contentPosition[1] + contentDimensions.height <= areaDimensions.height && contentPosition[1] < 0) {
      var top = areaDimensions.height - contentDimensions.height;
      if (top > 0) top = 0;

      Element.setStyle(this.nodes.content, { top: top + 'px' });
    }
    if (contentPosition[0] + contentDimensions.width <= areaDimensions.width && contentPosition[0] < 0) {
      var left = areaDimensions.width - contentDimensions.width;
      if (left > 0) left = 0;
      Element.setStyle(this.nodes.content, { left: left + 'px' });
    }


    this.positionHandles();
  },

  positionHandles: function() {
    var areaDimensions    = Element.getDimensions(this.nodes.area);
    var contentPosition   = Element.positionedOffset(this.nodes.content);
    var contentDimensions = Element.getDimensions(this.nodes.content);

    if (!!this.nodes.vBar) {
      var height = Element.getHeight(this.nodes.vBar);
      var hheight = Element.getHeight(this.nodes.vHandle);

      var vRatio = 1;
      if (contentDimensions.height != 0) vRatio = (contentDimensions.height-areaDimensions.height) / height;
      var handleHeight = Math.round(height / vRatio);
      if (handleHeight < 5) handleHeight = 5;
      if (handleHeight > height) handleHeight = height;

      var y = Math.floor((contentPosition.top / vRatio) * -1);
      //y = Math.floor(y * (height/areaDimensions.height)) - hheight;
	  
      Element.setStyle(this.nodes.vHandle, { top: y + 'px' });

      this.nodes.vHandle.maxY = height;
/*
      if (handleHeight == height) {
        Element.hide(this.nodes.vBar);
        Element.setStyle(this.nodes.area, { width: areaDimensions.width + Element.getWidth(this.nodes.vBar) + 'px' });
        this.onVBarHide(this);
      } else {
        Element.show(this.nodes.vBar);
      }
      */
      
	  var contentHeight = Element.getHeight(this.nodes.content);
	  var areaHeight    = Element.getHeight(this.nodes.area);

	  if (contentHeight > areaHeight) {
	        this.nodes.vHandle.onDrag = (function(x, y) {
		        Element.setStyle(this.nodes.content, { top: (y * -vRatio) + 'px' });
		        this.onScrollV(this, 'drag');
	        }).bind(this);
	  }
	  else
	      	Element.hide(this.nodes.vBar);
    }
    if (!!this.nodes.hBar) {
      var width = Element.getWidth(this.nodes.hBar);

      var hRatio = 1;
      if (contentDimensions.width != 0) hRatio = contentDimensions.width / areaDimensions.width;
      var handleWidth = Math.round(width / hRatio);
      if (handleWidth < 5) handleWidth = 5;
      if (handleWidth > width) handleWidth = width;

      var x = Math.floor((contentPosition.left / hRatio) * -1);

      Element.setStyle(this.nodes.hHandle, { left: x + 'px' });

      this.nodes.hHandle.maxX = width - handleWidth;

      if (handleWidth == width) {
        Element.hide(this.nodes.hBar);
        Element.setStyle(this.nodes.area, { height: areaDimensions.height + Element.getHeight(this.nodes.hBar) + 'px' });
        this.onHBarHide(this);
      } else {
        Element.show(this.nodes.hBar);
      }

      this.nodes.hHandle.onDrag = (function(x, y) {
        Element.setStyle(this.nodes.content, { left: (x * -hRatio) + 'px' });
        this.onScrollH(this, 'drag');
      }).bind(this);
    }
  },

  vBarClick: function(event) {
    if (!this.canVDrag) return;

    var pos = Element.cumulativeOffset(this.nodes.vBar);
    var y = event.pointerY() - pos[1];

    var barHeight    = Element.getHeight(this.nodes.vBar);
    var handleHeight = Element.getHeight(this.nodes.vHandle);

    var newY = y - Math.floor((handleHeight/2));
    if (newY < 0) { newY = 0; }
    if (newY + handleHeight > barHeight) { newY = barHeight - handleHeight; }

    Element.setStyle(this.nodes.vHandle, { top : newY + 'px' });

    this.positionContent();

    this.onScrollV(this, 'click');
    if (newY == 0) this.onReachTop(this, 'click');
    if (newY == barHeight - handleHeight) this.onReachBottom(this, 'click');
  },

  hBarClick: function(event) {
    if (!this.canHDrag) return;

    var pos = Element.cumulativeOffset(this.nodes.hBar);
    var x = event.pointerX() - pos[0];

    var barWidth    = Element.getWidth(this.nodes.hBar);
    var handleWidth = Element.getWidth(this.nodes.hHandle);

    var newX = x - Math.floor((handleWidth / 2));
    if (newX < 0) { newX = 0; }
    if (newX + handleWidth > barWidth) { newX = barWidth - handleWidth; }

    Element.setStyle(this.nodes.hHandle, { left : newX + 'px' });

    this.positionContent();

    this.onScrollH(this, 'click');
    if (newX == 0) this.onReachLeft(this, 'click');
    if (newX == barWidth - handleWidth) this.onReachRight(this, 'click');
  },

  positionContent: function() {
    var areaDimensions    = Element.getDimensions(this.nodes.area);
    var contentDimensions = Element.getDimensions(this.nodes.content);
    var contentPosition   = Element.positionedOffset(this.nodes.content);
	var height = Element.getHeight(this.nodes.vBar);
	var hheight = Element.getHeight(this.nodes.vHandle);
	
    //var vRatio = contentDimensions.height / areaDimensions.height;
    var vRatio = Math.floor((contentDimensions.height-areaDimensions.height) / height);

	
	
	var y = !!this.nodes.vBar ?  Element.positionedOffset(this.nodes.vHandle).top + Math.floor(hheight) : 0;
//    var contentPosition   = Element.positionedOffset(this.nodes.content);
//	var y = Math.floor(contentPosition.top/contentDimensions.height);

    var hRatio = contentDimensions.width / areaDimensions.width;
    var x = !!this.nodes.hBar ?  Element.positionedOffset(this.nodes.hHandle).left : 0;

    var contentHeight = Element.getHeight(this.nodes.content);
    var areaHeight    = Element.getHeight(this.nodes.area);
    if (contentHeight > areaHeight) {
   		Element.setStyle(this.nodes.content, { top: (y * (-vRatio) + 'px'), left: (x * (-hRatio) + 'px') });
   	}
  },

  wheelScroll: function(event) {
    var change = Event.wheel(event);

    Event.stop(event);

    var contentHeight = Element.getHeight(this.nodes.content);
    var areaHeight    = Element.getHeight(this.nodes.area);

    if (contentHeight > areaHeight) {
      var currentPos = Element.positionedOffset(this.nodes.content).top;
      if (!(currentPos <= 0)) currentPos = 0;

      var newPos = currentPos + (change * (!!this.args.wheelDistance ? this.args.wheelDistance : 10));
      if (newPos > 0) newPos = 0;

      if (newPos < areaHeight - contentHeight) newPos = areaHeight - contentHeight;

      Element.setStyle(this.nodes.content, { top: newPos + 'px' });
    }

    this.positionHandles();

    this.onScrollV(this, 'wheel');
    if (newPos == 0) this.onReachTop(this, 'wheel');
    if (newPos <= areaHeight - contentHeight) this.onReachBottom(this, 'wheel');
  }

});
