var Carousels = function() {
      var instances = {};
      var timeTick = 10;
      var registerInstance = function( key, instance) {
        instances[key] = instance;
      }
      return {
        Instance : Class.create( {
          /**
           * parameters :
           *   - container       : the id of the div containing datas to show by sliding (should have a overflow:hidden)
           *   - content         : the id of the element sliding (by negative margin-left)
           *   - moveNextElement : the elment which will order a sliding to next by click event handling
           *   - movePrevElement : the elment which will order a sliding to previous by click event handling
           *   - speedChangeDist : the minimum distance between 
           *      1/ current position and target position  
           *      2/ current position and origin position 
           *    to get full speed. Otherwise gets a sin of proportion.
           *    NOTE : if given distance is negative, minimum distance will be evaluated to 
           *             get it as the minimum value between absolute value of given speedChangeDist and distance to be done
           *   - moveBy      : the moveBy pixel at full speed
           *   - minMove       : the minimum move in pixel
           */
          initialize : function(params) {
            this.container      = $(params.container);
            this.content      = $(params.content);
            this.contained      = this.content.childElements();
            this.moveNextElement  = (params.moveNextElement) ? $(params.moveNextElement) : null;
            this.movePrevElement  = (params.movePrevElement) ? $(params.movePrevElement) : null;
            this.containedWidth   = 0;
            this.singleItemWidth  = 0;
            this.originPosition   = 0;
            this.targetMarginLeft = 0;
            this.speedChangeDist  = (params.speedChangeDist) ? params.speedChangeDist : 100;
            this.moveBy       = (params.moveBy) ? params.moveBy : 20;
            this.minMove      = (params.minMove) ? params.minMove : 1;
            this.autoMove     = params.autoMove;
            this.currTick     = 0;
            this.bindEvents();
            if( this.decideVisibility() ) {
              registerInstance(this.container.identify(), this);
            }
          },
          
          bindEvents : function() {
            if(this.moveNextElement) {
              Event.observe(this.moveNextElement, "click", this.next.bindAsEventListener(this));
            }
            if(this.movePrevElement) {
              Event.observe(this.movePrevElement, "click", this.previous.bindAsEventListener(this));
            }
          },
          
          decideVisibility : function() {
            
            this.containedWidth = 0;
            for(var i=0;i<this.contained.length;i++) {
              this.containedWidth += this.contained[i].getWidth();
              this.singleItemWidth =  this.contained[i].getWidth();
            }
            if(this.containedWidth <= this.container.getWidth()) {
              if(this.moveNextElement) {
                this.moveNextElement.hide();
              }
              if(this.movePrevElement) {
                this.movePrevElement.hide();
              }
              return false;
            }
            return true;
          },
          
          getMarginLeft : function(element) {
            var toParse = element.style.marginLeft;
            if(toParse.replace(/\s/g, "") == "") {
              toParse = "0";
            }
            return parseInt(toParse.replace(/px/, ""));
          },
          
          previous : function() {
            if(this.container.getWidth() - this.targetMarginLeft < this.containedWidth) {
              this.targetMarginLeft = (this.targetMarginLeft - this.singleItemWidth);
            } else {
              this.targetMarginLeft = 0;
            }
          },
          
          next : function() {
            if(this.targetMarginLeft < 0) {
              this.targetMarginLeft = (this.getMarginLeft(this.content) + this.singleItemWidth);
            } else {
              this.targetMarginLeft = (this.container.getWidth() - this.containedWidth);
            }
          },
          
          tick : function() {           
            var distToOri   = Math.abs(this.originPosition - this.getMarginLeft(this.content));
            var distToDest    = Math.abs(this.targetMarginLeft - this.getMarginLeft(this.content));
            
            var smallestdist  = Math.min(distToOri, distToDest);
            
            var coeff     = 1;
            var speedChangeDistLocal = (this.speedChangeDist < 1) ? Math.min(((distToOri + distToDest) / 2), Math.abs(this.speedChangeDist))  : this.speedChangeDist;
            
            if(smallestdist < speedChangeDistLocal) {
              coeff     = Math.sin((smallestdist / speedChangeDistLocal) * (Math.PI / 4));
            }
            
            var move = Math.min(distToDest, Math.max(this.minMove, this.moveBy * coeff));
            
            
            if(this.getMarginLeft(this.content) > this.targetMarginLeft) {
              move *= -1;
            }
            this.content.style.marginLeft = this.getMarginLeft(this.content) + move + "px";
            
            if(this.getMarginLeft(this.content) == this.targetMarginLeft) {
              this.currTick ++;
              this.originPosition = this.targetMarginLeft;
              if(this.currTick % this.autoMove == 0) {
                this.next();
              }
            }
          }
        }),
        
        tick : function() {
          for(var key in instances) {
            instances[key].tick()
          }
          //Carousels.tick.defer(timeTick);
          setTimeout("Carousels.tick()", timeTick);
        },
        
        setTimeTick : function(value) {
          timeTick = Math.max(1, value);
        },
        
        getTimeTick : function() {
          return timeTick;
        }
      };
    }();


Carousels.tick();