var _images = new Array();
function preload(img) {
	if (img == "") return;
	
	var i = _images.length;
	_images[i] = new Image();
	_images[i].src = img;
}

// class Hilite

function Hilite(off_img, on_img, name /*opt arg*/, props /*opt arg, ="" */) {
	var myname, myprops;
	
	if (name == null) {
		myname = "__img_" + Hilite.img_id++;
	} else {
		myname = name;
	}
	
	if (props == null) {
		myprops = "";
	} else {
		myprops = props;
	}

	this.off_img = off_img;
	this.on_img = on_img;
	this.state = Hilite.OFF;
	this.locked = false;
	this.name = myname;
	
	var i = Hilite.images.length;
	Hilite.images[i] = this;
	
	preload(off_img);
	preload(on_img);
	
	myprops = 'onmouseover="Hilite.images[' + i + '].on()" onmouseout="Hilite.images[' + i + '].off()"' + myprops;
	document.write('<img id="' + myname + '" src="' + off_img + '" ' + myprops + ' />');
}

Hilite.OFF = false;
Hilite.ON = true;
Hilite.img_id = 0;
Hilite.images = new Array();

Hilite.prototype.setState = function (newState) {
	if (this.locked) return;
	
	if (newState == Hilite.OFF) {
		document.getElementById(this.name).src = this.off_img;
	} else {
		document.getElementById(this.name).src = this.on_img;
	}
	this.state = newState;
}

Hilite.prototype.on = function () {
	this.setState(Hilite.ON);
}

Hilite.prototype.off = function () {
	this.setState(Hilite.OFF);
}

Hilite.prototype.flip = function () {
	this.setState(!this.state);
}

Hilite.prototype.setLock = function (lock, state) {
	if (arguments.length > 1) {
		this.locked = false;
		this.setState(state);
	}
	this.locked = lock;
}	

//class Slideshow

function ssAnim(ss) {
	var myImg = document.getElementById(ss.ssid);
	if (ss.bRand) {
		ss.idx = Math.floor(Math.random() * ss.myPix.length);
	} else {
		ss.idx = (ss.idx + 1) % ss.myPix.length;
	}

	var ssIsIE = document.all != null; //myImg.filters["blendTrans"] != null;
	ssIsIE && myImg.filters["blendTrans"].apply();
	myImg.src = ss.myPix[ss.idx].src;	
	ssIsIE && myImg.filters["blendTrans"].play();
}

function SlideShow(arefPix, bControls, bRand, sImgAttrs, defaultDelay) {
	var ssidx = SlideShow.objs.length;
	SlideShow.objs[ssidx] = this;
	this.ssIdx = ssidx;
	
	this.myPix = new Array(arefPix.length);
	for (var i = 0; i < arefPix.length; i++) 
	{
		this.myPix[i] = new Image();
		this.myPix[i].src = arefPix[i];
	}

	this.bControls = bControls != null ? bControls : false;
	this.bRand = bRand != null ? bRand : false;
	this.idx = this.bRand ? Math.floor(Math.random() * this.myPix.length) : 0;
	this.ssid = "slideshow"+(SlideShow.ssid++);
	sImgAttrs = sImgAttrs != null ? sImgAttrs : "";
	

	document.write('<img id="'+this.ssid+'" src="'+this.myPix[this.idx].src+'" style="filter: blendTrans(duration=3)" '+sImgAttrs+'>')

	this.defaultDelay = defaultDelay != null ? defaultDelay : 5000;
	this.delay = this.defaultDelay;
	var foo = this;
	this.timeoutID = setInterval("ssAnim(SlideShow.objs["+ssidx+"])", this.delay)
}

SlideShow.ssid = 0;
SlideShow.objs = new Array();

// class Overlay

function Overlay(ovlay, sImgAttrs, size) {
	if (sImgAttrs != null) {
		this.imgAttrs = sImgAttrs;
	} else {
		this.imgAttrs = "";
	}
	
	var h, w;
	if (size == null) {
		this.h = this.w = 0;
	} else {
		this.w = size[0];
		this.h = size[1];
	}
	
	if (typeof ovlay == "string") {
		this.ovlay = document.getElementById(ovlay);
		if (this.ovlay == null) {
			this.ovlay = new Image();
			this.ovlay.src = ovlay;
		}
	} else {
		this.ovlay = ovlay;
	}
	
	this.openned = false;
	this.closed = false;
	this.locked = false;
	
	this.idno = Overlay.id++;
	this.id = '__overlay_' + this.idno;
	this.imgid = '__overlayimg_' + this.idno;
	Overlay.ary[this.idno] = this;
}
Overlay.id = 0;
Overlay.depth = 0;
Overlay.ary = new Array();


Overlay.prototype.begin = function () {
	if (this.openned) {
		document.write('<!-- Overlay ' + this.id + ' has already begun -->');
		return;
	}
	this.openned = true;
	Overlay.depth++;
	
	document.write('<span id="' + this.id + '" onmouseover="Overlay.ary['+this.idno+'].show()" onmouseout="Overlay.ary['+this.idno+'].hide()">');
	document.write('<img id="' + this.imgid + '" src="' + this.ovlay.src + '" style="position:absolute; visibility:hidden; z-index:' + Overlay.depth + '0" ' + this.imgAttrs + ' >');
}

Overlay.prototype.end = function () {
	if (!this.openned) {
		document.write('<!-- Overlay ' + this.id + ' has not yet begun -->');
		return;
	}
	if (this.closed) {
		document.write('<!-- Overlay ' + this.id + ' has already closed -->');
		return;
	}
	this.closed = true;
	Overlay.depth--;
	document.write('</span>');
}

Overlay.prototype.show = function () {
	if (this.locked) return;
	
	var img = document.getElementById(this.imgid);
	var istyle = img.style;
	
	istyle.visibility = "visible";
}

Overlay.prototype.hide = function () {
	if (this.locked) return;
	
	var img = document.getElementById(this.imgid);
	var istyle = img.style;
	
	istyle.visibility = "hidden";
}

Overlay.prototype.lock = function (lock, show) {
	this.locked = false;
	if (lock) {
		if (show) {
			this.show();
		} else {
			this.hide();
		}
	}
	this.locked = lock;
}

// class ImageMenu

/*	ImageMenu creates a scrolling image thumbnail "ribbon".  It can work horizontally or vertically.  When the user mouses over one end 
of the ribbon, it scrolls in that direction.  The farther towards the end, the faster the scrolling.  The user can click on a thumbnail,
which throws a corresponding full sized image into the main display.  The user can click on the main image, which loads a new ribbon of
images from a subgallery a link up.  Each image can have two captions; the first is displayed over the image and the second under it.  
The first caption is also displayed under the thumbnail in the ribbon.

ImageMenu runs entirely in Javascript on the user's browser.  It depends on the included class, a set of class variables for customizing
the display, and a set of CSS entries for customizing the layout.  Although it is possible to have multiple ImageMenu objects on a page, 
only one set of customizations can be made; all will have the same layout.

Class Variables
The following class variables have default values, but if they are set before creating a new ImageMenu object, it will reflect the changes.
ImageMenu.topMessage			-	provides a link to the top level image gallery
ImageMenu.upMessage				-	provides a link to the next level up image gallery
ImageMenu.leftMessage			-	an item displayed under the left side/to the right of the top of the ribbon when it can scroll left/up
ImageMenu.rightMessage			-	an item displayed under the right side/to the right of the bottom of the ribbon
ImageMenu.directions			-	html to display under large image for user instructions
ImageMenu.giveDirections		-	How to display directions: 0 - never, 1 - until first user interaction, 2 - always

Call and Arguments
var im = new ImageMenu(bigImgDivID, maxVis, horiz, imgSize, images);

bigImgDivID	-	the id attr for a div that will hold the main display image
maxVis		-	an integer number of thumbnails to display in the ribbon
horiz		-	true => horizontal ribbon, false => vertical ribbon
imgSize		-	an array, [ w, h ], that gives the width and height of the thumbnail images
images		-	the image gallery data structure:
	[
		[ img, tn, caption1, caption2, {subgallery} ],
		...
	]
	img			-	a string that gives the URL of the full sized image
	tn			-	a string that gives the URL of the corresponding thumbnail image
	caption1	-	a string that gives the caption displayed under the thumbnail and above the full sized image
	caption2	-	a string that gives the caption displayed under the full sized image
	subgallery	-	an optional data structure just like the images structure, that supplies a new gallery to be displayed when the full 
					sized image is clicked.  May be nested as deeply as required.

CSS Styles
.ImageMenu					-	a block that describes the area of the ribbon.  The "short side" length must be specified in px
.ImageMenu-nav				-	how the top and up navigation links are displayed
.ImageMenu-img-caption1		-	how the caption1 is displayed over the full sized image
.ImageMenu-img-caption2		-	how the caption2 is displayed under the full sized image
.ImageMenu-tn-block			-	a block that describes the area of a single thumbnail, including caption.  Width and height must be given in px
.ImageMenu-tn-pic			-	a block that describes the area of the thumbnail image
.ImageMenu-tn-caption		-	how the caption1 is displayed under the thumbnail image
.ImageMenu-{left|right}-block	controls display of ImageMenu.{left|right}Message
.ImageMenu-directions		-	how the user instructions are displayed under the main image
*/

function ImageMenu(bigImgDivID, maxVis, horiz, imgSize /*[w, h]*/, images /*[[img, tn, caption1, caption2{, subgallery}]...]*/) {
	var out = '';
	this.id = ImageMenu.id++;
	ImageMenu.objs[this.id] = this;
	
	this.div_id = "ImageMenu_"+this.id;
	this.bigImgObj = document.getElementById(bigImgDivID);
	this.maxVis = maxVis;
	this.hw = horiz ? 0 : 1;
	this.dir = horiz ? "width" : "height";
	this.imgSize = imgSize;
	this.images = images;
	this.firstAction = true;
	this.gallery = new Array();

	out += "<div id = '"+this.div_id+"' class='ImageMenu' onMouseOver='ImageMenu.objs["+this.id+"].mouseOver(event)' onMouseOut='ImageMenu.objs["+this.id+"].mouseOut(event)' onMouseMove='ImageMenu.objs["+this.id+"].mouseMove(event)' style='top:0px;left:0px;"+this.dir+":"+this.getWidth()+"px'>\n";
	for (var i=0; i <= this.maxVis; i++) { // note - create maxVis+1 <img>s
		out += "\t<div id='"+this.div_id+"_"+i+"d' class='ImageMenu-tn-block' style='position:absolute;top:0px;left:0px;overflow:hidden;'><img id='"+this.div_id+"_"+i+"' class='ImageMenu-tn-pic'><div id='"+this.div_id+"_"+i+"t' class='ImageMenu-tn-caption'></div></div>\n";
	}

	var t = 0, l = 0, s;
	if (horiz) {
		t += 40 + this.imgSize[1];
		s = "top:"+t+"px;right:0px";
	} else {
		l += 10 + this.imgSize[0];
		s = "bottom:0px;left:"+l+"px";
	}
	out += "<div id='"+this.div_id+"left' class='ImageMenu-left-block' style='position:absolute;top:"+t+"px;left:"+l+"px'></div>\n";
	out += "<div id='"+this.div_id+"right' class='ImageMenu-right-block' style='position:absolute;"+s+"'></div></div>\n";
	document.write(out); out = '';
	
	this.setGallery();
}
ImageMenu.prototype.interval = 8;
ImageMenu.id = 0;
ImageMenu.objs = new Array();
ImageMenu.breadcrumbSeparator = '&nbsp;&gt;&nbsp;';
ImageMenu.topMessage = 'back';
ImageMenu.upMessage = 'back';
ImageMenu.leftMessage = '&lt;&mdash;';
ImageMenu.rightMessage = '&mdash;&gt;';
ImageMenu.directions = 'Click on a small image to view a larger image; click on the large image to see more detailed images.';
ImageMenu.giveDirections = 1;	// 0 - never, 1 - until first user interaction, 2 - always

ImageMenu.prototype.breadcrumb = function(showFirst, showRest) {
	var ret = '';
	var f = true;
	var images = this.images;
	for (var i=0; i < this.gallery.length; i++) {
		if ((f && showFirst) || (!f && showRest) || (!showFirst && !showRest && i == this.gallery.length-1)) {
			if (ret != '') ret += this.breadcrumbSeparator;
			ret += images[this.gallery[i]][2];
		}
		f = false;
	}
	return ret;
}

ImageMenu.prototype.setGallery = function() {
	var galImgs = this.images;
	for (var i=0; i < this.gallery.length; i++) {
		galImgs = galImgs[this.gallery[i]][4];
	}

	this.img = new Array();
	for (var i=0; i < galImgs.length; i++) {
		var tmp1 = new Image();
		tmp1.src = galImgs[i][0];
		var tmp2 = new Image();
		tmp2.src = galImgs[i][1];
		this.img[this.img.length] = new Array(tmp1, tmp2, galImgs[i][2], galImgs[i][3], galImgs[i][4]);
	}
	this.index = 0;
	this.offset = 0;
	this.scrollable = (this.img.length > this.maxVis);
	this.scrollspeed = 0;
	this.scrolltimeout = 0;
	
	this.setBigImg(0);
	this.display();
}

ImageMenu.setSubGallery = function(im, idx, mod) {
	im = ImageMenu.objs[im];
	if (mod != null) {
		switch(mod) {
		case 0: // top
			im.gallery = new Array();
			break;
		case -1: // move up one
			im.gallery.length = im.gallery.length-1;
			break;
		}
	} else {
		im.gallery[im.gallery.length] = idx;
	}
	im.firstAction = false;
	im.setGallery();
}

ImageMenu.prototype.setBigImg = function(idx) {
	var out = '';
	var title = '';
	if (this.gallery.length) { //in a subgallery, set subgallery title
		out += "<div class='ImageMenu-nav'><span onClick='ImageMenu.setSubGallery("+this.id+","+idx+",0)'>"+ImageMenu.topMessage+"</span>";
		if (this.gallery.length > 1) {
			out += "&nbsp;&nbsp;<span onClick='ImageMenu.setSubGallery("+this.id+","+idx+",-1)'>"+ImageMenu.upMessage+"</span>";
		}
		out += "</div>\n";

		title = this.breadcrumb(false, false);
		out += "<div class='ImageMenu-breadcrumb'>"+title+"</div>\n";
	}
	out += "<div class='ImageMenu-img-caption1'>"+this.img[idx][2]+"</div><br />\n<img src='"+this.img[idx][0].src+"'";
	if (this.img[idx][4]) { // subgallery available
		out += " onClick='ImageMenu.setSubGallery("+this.id+","+idx+")' style='cursor:pointer'";
	}
	out += "><br />\n<div class='ImageMenu-img-caption2'>"+this.img[idx][3]+"</div>\n";
	if (ImageMenu.giveDirections == 2 || (this.firstAction && ImageMenu.giveDirections == 1)) {
		out += "<br />\n<div class='ImageMenu-directions'>"+ImageMenu.directions+"</div>\n";
	}
	this.bigImgObj.innerHTML = out;
}

ImageMenu.getEffectiveStyleElement =  function(obj, elem) {
	var r;
	if (document.defaultView) {	// W3C
		r = document.defaultView.getComputedStyle(obj, "").getPropertyValue(elem);
	} else if (obj.currentStyle) { // assume IE
		r = obj.currentStyle[elem];
	} else {
		r = obj[elem];
	}
	return r;
}

ImageMenu.prototype.imgWidth = function() {
	var div, l;
	div = document.getElementById(this.div_id + "_0d");
	if (div) {
		l = parseInt(ImageMenu.getEffectiveStyleElement(div, this.dir));
	} else { // div not yet created
		l = this.imgSize[this.hw] + (this.hw?40:0);
	}
	return l;
}

ImageMenu.prototype.getWidth = function() {
	return this.imgWidth()*this.maxVis+this.interval*(this.maxVis-1);
}

ImageMenu.prototype.getImgLeft = function(idx) {
	var myLeft;
	if (this.img.length <= idx) {
		myLeft = this.getWidth()+1;
	} else if (!this.scrollable) { // compute from field center
		myLeft = Math.floor((this.img.length/2) * this.imgWidth() + Math.max(0, this.img.length/2 - 0.5) * this.interval);
		myLeft = Math.floor(this.getWidth()/2 - myLeft);
		myLeft += idx*this.imgWidth() + (idx-1)*this.interval + this.offset;
	} else { // compute from field left
		myLeft = idx*this.imgWidth() + idx*this.interval - this.offset;
	}
	return myLeft;
}

ImageMenu.prototype.display = function () {
	var divl = document.getElementById(this.div_id + "left");
	var divr = document.getElementById(this.div_id + "right");
	if (this.scrollable) {
		divl.style.visibility = 'visible';
		divr.style.visibility = 'visible';
		if (this.index || this.offset) {
			divl.innerHTML = ImageMenu.leftMessage;
		} else {
			divl.innerHTML = '';
		}
		if (this.offset || this.index != (this.img.length - this.maxVis)) {
			divr.innerHTML = ImageMenu.rightMessage;
		} else {
			divr.innerHTML = '';
		}
	} else {
		divl.style.visibility = 'hidden';
		divr.style.visibility = 'hidden';
	}

	var img;
	var div;
	var divt;
	for (var i = 0; i <= this.maxVis; i++) { // note - do maxVis+1 images; last one might be completely out of view
		img = document.getElementById(this.div_id + "_"+i);
		div = document.getElementById(this.div_id + "_"+i+"d");
		divt = document.getElementById(this.div_id + "_"+i+"t");
		if (i+this.index < this.img.length  && i+this.index >= 0) {
			img.src = this.img[i+this.index][1].src;
			div.onclick = new Function("event", "ImageMenu.objs["+this.id+"].mouseClick(event,"+(this.index+i)+")");
			divt.innerHTML = this.img[i+this.index][2];
		}
		if (this.hw) {	// vertical
			div.style.top = this.getImgLeft(i)+"px";
		} else  { // horizontal
			div.style.left = this.getImgLeft(i)+"px";
		}
	}
	document.getElementById(this.div_id).style.visibility = "visible";
}

ImageMenu.getEvent = function (evt) {
	return 	evt ? evt : ((event != null) ? event : null);
}

ImageMenu.isIE = function () {
	return event != null;
}

ImageMenu.getEventXY = function (evt, obj) {
	var x, y;
	if (evt = ImageMenu.getEvent(evt)) {
		x = evt.clientX;
		y = evt.clientY;
		if (evt.pageX) { // NN 6
			x = evt.pageX - (obj.offsetLeft ? obj.offsetLeft : obj.left);
			y = evt.pageY - (obj.offsetTop ? obj.offsetTop : obj.top);
		} else if (evt.clientX) { //IE
			if (evt.x) {
				x = evt.x;
				y = evt.y;
			} else {
				x = evt.offsetX - ((evt.offsetX < -2) ? 0 : document.body.scrollLeft);
				y = evt.offsetY - ((evt.offsetY < -2) ? 0 : document.body.scrollTop);
			}
		} else { //W3C
			x = evt.clientX - (obj.offsetLeft ? obj.offsetLeft : 0);
			y = evt.clientY - (obj.offsetTop ? obj.offsetTop : 0);
		}
		return new Array(x, y);
	}
	return null;
}

ImageMenu.prototype.scrolltable = [ [ 0.4, 0 ], [ 0.65, 1 ], [ 0.81, 3 ], [ 0.9, 5 ], [ 0.96, 8 ], [ 1, 13 ] ];

ImageMenu.prototype.computeScroll = function(xy) {
	var x = xy[this.hw];
	var len = this.getWidth()/2;
	var dist = x - len;
	var dir = dist < 0 ? -1 : 1;
	dist = Math.abs(dist) / len;
	for (var i = 0; i < this.scrolltable.length; i++) {
		if (dist < this.scrolltable[i][0]) {
			return dir * this.scrolltable[i][1];
		}
	}
	return 0;
}

ImageMenu.shiftto = function(im, pixels) {
	var curPos = im.offset + im.index*(im.imgWidth()+im.interval);
	var maxPos = im.img.length*im.imgWidth()+Math.max(0,im.img.length-1)*im.interval;
	maxPos -= im.maxVis*im.imgWidth() + (im.maxVis-1)*im.interval;
	var newPos = Math.max(0, Math.min(maxPos, curPos+pixels));
	im.offset = newPos % (im.imgWidth()+im.interval);
	im.index = Math.floor(newPos / (im.imgWidth()+im.interval));
}

ImageMenu.doScroll = function(id) {
	var im = ImageMenu.objs[id];
	if (im != null) {
		var dir = im.scrollspeed < 0 ? -1 : 1;  // negative is to the left, positive to the right

		ImageMenu.shiftto(im, im.scrollspeed);
		im.display();

		if (!im.scrollspeed && im.scrolltimeout) {
			clearInterval(im.scrolltimeout);
			im.scrolltimeout = 0;
		}
	}
}

ImageMenu.prototype.setScroll = function(xy){
	if (xy != null) {
		if (this.scrolltimeout) {
			clearInterval(this.scrolltimeout);
			this.scrolltimeout = 0;
		}
		if (this.scrollspeed = this.computeScroll(xy)) {
			var ms = Math.abs(Math.floor(100/this.scrollspeed));
			this.scrolltimeout = setInterval('ImageMenu.doScroll('+this.id+')', 1);
		}
	}
}

ImageMenu.prototype.mouseOver = function (evt) {
	this.setScroll(ImageMenu.getEventXY(evt, document.getElementById(this.div_id)));
}

ImageMenu.prototype.mouseOut = function (evt) {
	if (this.scrolltimeout) {
		clearInterval(this.scrolltimeout);
	}
	this.scrollspeed = 0;
	this.scrolltimeout = 0;
}

ImageMenu.prototype.mouseMove = function (evt) {
	this.setScroll(ImageMenu.getEventXY(evt, document.getElementById(this.div_id)));
}

ImageMenu.prototype.mouseClick = function (evt, img_idx) {
	if (img_idx == null) {
		img_idx = evt;
		evt = null;
	}
	this.firstAction = false;
	this.setBigImg(img_idx);
}