/*
	QUICK START

	A <div id="slideshowPhoto"> is required somewhere.
	It will be populated with a single <img> element for a full-sized photo.

	A <div id="slideshowThumbnails"> is required somewhere.
	It will be populated with a sequence of <img> elements for thumbnails.

	A <div id="slideshowText"> is optional.  It will be populated with a
	heading for the title and some text for the description of the selected
	image.

	Optional previous/next navigation:
	<a href="#" onclick="switchToPreviousPhoto(); return false;">Previous</a>
	<a href="#" onclick="switchToNextPhoto(); return false;">Next</a>

	Things to know when building your stylesheets:
	-	class="selected" will be applied to the currently selected image
		thumbnail.
	-	class="slideshowPhotoTitle" is used for currently displayed
		photo titles.
	-	class="slideshowPhotoSubtitle" is used for currently displayed
		photo subtitles.
	-	class="slideshowPhotoComment" is used for currently displayed
		comments like "New!" or "Only GE has it!".
	-	class="slideshowPhotoDescription" is used for currently displayed
		photo descriptions.
	-	class="slideshowPhotoFootnotes" is used for currently displayed
		footnotes.

	To specify the list of photos: run the following code before calling
	setupSlideshow.  As a linked script called from the <head>, or as a
	script directly included in the <head>, or whatever.

		var slideshowPhotoURLFormat = "images/*.jpg";
		var slideshowThumbnailURLFormat = "images/*_sm.jpg";
		// the * gets replaced with photo IDs.
		
		var slideshowPhotoList = new Array(
			{	photoID: "044229",
				title: "TurboCool&trade; setting", // see note on special
				                                   // characters below.
				description: "Description goes here."
			},
			{	// instead of photoID, you can specify a photoURL and a
				// thumbnailURL for special cases.
				photoURL: "images/044203.jpg",
				thumbnailURL: "images/044203_sm.jpg",
				title: "French door model",
				subtitle: "(available December 2005)",
				description: "Description goes here.",
				footnotes: "Only available with certain models.",
				comment: "Only GE has it!" // optional
			},
			...
		);		
	
	Run this code when your document is finished loading (onload) to set up
	the photo gallery:

		setupSlideshow({
			thumbnailWidth: 60,
			thumbnailHeight: 63,
			photoWidth: 480,
			photoHeight: 500,
			onmouseover: function () { ... } // optional
		});	

	DETAILS

	slideshowPhotoURLFormat and slideshowThumbnailURLFormat are strings that
	specify the location of thumbnail and full-size images where only a
	photo ID is specified.  Place an asterisk in the string, and the first
	asterisk will get replaced with the photo ID to create the image URL.
	URLs are relative to the page, not any of the JavaScript files.

	slideshowPhotoList is an array of objects containing properties that
	provide information about each image.
	
	The following properties are required:
	-	title
	-	description

	The following properties are optional:
	-	subtitle (e.g., "(Available December 2005)")
	-	comment (e.g., "Only GE has it!")
	-	footnotes

	To specify the location of the image, you can do one of two things:
	-	specify a photoID property.
		"images/PHOTOID.jpg" (e.g.) will be used for the photo URL.
		"images/PHOTOID_sm.jpg" (e.g.) will be used for the thumbnail URL.
		See the description of the slideshow*URLFormat variables
		above for more details.
	-	specify photoURL and thumbnailURL properties.
		URLs are relative to the page, not the JavaScript file.
	-	In case of conflict between an explicitly specified URL and a photoID,
		the explicitly specified URL overrides, and any URLs not specified will
		be based on the photoID.

	Got special characters?
	-	Use HTML entities, such as &trade; or &reg;
	-	Remember, do not use &#128; to &#159; since they are not standard.
	
	Added bonus(es):
	-	newline characters (\n) get replaced with an actual HTML line break.
*/

/* Typically set in a separate JavaScript file. */
var slideshowPhotoList;
var slideshowPhotoURLFormat;
var slideshowThumbnailURLFormat;

/* Typically specified when calling setupSlideshow. */
var slideshowPhotoWidth;
var slideshowPhotoHeight;
var slideshowThumbnailWidth;
var slideshowThumbnailHeight;

/* <div id="slideshowPhoto">, etc. */
var slideshowPhotoElement;
var slideshowTextElement;
var slideshowThumbnailsElement;

/* These are containers created once within these elements, then dynamically
   populated as photo switch functions are called. */
var currentPhotoContainer;
var currentTextContainer;
var currentPhotoIndex;

/* Photo switch functions are disabled until setupSlideshow says they're
   ready to go. */
var slideshowIsReady = 0;

/* Utility function used by unescapeEntities.  Concatentates all text nodes,
   ignores everything else, and returns the resulting string. */
function concatTextData (node) {
	if (node.nodeType == 3 /* TEXT_NODE */) {
		return node.data;
	}
	else if (node.hasChildNodes()) {
		var result = "";
		for (var i = 0; i < node.childNodes.length; ++i) {
			result = result + concatTextData(node.childNodes[i]);
		}
		return result;
	}
	else {
		return "";
	}
}

/* Utility function that converts "&trade;" to "\u2122", for example.
   Since we're sticking HTML entities in the title and description strings,
   we need to use the title strings for alt attributes, we're using DOM
   methods to insert images into the slideshows, and those DOM methods
   need unescaped text in order to do the right thing, something like
   this is necessary. */
function unescapeEntities (string) {
	if (!document || !document.createElement) {
		/* fallback */
		return string;
	}
	var span = document.createElement("span");
	span.innerHTML = string;
	return concatTextData(span);
}

/* Utility function to remove all children from a node. */
function removeAllChildren (node) {
	while (node.hasChildNodes())
		node.removeChild(node.childNodes[0]);
}

/* Called by onclick event.  Handler is set up by setupSlideshow. */
function switchThisPhoto () {
	if (!slideshowIsReady) return;
	switchPhoto(slideshowPhotoList[this.photoIndex]);
	return false; /* browser ignores */
}

/* Called by "previous" navigation button. */
function switchToPreviousPhoto () {
	if (!slideshowIsReady) return;
	var newIndex = currentPhotoIndex - 1;
	if (newIndex < 0) newIndex = slideshowPhotoList.length - 1;
	switchPhoto(slideshowPhotoList[newIndex]);
}

/* Called by "next" navigation button. */
function switchToNextPhoto () {
	if (!slideshowIsReady) return;
	var newIndex = (currentPhotoIndex + 1) % slideshowPhotoList.length;
	switchPhoto(slideshowPhotoList[newIndex]);
}

function switchPhoto (photo) {
	if (!slideshowIsReady) return;
	currentPhotoIndex = photo.photoIndex;
	
	/* Switch the selected thumbnail. */
	
	for (var i = 0; i < slideshowPhotoList.length; ++i) {
		if (i == currentPhotoIndex) {
			slideshowPhotoList[i].thumbnailElement.className = "selected";
		} else {
			slideshowPhotoList[i].thumbnailElement.className = "";
		}
	}
	
	/* Make sure the current...Container elements are set up. */
	
	if (!currentPhotoContainer) {
		currentPhotoContainer = document.createElement("div");
		slideshowPhotoElement.appendChild(currentPhotoContainer);
	}
	if (slideshowTextElement) {
		if (!currentTextContainer) {
			currentTextContainer = document.createElement("div");
			slideshowTextElement.appendChild(currentTextContainer);
		}
	}

	/* Populate the current...Container elements. */
	
	if (slideshowTextElement) {
		removeAllChildren(currentTextContainer);
		if (photo.title != null) {
			var h2 = document.createElement("h2");
			h2.className = "slideshowPhotoTitle";
			h2.innerHTML = photo.escapedTitle;
			currentTextContainer.appendChild(h2);
		}
		if (photo.subtitle != null) {
			var div = document.createElement("div");
			div.className = "slideshowPhotoSubtitle";
			div.innerHTML = photo.subtitle;
			currentTextContainer.appendChild(div);
		}
		if (photo.comment != null) {
			var div = document.createElement("div");
			div.className = "slideshowPhotoComment";
			div.innerHTML = photo.comment;
			currentTextContainer.appendChild(div);
		}
		if (photo.description != null) {
			var div = document.createElement("div");
			div.className = "slideshowPhotoDescription";
			div.innerHTML = photo.description.replace(/\n/g, "<br />\n");
			currentTextContainer.appendChild(div);
		}
		if (photo.footnotes != null) {
			var div = document.createElement("div");
			div.className = "slideshowPhotoFootnotes";
			div.innerHTML = photo.footnotes.replace(/\n/g, "<br />\n");
			currentTextContainer.appendChild(div);
		}
	}

	var image = document.createElement("img");
	image.width = slideshowPhotoWidth;
	image.height = slideshowPhotoHeight;
	image.src = photo.photoURL;
	image.alt = photo.unescapedTitle;
	image.title = photo.unescapedTitle;
	removeAllChildren(currentPhotoContainer);
	currentPhotoContainer.appendChild(image);
	
	/* We may have to scroll the thumbnail container so that the selected
	   thumbnail is visible. */
	
	var thumbnail = photo.thumbnailElement;
	if (thumbnail.offsetTop < slideshowThumbnailsElement.scrollTop) {
		slideshowThumbnailsElement.scrollTop = thumbnail.offsetTop;
	}
	else if ((thumbnail.offsetTop + thumbnail.offsetHeight) >
	         (slideshowThumbnailsElement.scrollTop +
	          slideshowThumbnailsElement.offsetHeight)) {
		slideshowThumbnailsElement.scrollTop = (
			thumbnail.offsetTop + thumbnail.offsetHeight
			- slideshowThumbnailsElement.offsetHeight
		);
	}
}

function setupSlideshow (options) {
	slideshowIsReady = 0;
	
	/* required */
	slideshowPhotoElement      = document.getElementById("slideshowPhoto");
	slideshowThumbnailsElement = document.getElementById("slideshowThumbnails");
	
	/* optional */
	slideshowTextElement       = document.getElementById("slideshowText");

	if (options.photoWidth != null)	
		slideshowPhotoWidth = options.photoWidth;
	if (options.photoHeight != null)	
		slideshowPhotoHeight = options.photoHeight;
	if (options.thumbnailWidth != null)	
		slideshowThumbnailWidth = options.thumbnailWidth;
	if (options.thumbnailHeight != null)	
		slideshowThumbnailHeight = options.thumbnailHeight;
	
	for (var i = 0; i < slideshowPhotoList.length; ++i) {
		var photo = slideshowPhotoList[i];
		if (photo.photoURL == null) {
			photo.photoURL = slideshowPhotoURLFormat.replace(/\*/, photo.photoID);
		}
		if (photo.thumbnailURL == null) {
			photo.thumbnailURL = slideshowThumbnailURLFormat.replace(/\*/, photo.photoID);
		}
		
		photo.escapedTitle = photo.title;
		photo.unescapedTitle = unescapeEntities(photo.title);

		var anchor = document.createElement("a");
		var image = document.createElement("img");
		image.src = photo.thumbnailURL;
		image.width = slideshowThumbnailWidth;
		image.height = slideshowThumbnailHeight;
		image.alt = photo.unescapedTitle;
		image.title = photo.unescapedTitle;
		anchor.appendChild(image);
		slideshowThumbnailsElement.appendChild(anchor);
		photo.thumbnailElement = image;
		
		/* Since these are accessible from functions called due to
		   events, give them access to the appropriate index in
		   slideshowPhotoList. */
		photo.photoIndex = i; /* switchPhoto() is called with this. */
		anchor.photoIndex = i; /* onclick is called on this object. */
		
		anchor.onclick = switchThisPhoto;
		if (options.onmouseover) {
			anchor.onmouseover = options.onmouseover;
		}
		anchor.href = "#"; /* required in MSIE for a:hover to work. */
	}
	slideshowIsReady = 1; /* enable the photo switch functions. */

	/* Which image gets shown upon page load?  If the query string's startat
	   parameter is an integer between 0 and (number of photos) - 1, it
	   determines which photo is shown first.  Otherwise, the first photo
	   is shown first. */
	
	var initialIndex = 0;
	var match = document.location.search.match(/[\?\&]startat=(\d+)/);
	if (match) {
		var i = match[1];
		if (i >= 0 && i < slideshowPhotoList.length) {
			initialIndex = i;
		}
	}
	switchPhoto(slideshowPhotoList[initialIndex]);
}

