(function($){

function map ( value, low1, high1, low2, high2 ) {
  return ( high2 - low2 ) * ( value - low1 ) / ( high1 - low1 ) + low2;
}

var ns = "AutoSlide";

window[ns] = function ( options ) {
  this.root = $(options.root);
  this.box  = $(options.box);
  this.roller = $(options.roller);
  
  if ( ! this.root.length ) return;

  this.init();
  this.observe();
};

window[ns].prototype = {
  init: function () {
    this.counter = 0;

    this.is_rolling = true;
    this.disable_roll = false;
    
    this.middle = $(window).width() / 2;
    
    this.start_point = 0;
    this.end_point = ( this.roller.width() - this.box.width() ) * -1;

    this.disable_roll = this.box.width() >= this.roller.width();
    this.direction = 'right';
    
    this.mousemove();
  },
  
  observe: function () {
    this.root.hover( $.proxy( this.mouseover, this ) , $.proxy( this.mouseout, this ) );
    $(document).mousemove( $.proxy( this.mousemove, this ) );
    $(window).resize( $.proxy( this.resize, this ) );
  },
  
  resize: function ( event ) {
    this.middle = $(window).width() / 2;
  },
  
  mouseover: function () {
    this.hover = true;
  },
  
  mouseout: function () {
    this.hover = false;
  },
  
  mousemove: function ( event ) {
    if ( this.disable_roll ) return;
    
    this.latest_id = this.counter++;
    
    if ( this.hover ) {
      this.x = event.pageX;

      this.is_rolling = true;
      this.rolling( this.latest_id );
    } else {
      this.is_rolling = false;
      this.autoroll( this.latest_id );
    }
  },
  
  in_range: function ( x, y ) {
    return this.x_range[0] < x  && x < this.x_range[1] && this.y_range[0] < y && y < this.y_range[1] ;
  },
  
  autoroll: function ( my_id ) {
    var unit = 1;
    var step = this.direction == 'right' ? -unit : unit;
    this.move( step, my_id, 'autoroll' );
  },
  
  rolling: function ( my_id ) {
    if ( ! this.is_rolling ) return;
    
    var step = this.parse_position( this.x, this.middle );
    this.move( step, my_id );
  },
  
  parse_position: function ( x, middle ) {
    var step;
    if ( x < middle ) { // forward
      step = map( x, 0, middle, 3, 0 );
    } else {
      step = map( x, middle, middle*2, 0, -3 );
    }
    
    return step;
  },
  
  move: function ( step, my_id, autoroll ) {
    var go_forward  = step > 0;
    var go_backward = step < 0;
    var left = parseFloat(this.roller.css('left'));
    
    if ( go_forward && left >= this.start_point ) {
      this.roller.css('left', this.start_point + 'px');
      this.direction = 'right';
      if ( autoroll ) {
        this.continueRolling(my_id, autoroll);
      }
      return;
    }
    if ( go_forward && this.start_point - left < step ) {
      step = this.start_point - left;
    }
    
    
    if ( go_backward && left <= this.end_point ) {
      this.roller.css('left', this.end_point + 'px');
      this.direction = 'left';
      if ( autoroll ) {
        this.continueRolling(my_id, autoroll);
      }
      return;
    }
    if ( go_backward && this.end_point - left > step ) {
      step = this.end_point - left;
    }
    if ( $.browser.msie ) var unit = 1;
    else var unit = 10;
    this.roller.animate({
        left: '+=' + step
      }, { 
           easing: 'linear',
           duration: unit,
           complete: $.proxy( function() {
               this.continueRolling(my_id, autoroll);
             }, this )
      } );
      
  },
  
  continueRolling: function ( my_id, autoroll ) {
    var method = autoroll ? 'autoroll' : 'rolling';
    if ( my_id === this.latest_id ) this[method]( my_id );
  }
  
};

})(jQuery);
