var MooScroller = new Class({

               options: {
                       maxThumbSize: 10,
                       mode: 'vertical',
                       width: 0, //required only for mode: horizontal
                       scrollSteps: 10,
                       wheel: true,
                       scrollLinks: {
                               forward: 'scrollForward',
                               back: 'scrollBack'
                       },
                       onScroll: Class.empty,
                       onPage: Class.empty
               },

               initialize: function(content, knob, options){
                       this.setOptions(options);
                       this.horz = (this.options.mode == "horizontal");

                       this.content = $(content).setStyle('overflow', 'hidden');
                       this.knob = $(knob);
                       this.track = this.knob.getParent();
                       this.setPositions();
                      
                       if(this.horz && this.options.width) {
                       		   this.wrapper = new Element('div');
                               this.content.getChildren().each(function(child){
                                       this.wrapper.adopt(child);
                               });
                               this.wrapper.injectInside(this.content).setStyle('width', this.options.width);
                       }
                       
                       this.bound = {
                               'start': this.start.bind(this),
                               'end': this.end.bind(this),
                               'drag': this.drag.bind(this),
                               'wheel': this.wheel.bind(this),
                               'page': this.page.bind(this)
                       };

                       this.position = {};
                       this.mouse = {};
                       this.update();
                       this.attach();
                       
                       var clearScroll = function (){
                               $clear(this.scrolling);
                       }.bind(this);
                       ['forward','back'].each(function(direction) {
                               var lnk = $(this.options.scrollLinks[direction]);
                               if(lnk) {
                                       lnk.addEvents({
                                               mousedown: function() {
                                                       this.scrolling = this[direction].periodical(50, this);
                                               }.bind(this),
                                               mouseup: clearScroll.bind(this),
                                               click: clearScroll.bind(this)
                                       });
                               }
                       }, this);
                       this.knob.addEvent('click', clearScroll.bind(this));
                       window.addEvent('domready', function(){
                               try {
                                   $(document.body).addEvent('mouseup', clearScroll.bind(this));
                               }catch(e){}
                       }.bind(this));
               },
               setPositions: function(){
                       [this.track, this.knob].each(function(el){
                               if (el.getStyle('position') == 'static') el.setStyle('position','relative');
                       });

               },
		/*      Property: update
               Updates the size of the scroll knob; execute this method when the content changes or the container's size is altered.
       */
               update: function(){
                       var plain = this.horz?'Width':'Height';
                       this.contentSize = this.content['offset'+plain];
                       this.contentScrollSize = this.content['scroll'+plain];
                       this.trackSize = this.track['offset'+plain];

                       this.contentRatio = this.contentSize / this.contentScrollSize;
						 
					   if (this.contentRatio >= 1) {
					      $$('.scrollarea').setStyle('visibility', 'hidden');
					   }
					   
                       this.knobSize = (this.trackSize * this.contentRatio).limit(this.options.maxThumbSize, this.trackSize);

                       this.scrollRatio = this.contentScrollSize / this.trackSize;
                       this.knob.setStyle(plain.toLowerCase(), this.knobSize+'px');
					   
					   // set bottom rounded corner below scrollKnob
					   $('scrollKnobBot').setStyle('top', (this.knobSize-6)+'px');
                       this.updateThumbFromContentScroll();
                       this.updateContentFromThumbPosition();
               },

               updateContentFromThumbPosition: function(){
                       this.content[this.horz?'scrollLeft':'scrollTop'] = this.position.now * this.scrollRatio;
               },

               updateThumbFromContentScroll: function(){
                       this.position.now = (this.content[this.horz?'scrollLeft':'scrollTop'] / this.scrollRatio).limit(0, (this.trackSize - this.knobSize));
                       this.knob.setStyle(this.horz?'left':'top', this.position.now+'px');
               },

               attach: function(){
                       this.knob.addEvent('mousedown', this.bound.start);
                       if (this.options.scrollSteps) this.content.addEvent('mousewheel', this.bound.wheel);
                       this.track.addEvent('mouseup', this.bound.page);
               },

               wheel: function(event){
                       event = new Event(event);
                       this.scroll(-(event.wheel * this.options.scrollSteps));
                       this.updateThumbFromContentScroll();
                       event.stop();
               },

               scroll: function(steps){
                       steps = steps||this.options.scrollSteps;
                       this.content[this.horz?'scrollLeft':'scrollTop'] += steps;
                       this.updateThumbFromContentScroll();
               },
               forward: function(steps){
                       this.scroll(steps);
               },
               back: function(steps){
                       steps = steps||this.options.scrollSteps;
                       this.scroll(-steps);
               },

               page: function(event){
                       var axis = this.horz?'x':'y';
                       event = new Event(event);
                       var forward = (event.page[axis] > this.knob.getPosition()[axis]);
                       this.scroll((forward?1:-1)*this.content['offset'+(this.horz?'Width':'Height')]);
                       this.updateThumbFromContentScroll();
                       this.fireEvent('onPage', forward);
                       event.stop();
               },


               
               start: function(event){
                       event = new Event(event);
                       var axis = this.horz?'x':'y';
                       this.mouse.start = event.page[axis];
                       this.position.start = this.knob.getStyle(this.horz?'left':'top').toInt();
                       document.addEvent('mousemove', this.bound.drag);
                       document.addEvent('mouseup', this.bound.end);
                       this.knob.addEvent('mouseup', this.bound.end);
                       event.stop();
               },

               end: function(event){
                       event = new Event(event);
                       document.removeEvent('mousemove', this.bound.drag);
                       document.removeEvent('mouseup', this.bound.end);
                       this.knob.removeEvent('mouseup', this.bound.end);
                       event.stop();
               },

               drag: function(event){
                       event = new Event(event);
                       var axis = this.horz?'x':'y';
                       this.mouse.now = event.page[axis];
                       this.position.now = (this.position.start + (this.mouse.now - this.mouse.start)).limit(0, (this.trackSize - this.knobSize));
                       this.updateContentFromThumbPosition();
                       this.updateThumbFromContentScroll();
                       event.stop();
               }

       });
       MooScroller.implement(new Events);
       MooScroller.implement(new Options);
