function ElementSlideShow (contentId, autoPageInterval, transEffect, transTime) {

this.id = contentId;

this.next = goNextPage;
this.previous = goPreviousPage;
this.stop = stopAutoPage;
this.resume = startAutoPage;
this.loadFrame = loadFrameById;

this.content = null;
this.autoAdvance = autoAdvancePage;
this.autoPageTimer = null;
this.transition = transitionStep;
this.transitionEffect = (transEffect ? transEffect : "none");
this.transitionTime = (transTime ? transTime : 1000);
this.transitionObject = null;

this.selected = -1;
this.autoPageInterval = autoPageInterval;

if (!document.getElementById) {
	return;
}

// IE for the Mac is garbage
if (navigator.appVersion.indexOf("Mac") >= 0 && (navigator.appVersion.indexOf("PPC") >= 0 || navigator.appVersion.indexOf("PowerPC") >= 0) && navigator.appVersion.indexOf("MSIE") >= 0) {
	this.transitionEffect = "none";
}

this.content = document.getElementById(contentId);
if (this.content == null) {
	return;
}
this.content.style.overflow = "hidden";

if (window["_elementSlideShows"] == null) {
	window["_elementSlideShows"] = new Object();
}
window["_elementSlideShows"][this.id] = this;

var childElements = getChildren(this.content);
this.ordering = getRandomArray(childElements.length);
this.children = new Array();
this.children.length = childElements.length;
for (var i=0; i<childElements.length; i++) {
	this.children[i] = childElements[this.ordering[i]];
}

this.selected = 0;
this.children[0].style.display = "block";
for (var i=1; i<this.children.length; i++) {
	this.children[i].style.display = "none";
}

this.content.style.opacity = 0.999999;
this.content.style.MozOpacity = 0.999999;
for (var i=0; i<this.children.length; i++) {
	this.children[i].style.opacity = 0.999999;
	this.children[i].style.MozOpacity = 0.999999;
}

this.content.onmouseover = stopOnMouseOver;
this.content.onmouseover = restartOnMouseOut;
addListener(window, "unload", removeAllListeners);
addListener(window, "blur", stopAll);
addListener(window, "focus", startAll);

this.resume();

this.content.onclick = listenForClicks;

//Begin private functions

function goToPage (slideShow, direction) {
	var selected = slideShow.selected;

	var next = selected + direction;
	if (next < 0) {
		next = slideShow.children.length - 1;
	} else if (next >= slideShow.children.length) {
		next = 0;
	}

	if (selected >= 0) {
		slideShow.children[selected].style.display = "none";
	}
	if (next >= 0) {
		slideShow.children[next].style.display = "block";
	}

	slideShow.selected = next;
}

function stopAll () {
	if (window["_elementSlideShows"] != null) {
		for (id in window["_elementSlideShows"]) {
			window["_elementSlideShows"][id].stop();
		}
	}
}

function startAll () {
	if (window["_elementSlideShows"] != null) {
		for (id in window["_elementSlideShows"]) {
			window["_elementSlideShows"][id].resume();
		}
	}
}

function removeAllListeners () {
	if (window["_elementSlideShows"] != null) {
		for (id in window["_elementSlideShows"]) {
			window["_elementSlideShows"][id].content.onmouseover = null;
			window["_elementSlideShows"][id].content.onmouseout = null;
		}
	}

	removeListener(window, "unload", removeAllListeners);
	removeListener(window, "blur", stopAll);
	removeListener(window, "focus", startAll);
}

function removeListener (target, event, handler) {
	if (target.removeEventListener) {
		target.removeEventListener(event, handler, false);
	} else if (target.detachEvent) {
		target.detachEvent("on" + event, handler);
	}
}

function addListener (target, event, handler) {
	if (target.addEventListener) {
		target.addEventListener(event, handler, false);
	} else if (target.attachEvent) {
		target.attachEvent("on" + event, handler);
	}
}

function goNextPage (autoPage) {
    if (this.content == null) {
        return;
    }

	clearTransition(this);
	goToPage(this, 1);

	autoPage ? this.resume() : this.stop();
}

function goPreviousPage (autoPage) {
    if (this.content == null) {
        return;
    }

	clearTransition(this);
	goToPage(this, -1);

	autoPage ? this.resume() : this.stop();
}

function stopAutoPage () {
    if (this.content == null) {
        return;
    }

	if (this.autoPageTimer) {
		clearInterval(this.autoPageTimer);
		this.autoPageTimer = null;
	}
	clearTransition(this);
}

function startAutoPage () {
    if (this.content == null) {
        return;
    }

	if (this.autoPageInterval <= 0) {
		return;
	}

	setNextAutoPage(this);

	if (this.autoPageTimer == null) {
		this.autoPageTimer = setInterval("window['_elementSlideShows']['" + this.id + "'].autoAdvance();", 1000);
	}
}

function loadFrameById (id, autoPage) {
    if (this.content == null) {
        return;
    }

    var frame = document.getElementById(id);
    if (frame != null) {
        for (var i=0; i<this.children.length; i++) {
			if (this.children[i] == frame) {
				clearTransition(this);
				if (this.selected != i) {
					this.children[this.selected].style.display = "none";
					this.children[i].style.display = "block";
					this.selected = i;
				}
				break;
			}
        }
    }

	autoPage ? this.resume() : this.stop();
}

function clearTransition (slideShow) {
	var currentTransition = slideShow.transitionObject;
	slideShow.transitionObject = null;

	if (currentTransition != null) {
		currentTransition.finish();
	}
}

function autoAdvancePage () {
	if (window["_elementSlideShows:active"] == this.id) {
		return;
	}

	if (this.nextAutoPage <= 0) {
		return;
	}

	var now = (new Date()).getTime();
	if (now + 50 - this.nextAutoPage < 0) {
		return;
	}

	// Prevent paging while transition in effect
	this.nextAutoPage = 0;

	var effect = this.transitionEffect;
	clearTransition(this);

	var transObj = null;
	var frameInterval = 75;
	if (effect == "fade") {
		transObj = new FadeTransition(this, true);
	} else if (effect == "merge") {
		transObj = new WipeTransition(this, false, true);
	} else if (effect == "wipe") {
		transObj = new WipeTransition(this, true, false);
	} else if (effect == "scroll") {
		transObj = new WipeTransition(this, false, false);
	} else {
		goToPage(this, 1);
		setNextAutoPage(this);
	}

	if (transObj != null) {
		transObj.slideShow = this;
		transObj.frameInterval = frameInterval;
		transObj.increment = 100 / (this.transitionTime / frameInterval);
		transObj.complete = 0;
		transObj.stepping = false;
		this.transitionObject = transObj;
	}

	this.transition();
}

function transitionStep () {
	var transition = this.transitionObject;
	if (transition != null) {
	    var startTime = (new Date()).getTime();
		transition.complete += transition.increment;
		if (transition.complete > 100) {
			transition.complete = 100;
			transition.finish();
			setNextAutoPage(this);
		} else {
			transition.step();

			var next = transition.frameInterval - ((new Date()).getTime() - startTime);
			if (next <= 0) {
			    this.transition();
			} else {
				setTimeout("window['_elementSlideShows']['" + this.id + "'].transition();", next);
			}
		}
	}
}

function setNextAutoPage (slideShow) {
	if (slideShow.autoPageInterval > 0) {
		slideShow.nextAutoPage = (new Date()).getTime() + (1000 * slideShow.autoPageInterval);
	}
}

function getChildren (element) {
	var children = new Array();
	var nodes = element.childNodes;
	for (var i=0; i<nodes.length; i++) {
		if (nodes[i].nodeType == 1) {
			children[children.length] = nodes[i];
		}
	}

	return children;
}

function getRandomArray (length) {
	var seeds = new Array();
	seeds.length = length;
	for (var i=0; i<seeds.length; i++) {
		seeds[i] = new Object();
		seeds[i].seed = Math.random();
		seeds[i].index = i;
	}

	seeds.sort(compareSeeds);

	var randomArray = new Array();
	randomArray.length = length;
	for (var i=0; i<length; i++) {
		randomArray[i] = seeds[i].index;
	}

	return randomArray;
}

function compareSeeds (obj1, obj2) {
	return obj1.seed - obj2.seed;
}

function listenForClicks (evt) {
	if (!evt) {
		evt = window.event;
	}

	var target = (evt.target ? evt.target : evt.srcElement);
	while (target != null) {
		if (target.id) {
			var slideShow = window["_elementSlideShows"][target.id];
			if (slideShow != null) {
				slideShow.stop();
				break;
			}
		}

		target = target.parentNode;
	}

	return true;
}

function setContentOpacity (content, value) {
	if (value > 1) {
		value = 1;
	} else if (value < 0) {
		value = 0;
	}

	var style = content.style;
	style.opacity = (value == 1 ? 0.999999 : value);
	style.MozOpacity = (value == 1 ? 0.999999 : value);
	style.KhtmlOpacity = value;

	if (value < 1) {
		style.filter = "alpha(opacity=" + Math.round(value * 100) + ")";
	} else {
		style.filter = null;
	}
}

function stopOnMouseOver (evt) {
	var id = this.id;

	var activeId = window["_elementSlideShows:active"];
	if (activeId != null) {
		return;
	}

	window["_elementSlideShows:active"] = this.id;
	clearTransition(this);
}

function restartOnMouseOut (evt) {
	if (evt == null) {
		evt = window.event;
	}

	var target = (evt.target ? evt.target : evt.srcElement);
	var relatedTarget = (evt.relatedTarget ? evt.relatedTarget : evt.toElement);

	while (relatedTarget != null && relatedTarget != target && relatedTarget.nodeName.toUpperCase() != 'BODY') {
		relatedTarget = relatedTarget.parentNode;
	}

	if (relatedTarget == target) {
		return;
	}

	window["_elementSlideShows:active"] = null;
}

function FadeTransition (slideShow) {
	this.step = fadeStep;
	this.finish = fadeFinish;

	this.slideShow = slideShow;
	this.direction = -1;

	function fadeStep () {
		var opacity;
		if (this.complete < 50) {
			opacity = 100 - (this.complete * 2);
		} else {
			if (this.direction < 0) {
				this.direction = 1;
				goToPage(this.slideShow, 1);
			}
			opacity = (this.complete - 50) * 2;
		}

		setContentOpacity(this.slideShow.content, opacity / 100);
	}

	function fadeFinish () {
		setContentOpacity(this.slideShow.content, 1);
	}

}

function WipeTransition (slideShow, horizontal, merge) {
    if (merge) {
        this.step = mergeStep;
    } else {
		this.step = wipeStep;
    }

	this.finish = wipeFinish;

	this.horizontal = horizontal;
	this.slideShow = slideShow;

	this.fromElement = slideShow.children[slideShow.selected];

	this.nextIndex = slideShow.selected + 1;
	if (this.nextIndex >= slideShow.children.length) {
		this.nextIndex = 0;
	}
	this.toElement = slideShow.children[this.nextIndex];

	var x = getLeft(this.fromElement);
	var y = getTop(this.fromElement);
	var width = slideShow.content.offsetWidth;
	var height = slideShow.content.offsetHeight;

	var from = this.fromElement.style;
	from.left = x + "px";
	from.top = y + "px";
	from.width = width + "px";
	from.height = height + "px";
	from.position = "absolute";

	var to = this.toElement.style;
	to.left = (horizontal && !merge ? (x + width) : x)+ "px";
	to.top = (horizontal || merge ? y : y + height) + "px";
	to.width = width + "px";
	to.height = height + "px";
	if (merge) {
		setContentOpacity(this.toElement, 0);
	} else {
		to.clip = (horizontal ? "rect(0px,0px," + height + "px,0px)" : "rect(0px," + width + "0px,0px,0px)");
	}
	to.position = "absolute";
	to.display = "block";

	this.fromPos = (horizontal ? x : y);
	this.toPos = (horizontal ? x + width : y + height);
	this.scrollDelta = (this.toPos - this.fromPos);
	this.paged = false;
	
	function wipeStep () {
		var width = this.slideShow.content.offsetWidth;
		var height = this.slideShow.content.offsetWidth;

		var prevOffset = Math.round(this.scrollDelta * (this.complete / 100));

		if (this.complete >= 50 && !this.paged) {
			this.slideShow.selected = this.nextIndex;
			this.paged = true;
		}

		var offset = Math.round(this.scrollDelta * (this.complete / 100));

		var from = this.fromElement.style;
		var to = this.toElement.style;

		var fromRect;
		var toRect;
		if (this.horizontal) {
			fromRect = "rect(0px," + width + "px," + height + "px," + offset + "px)";
			toRect = "rect(0px," + offset + "px," + height + "px,0px)";
		} else {
			fromRect = "rect(" + offset + "px," + width + "px," + height + "px,0px)";
			toRect = "rect(0px," + width + "px," + offset + "px,0px)";
		}

		var fromPos = (this.fromPos - offset) + "px";
		var toPos = (this.toPos - offset) + "px";

		if (horizontal) {
			from.left = fromPos;
		} else {
			from.top = fromPos;
		}
		from.clip = fromRect;

		if (horizontal) {
			to.left = toPos;
		} else {
			to.top = toPos;
		}
		to.clip = toRect;
	}
	
	function mergeStep () {
	    if (this.complete >= 50 && !this.paged) {
	        this.paged = true;
			this.slideShow.selected = this.nextIndex;
		}

		var opacityOut = 100 - this.complete;
		var opacityIn = this.complete;

		setContentOpacity(this.toElement, opacityIn / 100);
		setContentOpacity(this.fromElement, opacityOut / 100);
	}

	function wipeFinish () {
		var show;
		var hide;

		if (this.paged) {
			hide = this.fromElement.style;
			show = this.toElement.style;
		} else {
			this.paged = true;
			hide = this.toElement.style;
			show = this.fromElement.style;
		}

		hide.display = "none";
		hide.width = "auto";
		hide.height = "auto";
		hide.position = "static";

		show.display = "block";
		show.width = "auto";
		show.height = "auto";
		show.position = "static";
		
		setContentOpacity(this.toElement, 1);
		setContentOpacity(this.fromElement, 1);
	}

	function isInRect (x, y, left, top, width, height) {
		if (x < left || x > left + width) {
			return false;
		} else if (y < top || y > top + height) {
			return false;
		} else {
			return true;
		}
	}
	
	function getLeft (element) {
		var x = 0;
		while (element) {
			x += element.offsetLeft;
			element = element.offsetParent;
		}
	
		return x;
	}
	
	function getTop (element) {
		var y = 0;
		while (element) {
			y += element.offsetTop;
			element = element.offsetParent;
		}
	
		return y;
	}
}

}
