/*
 * Slideshow Script
 * Copyright Hugo Hudson, 2006
 *
 * Usage:
 *
 * Include this file in your page by placing the following code in the page
 * header (between the <head> and </head> tags):
 * <script type="text/javascript" src="slideshow.js"></script>
 *
 * Then within the source of your page, place a divider called 'SS_slideshow'
 * and within that a single image, as follows:
 * <div id='SS_slideshow'>
 *     <img src="first-image.jpg" alt='picture of an image' />
 * </div>
 *
 * You may optionally add a 'SS_controls' divider, if you want to allow people
 * to be able to start, stop, skip forward and skip backward with the
 * slideshow.  Like this:
 * <div id='SS_slideshow'>
 *     <img src="first-image.jpg" alt='picture of an image' />
 *     <div id='SS_controls'><!-- --></div>
 * </div>
 *
 * Now you should add some javascript (probably in the head of the document) to
 * make an array containing all of the images for the slideshow (INCLUDING the
 * first) in the order in which they should appear, along with their 'alt'
 * attributes, as follows:
 * <script type="text/javascript">
 * var SS_imageNames = [
 *     ['images/first-image.jpg', 'picture of an image'],
 *     ['images/second-image.jpg', 'another picture of some imagey thing'],
 *     ['images/third-image.jpg', 'something else in image form']
 * ];
 * </script>
 *
 * Finally you may optionally decide to style both the slideshow container and
 * the controls container that will be on the page, as follows:
 * <style type="text/css">
 * div#SS_slideshow {
 *     // slideshow styling
 * }
 * div#SS_slideshow div#SS_controls {
 *     // controls styling
 * }
 * div#SS_slideshow div#SS_controls span.SS_button {
 *     // buttons for the slideshow styling
 * }
 *
 * The script will cycle through all of the images named in the SS_imageNames
 * array giving a specified delay to each image.  It will also provide buttons
 * below the slideshow to stop, start, and skip forward or back, if you have
 * provided a controls divider, by inserting the text nodes appropriately.
 */

// run the setup method after script load
addEvent(window, 'load', SS_setup);
// the timeout for the slider - how often it should change images in ms
var SS_timeout = 2800;
// the slideshow divider
var SS_slideshow = 0;
// the index of the currently visible image in the slideshow
var SS_current = 0;
// the img element inside the slideshow
var SS_theImage = 0;
// the cached array of images, for preloading purposes
var SS_cachedImages = new Array();
// the number of images in the cache that have been fully loaded
var SS_cacheIndex = 0;
// the progress divider, which contains our 'loading' message
var SS_progress = 0;
// the text node telling us how many images we have loaded
var SS_loadingText = 0;
// the image name divider and text to tell us which image we are seeing
var SS_imageNameDiv = 0;
var SS_imageNameText = 0;
// tells us if the slideshow is operative - if all images are loaded
var SS_operative = false;
// the timer, being used to regularly call the SS_next() method
var SS_timer = 0;
// should we fade between images (true) or change immediately (false)
var SS_fade = false;
// the fade timer, being used to regularly call the SS_doFade() method
var SS_fadeTimer = 0;
// the direction of fade - first we fade out (true) then we fade in (false)
var SS_fadeOut = true;
// the amount of fade - first we fade out (1 to 0) then we fade in (0 to 1)
var SS_fadeAmount = 1;
// the length of time the entire fade should take in milliseconds
var SS_fadeDuration = 1000;
// the number of frames per second occupied by the fade
var SS_fadeFPS = 25;
// if true, we automatically start the slideshow
var SS_autostart = true;
// tells us if the slideshow is running
var SS_running = false;
// which type of opacity settings we should use
var SS_opacityType = 0;
// if true then we fade between the two images, if false we blend
var SS_crossfade = true;

function SS_setup() {
  // check that we have some valid slideshow image names
  if (typeof SS_imageNames == "undefined") return;
  // find the slideshow divider.  check that it does exist
  SS_slideshow = byid('SS_slideshow');
  if (!SS_slideshow) return;
  // set theImage variable to the image contained in the slideshow div.
  // check that there is exactly one
  var innerImages = SS_slideshow.getElementsByTagName('img');
  if (innerImages.length != 1) return;
  SS_theImage = innerImages[0];
  // find the slideshow controls, if it exists
  var controls = byid('SS_controls');
  if (controls) {
    // inside the control panel, add the buttons
    var texts = new Array('prev','stop','start','next');
    var functions = new Array(SS_prev, SS_stop, SS_start, SS_next);
    for (var i=0; i<texts.length; i++) {
      var sp = document.createElement('span');
      sp.className = 'SS_button';
      sp.appendChild(document.createTextNode(texts[i]));
      sp.onclick = functions[i];
      controls.appendChild(sp);
    }
  }
  // find the slideshow progress indicator, if it exists
  SS_progress = byid('SS_progress');
  if (SS_progress) {
    SS_loadingText = document.createTextNode('loading...');
    SS_progress.appendChild(SS_loadingText);
    SS_progress.style.display = 'block';
  }
  // find the image name text, if it exists
  SS_imageNameDiv = byid('SS_imageNameDiv');
  if (SS_imageNameDiv) {
    SS_imageNameText = document.createTextNode('image name: ');
    SS_imageNameDiv.appendChild(SS_imageNameText);
    SS_imageNameDiv.style.display = 'block';
  }
  // if we are using fade, detect the type of opacity change
  if (SS_fade) {
    SS_opacityType = SS_detectOpacity();
    if (SS_opacityType == 'unknown') SS_fade = false;
  }
  // begin preloading images
  SS_preloadNext();
}

function SS_preloadNext() {
  // if we've cached all the images, then return, after hiding the loading
  // display
  if (SS_cacheIndex >= SS_imageNames.length) 
  {
    // we're done with the loading progress
    if (SS_loadingText) SS_loadingText.nodeValue = 'done';
    if (SS_progress) SS_progress.style.display = 'none';
    // we are now operative
    SS_operative = true;
    // allow the user to click on our main image to advance slides, style
    // the image appropriately with a cursor too
    SS_theImage.onclick = SS_next;
    SS_theImage.style.cursor = 'pointer';
    // start the slideshow if required
    if (SS_autostart) SS_start();
    return;
  }
  // update the loading text to show which image we're working on
  if (SS_loadingText) {
    SS_loadingText.nodeValue = 'loading '+(SS_cacheIndex+1)+' of '+
      SS_imageNames.length+'...';
  }
  // construct a new cache image
  var cache = new Image();
  // when this image loads, have it callback to this method.  unfortunately
  // we need the setTimout() method, since internet explorer has some kind of
  // stack overflow problem.
  cache.onload = function() {
    setTimeout('SS_preloadNext()',0);
  };
  // change the cache source
  cache.src = SS_imageNames[SS_cacheIndex][0];
  // and store the cached image
  SS_cachedImages[SS_cacheIndex++] = cache;
}

function SS_start() {
  if (!SS_operative) return;
  if (SS_running) return;
  if (SS_timer) clearTimeout(SS_timer);
  SS_timer = setTimeout('SS_next()', SS_timeout);
  SS_running = true;
}

function SS_stop() {
  if (!SS_operative) return;
  if (!SS_running) return;
  if (SS_timer) clearTimeout(SS_timer);
  SS_timer = 0;
  SS_running = false;
}

function SS_next() {
  if (!SS_operative) return;
  if (SS_running) SS_restart();
  if (SS_fade) SS_fadeImageChange(1);
  else SS_snapImageChange(1);
}

function SS_prev() {
  if (!SS_operative) return;
  if (SS_running) SS_restart();
  if (SS_fade) SS_fadeImageChange(-1);
  else SS_snapImageChange(-1);
}

function SS_restart() {
  SS_stop();
  SS_start();
}

function SS_snapImageChange(direction) {
  SS_current += direction;
  if (SS_current >= SS_imageNames.length) SS_current = 0;
  if (SS_current < 0) SS_current = SS_imageNames.length-1;
  SS_theImage.src = SS_imageNames[SS_current][0];
  SS_theImage.alt = SS_imageNames[SS_current][1];
  if (SS_imageNameText) {
    SS_imageNameText.nodeValue = 'image name: '+SS_imageNames[SS_current][0];
  }
}

function SS_fadeImageChange(direction) {
  if (SS_crossfade) {
    SS_slideshow.style.background = 'url('+SS_theImage.src+')';
    SS_fadeOut = false;
    SS_fadeAmount = 0;
    SS_changeOpacity();
    var interval = Math.round(1000 / SS_fadeFPS);
    var amount = interval / SS_fadeDuration;
    //SS_snapImageChange(direction);
    setTimeout('SS_snapImageChange('+direction+')',0);
  } else {
    SS_fadeOut = true;
    SS_fadeAmount = 1;
    var interval = Math.round(1000 / SS_fadeFPS);
    var amount = 2 * interval / SS_fadeDuration;
  }
  if (SS_fadeTimer) clearInterval(SS_fadeTimer);
  SS_fadeTimer = setInterval(
    'SS_doFade('+amount+','+direction+')',
    interval
  );
}

function SS_doFade(amount,direction) {
  if (SS_fadeOut && SS_fadeAmount <= 0) {
    SS_snapImageChange(direction);
    SS_fadeOut = false;
  } else if (SS_fadeOut) {
    SS_fadeAmount -= amount;
    if (SS_fadeAmount <= 0) SS_fadeAmount = 0;
    SS_changeOpacity();
  } else {
    SS_fadeAmount += amount;
    if (SS_fadeAmount >= 1) {
      SS_fadeOut = true;
      SS_fadeAmount = 1;//TODO mozilla hack necessary? 0.9999999;
      if (SS_fadeTimer) {
        clearInterval(SS_fadeTimer);
        SS_fadeTimer = 0;
      }
    }
    SS_changeOpacity();
  }
}

function SS_detectOpacity() {
  var img = SS_theImage;
  if (typeof img.style.MozOpacity != 'undefined') return 'moz';
  if (typeof img.style.KhtmlOpacity != 'undefined') return 'khtml';
  if (typeof img.filters == 'object' && img.filters.length > 0 &&
    typeof img.filters.alpha == 'object' &&
    typeof img.filters.alpha.opacity == 'number') return 'ie';
  if (typeof img.style.opacity != 'undefined') return 'w3c';
  return 'unknown';
}

function SS_changeOpacity(value) {
  if (SS_opacityType == 'ie') {
    SS_theImage.filters.alpha.opacity = Math.round(SS_fadeAmount*100);
  } else if (SS_opacityType == 'moz') {
    SS_theImage.style.MozOpacity = SS_fadeAmount;
  } else if (SS_opacityType == 'wc3') {
    SS_theImage.style.opacity = SS_fadeAmount;
  } else if (SS_opacityType == 'khtml') {
    SS_theImage.style.KhtmlOpacity = SS_fadeAmount;
  }
}
