// This is a simple slideshow gallery. You need to pass two arguments to the 
// startup function, the image holder to show the slideshow in and an array
// containing paths to the photos.

function Slideshow(photoArray, imageHolder) {

  // Initialize internal state.
  this.photoArray = photoArray;
  this.imageHolder = imageHolder;
  
  this.opacity = 0; // This is the opacity of the currently showing photo, it varies between 0 and 100. 
  this.fadeSpeed = 10; // The time in millis to wait between each fade step.
  this.fadeResolution = 2; // Resolution of fade, best is 1, worst is 100.
  this.stallTime = 3000; // Time to stall at each photo.
  this.retryDelay = 500;
  this.maxRetries = 5;
  
  this.nPhotos = this.photoArray.length;
  this.loadedPhotos = new Array(); // This array holds the loaded photos.
  this.image = new Image();
  this.currentPhoto = 0; // Currently showing photo.
  this.retries = 0;

  // Create event handlers for this image object.
  this.image.onload = Slideshow.prototype.imageLoaded;
  this.image.onerror = Slideshow.prototype.imageError;
  this.image.onabort = Slideshow.prototype.imageError;
    
  this.setOpacity();
  
  // Spawn the process preloading the photos.
  this.preload();
  this.nextSlide();
}


// This functions preloads one photo, depeding on the event invoked on this photo
// the function is respawned or ended until all photos has been preloaded.
Slideshow.prototype.preload = function () {
  
  // Create new image object.
  this.image.oSlideshow = this; // Reference back to this.
  
  // Have all photos been loaded?
  if (this.photoArray.length != 0) { // No
    // Load the next one and continue
    this.image.src = this.photoArray.shift();
    document.getElementById('preloadStatus').innerHTML=" // Preloading photo " + (this.loadedPhotos.length + 1) + " of " + (this.photoArray.length + this.loadedPhotos.length + 1);
    // Event will be invoked here for the image object.
  
  } else {
    // Yes all images have been preloaded. The preloading phase stops.
    document.getElementById('preloadStatus').innerHTML=" // Preloading... Done!";
    var t=setTimeout("document.getElementById('preloadStatus').innerHTML=''",5000);
  }
  
}

Slideshow.prototype.imageLoaded = function () {
  // Image loaded correctly, put it into completed photos array.
  this.oSlideshow.loadedPhotos.push(this.src);
  
  // Continue the preload process.
  this.oSlideshow.preload();
}

Slideshow.prototype.imageError = function () {
  // Error occured while loading image. Put it back at the end of photoArray
  // and continue preloading. This image will be preloaded later.
  this.oSlideshow.photoArray.push(this.src);

  // Continue the preload process.
  this.oSlideshow.preload();  
}




// When the slideshow has startred, this function is called recursively for the rest of the session.
Slideshow.prototype.nextSlide = function () {
  //this.slide.oSlideshow = this; // Reference back to this.

  // Have we reached the last photo in the array? In that case, restart.
  if (this.currentPhoto >= this.nPhotos) { // Yes
    this.currentPhoto = 0;
  }
  
  // Has next photo loaded yet?
  if (this.currentPhoto >= this.loadedPhotos.length) { // No it has not.
    this.retries++;
    if (this.retries >= this.maxRetries) {
      this.currentPhoto = 0;
    }
    
    var self = this;
    // Wait a while and try again.
    var t = setTimeout(function () { self.nextSlide(); }, this.retryDelay);
  
  } else { // Yes it has.
    this.retries = 0;
    this.imageHolder.src=this.loadedPhotos[this.currentPhoto++];

    // Fade in this photo.
    this.fIn();
  }
}


Slideshow.prototype.fIn = function () {
  this.setOpacity(); // Set new opacity
  this.opacity = this.opacity + this.fadeResolution; // Increase opacity
  
  var self = this; // Reference to own object, used to bypass the weird behaivour of setTimeout.

  // Have we reached max opacity?
  if (this.opacity < 100) { // No
    // Wait and then continue fade in.
    t=setTimeout(function () { self.fIn(); },this.fadeSpeed);    
  
  } else { // Yes
    // Show this photo and then fade out.
    t=setTimeout(function () { self.fOut(); },this.stallTime);
  }
}


Slideshow.prototype.fOut = function () {
  this.setOpacity(); // Set new opacity
  this.opacity = this.opacity - this.fadeResolution; // Decrease opacity
  
  var self = this; // Reference to own object, used to bypass the weird behaivour of setTimeout.
  
  // Have we reached total invisibility?
  if (this.opacity > 0) { // No
    // Wait and then continue fade out.
    t=setTimeout(function () { self.fOut(); },this.fadeSpeed);
  
  } else { // Yes
    // Go to next slide.
    this.nextSlide();
  }
  
}

Slideshow.prototype.setOpacity = function () {
	var opacity = (this.opacity == 100)?99.999:this.opacity;
	
	// IE/Win
	this.imageHolder.style.filter = "alpha(opacity="+opacity+")";
	
	// Safari<1.2, Konqueror
	this.imageHolder.style.KHTMLOpacity = opacity/100;
	
	// Older Mozilla and Firefox
	this.imageHolder.style.MozOpacity = opacity/100;
	
	// Safari 1.2, newer Firefox and Mozilla, CSS3
	this.imageHolder.style.opacity = opacity/100;
}
