function Slideshow(numImages, slideshowId, timer, useCaptions)
{
  this.numImages = numImages;
  this.slideshowId = slideshowId;
  this.timer = timer;
  this.timeout = null;
  this.curr = 0;
  this.prev = numImages - 1;
  this.next = 1;
  this.fade = 1000;
  this.busy = false;
  this.width = 656;
  this.paused = false;
  selfRef = this;
  this.images = new Array();
  this.captions = new Array();
  
  if (typeof(useCaptions) == 'undefined') {
    useCaptions = true;
  }
  
  $('#slideshowCounter_' + this.slideshowId).append('<div class="floatWrapper" id="floatWrapper_' + this.slideshowId + '"></div>');
  floatWrapper = $('#floatWrapper_' + this.slideshowId);
  
  var boxes = "";
  
  for (i = 0; i < numImages; i++)
  {
    
    this.images[i] = document.getElementById('slide_' + slideshowId + '_' + i);
    if (useCaptions) {
      this.captions[i] = document.getElementById('caption_' + slideshowId + '_' + i);
    }
    
    if (i == this.curr)
    {
      boxes = boxes + '<div id="goTo_slide_' + this.slideshowId + '_' + i + '" class="goTo current"></div>';
    }
    else
    {
      boxes = boxes + '<div id="goTo_slide_' + this.slideshowId + '_' + i + '" class="goTo"></div>';
    }
  }
  
  boxes = boxes + '<div class="slideshowCounterPrev" id="slideshowCounter_' + this.slideshowId + '_Prev"></div>';
  boxes = '<div class="slideshowCounterNext" id="slideshowCounter_' + this.slideshowId + '_Next"></div>' + boxes;
  $(floatWrapper).append(boxes);
  
  this.prevArrow = $('#slideshowCounter_' + this.slideshowId + '_Prev');
  this.nextArrow = $('#slideshowCounter_' + this.slideshowId + '_Next');
  $(this.prevArrow).animate({ opacity: 0 }, 0);
  $(this.nextArrow).animate({ opacity: 0 }, 0);

  $(this.images[this.curr]).css('zIndex', '2');
  $(this.images[this.next]).hide();
  $(this.images[this.next]).css('zIndex', '3');
  
  this.timeout = setTimeout( function() { selfRef.forward(true) }, this.timer);
  
  // Event handlers     
  $('.goTo').live('click', function()
  {
    ssId = (($(this).attr('id')).split('_'))[2];
    if (ssId == selfRef.slideshowId)
    {         
      id = (($(this).attr('id')).split('_'))[3];
      selfRef.goTo(id);
    }
  })
  
  $('#slideshowCounter_' + this.slideshowId + '_Prev').click(function()
  {
    selfRef.back();
  })
  
  $('#slideshowCounter_' + this.slideshowId + '_Next').click(function()
  {
    selfRef.forward();
  })
  
  $('.slideshow').mouseenter(function()
  {
    selfRef.pause();
    $(selfRef.prevArrow).animate({ opacity: 1 }, 500);
    $(selfRef.nextArrow).animate({ opacity: 1 }, 500);
  })
  
  $('.slideshow').mousemove(function()
  {
    if (!selfRef.paused)
    {
      selfRef.pause();
      $(selfRef.prevArrow).animate({ opacity: 1 }, 500);
      $(selfRef.nextArrow).animate({ opacity: 1 }, 500);
    }
  })
  
  $('.slideshow').mouseleave(function()
  {
    selfRef.unPause();
    $(selfRef.prevArrow).animate({ opacity: 0 }, 500);
    $(selfRef.nextArrow).animate({ opacity: 0 }, 500);
  })
}

Slideshow.prototype.pause = function()
{
  if (!this.paused)
  {
    clearTimeout(this.timeout);
    this.paused = true;
  }
}

Slideshow.prototype.unPause = function()
{
  if (this.paused)
  {
    clearTimeout(this.timeout);
    this.timeout = setTimeout(function() { selfRef.forward(true); }, this.timer);
    this.paused = false;
  }  
}

Slideshow.prototype.forward = function(auto)
{
  this.goTo(this.next, auto);
}

Slideshow.prototype.back = function()
{
  this.goTo(this.prev, false);
}

Slideshow.prototype.goTo = function(slideId, auto)
{
  if (!this.busy && this.next != this.curr)
  {
    this.next = slideId;
    this.showNext(auto);
  }
}

Slideshow.prototype.showNext = function(auto)
{
  if (!this.busy)
  {
    selfRef = this;
    this.busy = true;
    
    // Hide the next image, and put it on the top, then fadeIn
    $(this.images[this.next]).hide();
    $(this.images[this.next]).css('zIndex', '3');
    $(this.images[this.curr]).css('zIndex', '2');
    if (this.prev != this.next)
    {
      $(this.images[this.prev]).css('zIndex', '1');
    }
    
    // Update the counter boxes to reflect any changes
    $('#goTo_slide_' + this.slideshowId + '_' + this.curr).removeClass('goTo current').addClass('goTo');
    $('#goTo_slide_' + this.slideshowId + '_' + this.next).addClass('goTo current');
    $(this.images[this.next]).fadeIn(this.fade, function()
    {
      // Hide the old one when we're done, and put the current one in the middle of the zindex stack
      $(selfRef.images[selfRef.curr]).css('zIndex', '1');
      $(selfRef.images[selfRef.next]).css('zIndex', '2');
      
      // Reset the indexes to point at the new images. Always assume that next is the variable with correct value. Set the others accordingly.
      selfRef.curr = selfRef.next;
      selfRef.next++;
      selfRef.prev = selfRef.curr - 1;
                
      if (selfRef.next >= selfRef.numImages)
      {
        selfRef.next = 0;
      }
      
      if (selfRef.prev < 0)
      {
        selfRef.prev = selfRef.numImages - 1;
      }
      
      // If captions aren't used, trigger next slide here instead.
      if (!selfRef.captions.length) {
        selfRef.busy = false;
        if (auto && !selfRef.paused)
        {
          selfRef.timeout = setTimeout(function() { selfRef.forward(true); }, selfRef.timer);
        }
      }
    });
    
    // Prepare next caption, if any. Slide out old caption, slide in new caption.
    if (this.captions.length) {
      $(this.captions[this.next]).css('left', '400px');
      $(this.captions[this.curr]).animate( { left: '-400px' }, this.fade, function() {} );
      $(this.captions[this.next]).animate( { left: '0px' }, this.fade, function()
      {
        // When the new caption is in, we're not busy anymore, and we can start the timeout for the next slide if we're on autoslide
        selfRef.busy = false;
        if (auto && !selfRef.paused)
        {
          selfRef.timeout = setTimeout(function() { selfRef.forward(true); }, selfRef.timer);
        }
      });
    }
  }
}
