function image(objectname, url, title, description) { 

	this.instancename = objectname;
	this.url = url;
	this.title = title;
	this.description = description;

	// Create an image object for the slide
	if (document.images) {
		this.img = new Image();
	}

	this.content = document.createElement("div");
	this.content.setAttribute("id", this.instancename);
	this.content.style.opacity = 0;
	this.content.style.position = "absolute";
	this.content.style.filter = "alpha(opacity=0)";
	this.content.appendChild(this.img);
	if ((this.title !== undefined) && (this.title != "")) {
		titleh3 = document.createElement("h3");
		titleh3_text = document.createTextNode(this.title);
		titleh3.appendChild(titleh3_text);
		this.content.appendChild(titleh3);
	}
	if ((this.description !== undefined) && (this.description != "")) {
		caption = document.createElement("p");
		caption.setAttribute("id", "caption");
		caption_text = document.createTextNode(this.description);
		caption.appendChild(caption_text);
		this.content.appendChild(caption);
	}
	
	this.loaded = false;

}

image.prototype.load = function(callback) {
	// This method loads the image for the slide

	if (!document.images) { return; }

	var me = this;
	this.callback = callback;

	if (!this.loaded) {
		//alert("stop");
		//alert("loading image " + this.instancename + "; this.url = " + this.url);
		if (typeof this.callback == 'function') {
			//alert("SETTING CALLBACK!");
			this.img.onload = this.callback;
		}
		this.img.src = this.url;
		this.loaded = true;
	}
	else {
		//alert("loading image already loaded " + this.instancename);
		// null or undefined is allowed, so check for it
		if (typeof this.callback == 'function') {
			//alert("CALLBACK!");
			this.callback();
		}
		//else
			//alert("callback is " + typeof this.callback);
	}
}

/*
image.prototype.setloaded = function() {
	this.loaded = true;
	// null or undefined is allowed, so check for it
	if (typeof this.callback == 'function') {
		alert("CALLBACK!");
		this.callback();
	} else {
		alert("callback is " + typeof this.callback);
	}
}
*/

// END image


function images(objectname, parentelementid) {

	this.instancename = objectname;
	this.currentcount = -1;
	this.oldcount = -1;  // keep track of who to remove from the dom
	this.cache = 3;
	this.busy = false;
	this.images = new Array();
	this.autotimer = 3000;  // 3 second default
	this.autotimeoutid = 0;
	this.pre_hooks = new Array();
	this.pre_hooks_args = new Array();
	// the elementid of the element to be replaced; an <img> perhaps
	//this.elementid = elementid;
	// the container element for the element to be replaced
	this.parentelementid = parentelementid;
}

images.prototype.add_pre_hook = function (object, method, args) {
	if (!(method instanceof Function))
		method = object[method];
	this.pre_hooks[this.pre_hooks.length] = function () { method.apply(object, arguments); }
	this.pre_hooks_args[this.pre_hooks_args.length] = args;
}

images.prototype.addimage = function(image) {
	count = this.images.length;
	this.images[count] = image;
}

images.prototype.populatecache = function() {
	var next, prev, count;

	if (this.cache == 0) {
		// do nothing
		return;
	}

	if ((this.cache < 0) || (this.cache >= this.images.length)) {
		this.cache = (this.images.length - 1);
	}
	// Pre-fetch the next slide image(s)
	next = this.currentcount;
	prev = this.currentcount;
	count = 0;
	do {
		// Get the next and previous slide number
		// Loop past the ends of the slideshow if necessary
		if (++next >= this.images.length) next = 0;
		if (--prev < 0) prev = this.images.length - 1;

		// Preload the slide image
		this.images[next].load();
		this.images[prev].load();

		// Keep going until we have fetched
		// the designated number of slides

	} while (++count < this.cache);

}

images.prototype.replaceimage = function() {
	var me = this;
	//if (document.getElementById(this.elementid) !== undefined) {
	if (this.images[this.oldcount] !== undefined) {
		Effect.Fade(this.images[this.oldcount].content.getAttribute("id"), { duration:0.5, from:1.0, to:0.0, afterFinish: function(){me.remove()} } );
		//alert("fading " + this.elementid);
	}
	else {
		this.busy = false;
	}

	for (i = 0; i < this.pre_hooks.length; i++) {
		this.pre_hooks[i](eval(this.pre_hooks_args[i]));
	}

	// set position within parentelement:
	this.setleft();
	this.settop();

	//alert("appending " + this.images[this.currentcount].content.getAttribute("id") + " to " + this.parentelementid);
	document.getElementById(this.parentelementid).appendChild(this.images[this.currentcount].content);
	//alert("appearing " + this.elementid);
	Effect.Appear(this.images[this.currentcount].content.getAttribute("id"), { duration:0.5, from:0.0, to:1.0 } );
	//this.remove();
}

images.prototype.setleft = function() {
	var parentelement = document.getElementById(this.parentelementid);
	if ((parentelement !== undefined) && (parentelement.clientWidth != "")) {
		if (this.images[this.currentcount].img.width > 0) {
			this.images[this.currentcount].content.style.left = Math.round((parentelement.clientWidth - this.images[this.currentcount].img.width) / 2) + "px";
		/*
		} else {
			alert("Could not get width for image " + this.images[this.currentcount].img.src + ".");
		*/
		}
	} else {
		alert("If you want to horizontal center the " + this.images[this.currentcount].content.getAttribute("id") + " div, you have to set the" +
				" width on its parent, which you've defined to be " + this.parentelementid + "." +
				" its width is \"" +  parentelement.clientWidth + "\".");
	}
}

images.prototype.settop = function() {
	var parentelement = document.getElementById(this.parentelementid);
	if ((parentelement !== undefined) && (parentelement.clientHeight != "")) {
		if (this.images[this.currentcount].img.height > 0) {
			this.images[this.currentcount].content.style.top = Math.round((parentelement.clientHeight - this.images[this.currentcount].img.height - parentelement.style.paddingTop) / 2) + "px";
		}/* else {
			alert("Could not get height for image " + this.images[this.currentcount].img.src + ".");
		}*/
	} else {
		alert("If you want to vertical center the " + this.images[this.currentcount].content.getAttribute("id") + " div, you have to set the" +
				" height on its parent, which you've defined to be " + this.parentelementid + "." +
				" its height is \"" +  parentelement.clientHeight + "\".");
	}
}

images.prototype.remove = function() {
	if ((this.oldcount != -1) && (document.getElementById(this.images[this.oldcount].content.getAttribute("id")) !== 'undefined')) {
		//alert("removing " + this.images[this.oldcount].content.getAttribute("id") + " from " + this.parentelementid);
		document.getElementById(this.parentelementid).removeChild(document.getElementById(this.images[this.oldcount].content.getAttribute("id")));
	}
	this.busy = false;
}

images.prototype.next = function() {
	// Increment the image number
	var me = this;
	if (!this.busy) {
		this.busy = true;
		this.oldcount = this.currentcount;
		if (this.currentcount < this.images.length - 1) {
			this.currentcount++;
		} else {
			this.currentcount = 0;
		}
		this.images[this.currentcount].load(function(){me.replaceimage()});
	}

}

images.prototype.prev = function() {
	// Decrement the image number
	var me = this;
	if (!this.busy) {
		this.busy = true;
		this.oldcount = this.currentcount;
		if (this.currentcount > 0) {
			this.currentcount--;
		} else {
			this.currentcount = this.images.length - 1;
		}
		this.images[this.currentcount].load(function(){me.replaceimage()});
	}
}

images.prototype.gotoimage = function(index)
{
	var me = this;
	clearTimeout(this.autotimeoutid);
	if (!this.busy) {
		this.busy = true;
		this.oldcount = this.currentcount;
		if (index != this.currentcount) {
			if ((index >= (0)) && (index < (this.images.length)))
				this.currentcount = index;
			this.images[this.currentcount].load(function(){me.replaceimage()});
		}
		this.populatecache();
	}
}

images.prototype.loop = function() {
	this.next();
   	this.play();
}

images.prototype.pause = function() {
	if (this.autotimeoutid != 0)
	{
    	clearTimeout(this.autotimeoutid);
		this.autotimeoutid = 0;
	}
}

images.prototype.play = function() {

	// Make sure we're not already playing
    this.pause();

	// After the timeout, call this.loop()
	this.autotimeoutid = setTimeout( this.instancename + ".loop()", this.autotimer);
}

images.prototype.toggle = function() {
	if (this.autotimeoutid != 0) {
		document.getElementById("toggle").setAttribute("class", "play");
		document.getElementById("togglespan").innerHTML = "play";
		this.pause();
	} else {
		document.getElementById("toggle").setAttribute("class", "pause");
		document.getElementById("togglespan").innerHTML = "pause";
		this.play();
	}
}

images.prototype.settimer = function(timer) {
	if (timer < 1)
		this.autotimer = 1000;
	else if (timer > 8)
		this.autotimer = 8000;
	else
		this.autotimer = timer * 1000;
}

// END images


function thumb(url, onclickref) {

	this.loaded = false;
	this.url = url;
	this.onclickref = onclickref;
	this.a = document.createElement("a");
	//this.a.setAttribute("href", "#");
	this.a.href = "javascript:" + onclickref;

	// Create an image object for the slide
	if (document.images) {
		//this.image = document.createElement("img");
		this.image = new Image();
	}

}

thumb.prototype.load = function(callback) {
	// This method loads the image for the thumbbox
	var me = this;
	this.callback = callback;

	if (!document.images) { return; }

	if (!this.loaded) {
		this.image.src = this.url;
		if (typeof this.callback == 'function')
			this.image.onload = function(){me.setloaded()};
		this.a.appendChild(this.image);
	}
}

thumb.prototype.setloaded = function() {
	this.loaded = true;
	this.callback();
}


// END images

function thumbbox(max, elementid) {
	this.thumbbox = document.createElement("div");
	this.thumbbox.setAttribute("id", elementid);
	//this.thumbbox.setAttribute("style", "display: none;");
	//this.thumbbox.style.textAlign = "center";

	this.thumbbox.style.opacity = 0;
	this.thumbbox.style.position = "absolute";
	this.thumbbox.style.filter = "alpha(opacity=0)";

	this.loaded = false;
	this.nloaded = 0;

	this.thumbs = new Array();
	this.max = max;
	this.full = false;
}

thumbbox.prototype.load = function(callback) {
	var me = this;
	this.callback = callback;
	if (!this.loaded) {
		for (i = 0; i < this.thumbs.length; i++) {
			this.thumbs[i].load(function(){me.myonload()});
			this.thumbbox.appendChild(this.thumbs[i].a);
		}
	}
	else {
		// null or undefined is allowed, so check for it
		if (typeof this.callback == 'function')
			this.callback();
	}
}

thumbbox.prototype.myonload = function() {
	this.nloaded++;
	if (this.nloaded == (this.thumbs.length - 1)) {
		this.loaded = true;
		// null or undefined is allowed, so check for it
		if (typeof this.callback == 'function')
			this.callback();
	}
}


thumbbox.prototype.addthumb = function(url, onclickref) {
	if (this.max == this.thumbs.length) alert("you're trying to add too many thumbs to the thumbbox; max = " + this.max);
	var me = this;
	this.thumbs[this.thumbs.length] = new thumb(url, onclickref);
	this.full = (this.max == this.thumbs.length);
}



// END thumbbox

function thumbboxes(objname, perpage, elementid, parentelementid) {
	// contaianer id; perhaps a <div>.  This is the one that gets replaced
	this.elementid = elementid;
	// parent container id; perhaps a <div>
	this.parentelementid = parentelementid;
	this.instancename = objname;
	this.thumbboxes = new Array();
	this.perpage = perpage;
	this.currentpage = -1;
	this.oldpage = -1;
	this.lastpicprevpage = 0;
	this.firstpicnextpage = 0;
	this.busy = false;
}

thumbboxes.prototype.addthumb = function(url, onclickref) {
	if ((this.thumbboxes.length == 0) || (this.thumbboxes[this.thumbboxes.length - 1].full)) {
		this.thumbboxes[this.thumbboxes.length] = new thumbbox(this.perpage, this.elementid + this.thumbboxes.length);
	}
	this.thumbboxes[this.thumbboxes.length - 1].addthumb(url, onclickref);
}

/*
thumbboxes.prototype.showallthumbs = function() {
	this.replacement = new thumbbox((this.thumbboxes.length - 1) * this.perpage + this.thumbboxes[this.thumbboxes.length - 1].thumbs.length, this.elementid);
	for (i = 0; i < this.thumbboxes.length; i++) {
		if(this.thumbboxes[i] !== undefined) {
			this.thumbboxes[i].load();
			for(j = 0; j < this.thumbboxes[i].thumbs.length; j++) {
				if (this.thumbboxes[i].thumbs[j] !== undefined) {
					this.thumbboxes[i].thumbs[j].load();
					if (this.thumbboxes[i].thumbs[j].loaded) {
						this.replacement.addthumb(this.thumbboxes[i].thumbs[j].url, this.thumbboxes[i].thumbs[j].onclickref);
					}
				}
			}
		}
	}
	this.replacement.load();
	if (this.replacement.loaded)  {
		this.currentpage = -1;
		this.replacediv();
	}
}
*/

thumbboxes.prototype.gotoimage = function(imgnum) {
	if (!this.busy) {
		//this.displayloading();
		this.busy = true;
		var me = this;
		var page = Math.floor( (imgnum) / this.perpage );

		this.lastpicprevpage = (page != 0) ? (page * this.perpage - 1) : (this.thumbboxes.length - 1) * this.perpage + this.thumbboxes[this.thumbboxes.length - 1].thumbs.length - 1;

		this.firstpicnextpage = (page == (this.thumbboxes.length - 1)) ? 0 : ((page + 1) * this.perpage);

		// make sure current is loaded, and might as well populate the prev and next
		//if (this.thumbboxes[page] !== undefined) {
		if (page != this.currentpage) {
			this.oldpage = this.currentpage;
			this.currentpage = page;
			this.populatecache();
			//alert("calling load with this.oldpage = " + this.oldpage + "; this.currentpage = " + this.currentpage);
			this.thumbboxes[this.currentpage].load(function(){me.replacediv()});
			// TODO: Should really do this a better way, instead of hard coding the "pageselect"
			if (document.getElementById("pageselect") != undefined)
				element = document.getElementById("pageselect").options[page].selected = true;
		}
		else {
			this.busy = false;
		}
		//}
	}
}

/*
thumbboxes.prototype.displayloading = function() {
	if (document.images) {
		img = new Image();
		img.src = "/images/ajax-loader.gif";
		div = document.createElement("div");
		div.appendChild(img);
		div.setAttribute("id", "ajaxloader");
		//this.images[this.currentcount].content.style.left = Math.round((parentelement.clientWidth - this.images[this.currentcount].img.width) / 2) + "px";
		this.remove();  // just in case
		document.getElementById(this.parentelementid).appendChild(div);
	}
}
*/

thumbboxes.prototype.replacediv = function() {
	var me = this;
//	alert("me is " + me);
	//if (document.getElementById(this.elementid) !== 'undefined') {
/*
	if ((document.getElementById(this.parentelementid) !== 'undefined') && (document.getElementById("ajaxloader") !== 'undefined')) {
		document.getElementById(this.parentelementid).removeChild(document.getElementById("ajaxloader"));
	}
*/
	//Effect.Fade(document.getElementById("ajaxloader"), { duration:0.5, from:1.0, to:0.0 } );
	if (this.thumbboxes[this.oldpage] !== undefined) {
		Effect.Fade(this.thumbboxes[this.oldpage].thumbbox.getAttribute("id"), { duration:0.5, from:1.0, to:0.0, afterFinish: function(){me.remove()} } );
		//Effect.Fade(this.thumbboxes[this.oldpage].thumbbox.getAttribute("id"), { duration:0.5, from:1.0, to:0.0 } );
	}
	else {
		this.busy = false;
	}
	//alert("appending " + this.thumbboxes[this.currentpage].thumbbox.getAttribute("id"));
	document.getElementById(this.parentelementid).appendChild(this.thumbboxes[this.currentpage].thumbbox);
	//Effect.SlideDown(this.elementid, { duration: 1.0, from: 0.0, to: 1.0 } );
	Effect.Appear(this.thumbboxes[this.currentpage].thumbbox.getAttribute("id"), { duration:0.5, from:0.0, to:1.0 } );
	//Effect.Appear(this.thumbboxes[this.currentpage].thumbbox.getAttribute("id"), { duration:0.5, from:0.0, to:1.0 } );

}

thumbboxes.prototype.remove = function() {
	if ((this.oldpage != -1) && (document.getElementById(this.thumbboxes[this.oldpage]) !== undefined)) {
		//alert("removing " + this.thumbboxes[this.oldpage].thumbbox.getAttribute("id") + " from " + this.parentelementid);
		document.getElementById(this.parentelementid).removeChild(document.getElementById(this.thumbboxes[this.oldpage].thumbbox.getAttribute("id")));
	}
	this.busy = false;
}

thumbboxes.prototype.populatecache = function() {
	var next, prev, count;

	// Pre-fetch the next slide image(s)
	next = this.currentpage;
	prev = this.currentpage;
	count = 0;
	do {
		// Get the next and previous slide number
		// Loop past the ends of the slideshow if necessary
		if (++next >= this.thumbboxes.length) next = 0;
		if (--prev < 0) prev = this.thumbboxes.length - 1;

		// Preload the slide image
		//alert("populating this.thumbboxes[" + next + "] which is " + this.thumbboxes[next]);
		this.thumbboxes[next].load();
		this.thumbboxes[prev].load();

		// Keep going until we have fetched
		// the designated number of slides

	//} while (++count < this.perpage+1);
	} while (++count < 1);

}

