/* -----------------------------------------------------------------------------
* scroller.js
* Copyright 2009 wollzelle GmbH (http://wollzelle.com). All rights reserved.
* ------------------------------------------------------------------------------ */
(function(){
  
  var $ = document.id;

  var Scroller = new Class({
  
    Implements: Options,
  
    options: {
      wheelEnabled: true
    },
  
    initialize: function(element, options){
      this.setOptions(options);

      this.element = $(element);
      this.dims = this.element.getSize();
      var html = this.element.get('html');
    
      this.contentHeight = parseInt(this.element.getStyle('height'));
    
      // Create a wrapper/scroller elements and inject them in existing code
      this.content   = new Element('div', { 'class': 'scroller-content' }).set('html', html);
      this.scrollbar = new Element('div', { 'class': 'scroller-scrollbar' });
      this.handle    = new Element('div', { 'class': 'scroller-thumb' });
    
      this.element.set('html', '').setStyle('height', 'auto');
      this.element.adopt(this.content, this.scrollbar, this.handle).setStyle('overflow', 'hidden');
      this.scrollbar.grab(this.handle);
    
       // We need to set height for scrollbar element for IE6
      if(Browser.Engine.trident4)
        this.scrollbar.setStyle('height', this.contentHeight);
      
      this.content.setStyles({
        'position':     'relative',
        'padding-right': 20,
        'height':       this.contentHeight,
        'overflow':     'hidden'
      });
    
      this.refresh();
  	
    	// Scroll the element element when the mousewheel is used within the 
  		// element or the scrollbar element.
    	if(this.options.wheelEnabled)
    		$$(this.content, this.scrollbar).addEvent('mousewheel', this.handleWheel.bindWithEvent(this));
  	
    	// Stops the handle dragging process when the mouse leaves the document body.
      $(document.body).addEvent('mouseleave',function(){this.slider.drag.stop()}.bindWithEvent(this));
    },
  
    handleWheel: function(event){
      event.stop();
  		var step = this.slider.step - event.wheel * 30;	
  		this.slider.set(step);
    },
  
    refresh: function(){
      // Scroll on top
      this.element.scrollTo(0,0);

      if($defined(this.slider)) {
        this.slider.detach();
        this.slider = null;
      }
    
      var elHeight = this.element.getSize().y;
      var steps = this.content.getScrollSize().y - elHeight;
      steps = (steps > 0) ? steps : 0; // Fix for IE7
      $(this.scrollbar, this.handle).setStyle('display', (steps == 0) ? 'none' : 'block'); // Don't display scrollbar unless it's necessary
      var thumbHeight =  elHeight * elHeight / (steps + this.element.getSize().y);
      this.handle.setStyle('height', (thumbHeight <= 20) ? 20: thumbHeight);

    	this.slider = new Slider(this.scrollbar, this.handle, {
    		steps: steps,
    		mode: 'vertical',
    		onChange: function(step){ 
    		  this.content.scrollTo(0,step);
    		  this.element.fireEvent('scroller:scrolled');
    		}.bindWithEvent(this)
    	});
  	
    	(function(){ this.slider.set(0) }.bind(this)).delay(1); // IE7 fix
    },
  
    destroy: function(){
      var html = this.content.get('html');
      if($defined(this.slider)) this.slider.detach();
      $$(this.content, this.scrollbar).removeEvents('mousewheel');
      $(this.content, this.scrollbar, this.handle).destroy();
      this.element.set('html', html).setStyle('height', this.dims.y);
    }
  
  });

  Element.implement({
    /**
     * Element#makeScrollable(element, options) -> Element
     * 
     * Implements custom scrollbars for a given element
     * 
     * 
     **/
    makeScrollable: function(options){
      if(!Browser.Engine.webkit) // Use CSS scroller in Webkit-based browsers
        this.scroller = new Scroller(this, options);
      else if(Browser.Platform.name == 'ipod') // But custom scroller for touch devices
        this.scroller = new iScroll(this.getElement('div'), options);
      
      // Add event listener to perform glue-less scroller updates
      if($defined(this.scroller)) this.addEvent('scroller:refresh', this.scroller.refresh.bindWithEvent(this.scroller));
    
    	return this;
    }
  });
})();
