var Slideshow = function(container, controls_container, width, options) {
  
  var playing = true;
  var animating = false;
  
  var animation_length = 750;
  var slide_interval = 3000;
  var slide_timer;
  
  var current_slide = 0;
  var slide_count = 0;
  
  var controls;
  var slideshow;
  var slides;
  
  var scroll_left, scroll_right;
  
  var queue;
  
  var last_mouse_x = null;
  
  var w;
  
  var init = function(container, controls_container, width) {
    slideshow = container;
    slides = slideshow.find('.slide');
    slide_count = slides.size();
  
    w = width;
      
    $('<div></div>').addClass('capture').appendTo(slideshow);
    $('<div></div>').addClass('slideshow-left').appendTo(slideshow);
    $('<div></div>').addClass('slideshow-right').appendTo(slideshow);
  
    scroll_left = slideshow.find('.slideshow-left');
    scroll_right = slideshow.find('.slideshow-right');
  
    var capture = slideshow.find('.capture');
  
    for (var i = 0; i < slide_count; i++) {
      var el = $('<div></div>');
      el.addClass('slide-selector');
      if (i == 0) el.addClass('active');
      
      (function(i) {
        el.click(function(){ set_slide(i) });
      })(i);
  
      controls_container.append(el);
    }
    
    controls = controls_container.find('.slide-selector');
    
    capture.bind('click', function(e) {
      var offsets = $(this).offset();
      var x = e.pageX - offsets.left;
  
      if (x >= w / 2 && current_slide != slide_count - 1) {
        new_slide = (current_slide + 1) % slide_count;
        set_slide(new_slide);
      }
  
      if (x < w / 2 && current_slide != 0) {
        new_slide = (current_slide + slide_count - 1) % slide_count;
        set_slide(new_slide);
      }
    });

    capture.bind('mousemove', function(e) {
      var offsets = $(this).offset();
      var x = e.pageX - offsets.left;
  
      if (x < w / 2) {
        if (last_mouse_x == null || last_mouse_x >= w / 2) {
          if (current_slide != 0) {
            fade_in(scroll_left)
          }
        }
  
        if (last_mouse_x != null && last_mouse_x >= w / 2) {
          fade_out(scroll_right);
        }
      }
  
      if (x >= w / 2) {
        if (last_mouse_x == null || last_mouse_x < w / 2) {
          if (current_slide != slide_count - 1) {
            fade_in(scroll_right)
          } 
        }
  
        if (last_mouse_x != null && last_mouse_x < w / 2) {
          fade_out(scroll_left);
        }
      }
  
      last_mouse_x = x;
    });
  
    capture.bind('mouseout', function() {
      fade_out(scroll_left);
      fade_out(scroll_right);
      last_mouse_x = null;
    });
    
    slide_timer = setTimeout(advance_slide, slide_interval);
    
  }
  
  var advance_slide = function() {
    if (!playing) return;
    var next_slide = (current_slide + 1) % slide_count;
    change_slide(next_slide);
    slide_timer = setTimeout(advance_slide, slide_interval + animation_length);
  }
  
  function set_slide(new_slide) {
    playing = false;
    clearTimeout(slide_timer);
    change_slide(new_slide);
  }
        
  var change_slide = function(new_slide) {
    if (new_slide == current_slide) return;
    if (animating) {
      queue = new_slide;
      return;
    }
    
    animating = true;
    
    var direction = (new_slide > current_slide) ? 1 : -1;
    
    var current_el = slides.eq(current_slide);
    var new_el = slides.eq(new_slide);
    
    new_el.stop(true, true).css({left: px(w * direction)});
    new_el.animate({left: 0}, animation_length);
    current_el.animate({left: px(-1 * w * direction)}, animation_length);
        
    if (new_el.hasClass('portrait')) {
      slideshow.addClass('portrait');
    }
    else {
      slideshow.removeClass('portrait');
    }
    
    if (new_slide == 0) {
      fade_out(scroll_left);
      last_mouse_x = null;
    }
    
    if (new_slide == slide_count - 1) {
      fade_out(scroll_right);
      last_mouse_x = null;
    }
    
    controls.eq(current_slide).removeClass('active');
    controls.eq(new_slide).addClass('active');
              
    setTimeout(unlock, animation_length);
    
    current_slide = new_slide;
  }

  var unlock = function() {
    animating = false;
    if (queue) {
      change_slide(queue);
      queue = null;
    }
  }

  var fade_in = function(el) {
    el.stop(true, false);
    
    var bp = el.css('backgroundPosition');
    
    if (typeof(bp) == 'undefined') {
      var x = parseInt(el.css('background-position-x'));
    }
    else {
      var offsets = el.css('backgroundPosition').split(' ');
      var x = parseInt(offsets[0]);
    }
    
    var step = (x / 58 * -1);
    
    for (var i = step; i < 10; i++) {
      new_x = i * 58 * -1;
      el.animate({backgroundPosition: new_x + 'px 0'}, 0).delay(30);
    }
  }
  
  var fade_out = function(el) {
    el.stop(true, false);
    
    var bp = el.css('backgroundPosition');
        
    if (typeof(bp) == 'undefined') {
      var x = parseInt(el.css('background-position-x'));
    }
    else {
      var offsets = el.css('backgroundPosition').split(' ');
      var x = parseInt(offsets[0]);
    }

    var step = (x / 58 * -1);
    
    for (var i = step; i >= 0; i--) {
      new_x = i * 58 * -1;
      el.animate({backgroundPosition: new_x + 'px 0'}, 0).delay(30);
    }
  }

  init(container, controls_container, width);      
};

