// divtransition.js - version 3.00 2008-08-02
//
// A JavaScript class for transitioning the content of a div
//
// base: http://www.webaware.com.au/free/divtransition/
//
// copyright © 2006-2008 WebAware Pty Ltd
//---------------------------------------------------------------------
// instructions here...
//---------------------------------------------------------------------
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// Full license: http://www.webaware.com.au/free/license.htm
//---------------------------------------------------------------------
// functions:
// FadeIn		create a fade-in transition for specified div
// GetExtRef	get name of global variable for external referencing
//---------------------------------------------------------------------
// * IE requires the divs to have width &/or height set, or you must set
//   position: absolute, to give the div "layout" so that opacity works
//
// * IE needs background-color set on the divs - see this link for more:
//   http://jszen.blogspot.com/2005/04/ie-bold-text-opacity-problem.html
//---------------------------------------------------------------------

// class constructor
function DivTransition(containerID, transition, delay_ms, steps) {
	// add members
	this.containerID = containerID;
	this.extref = DivTransition.GetExtRef(containerID);
	this.container = false;
	this.transition = (typeof transition != "undefined") ? transition : 'fadein';
	if (typeof steps != "undefined")
		this.steps = steps;
	else {
		switch (this.transition) {
			case 'fadein':
				this.steps = 10;
				break;
			case 'slideup':
				this.steps = 2;
				break;
			default:
				this.steps = 2;
				break;
		}
	}
	this.delay_ms = (typeof delay_ms != "undefined") ? delay_ms : 3000;
	this.timer = false;
	this.child_index = -1;
	this.previous_child = -1;

	this.paused = true;
	this.action = 'none';
	this.stepping = 0;
}

// generate global self-reference from div ID
DivTransition.GetExtRef = function(containerID) {
	return "v_DivTransition_" + containerID;
}

// behind-the-scenes class factory, creates Fade-In instance and adds it to global namespace
DivTransition.FadeIn = function(containerID, delay_ms, steps) {
	if (typeof delay_ms == "undefined")
		delay_ms = "";
	if (typeof steps == "undefined")
		steps = "";

	var newInstance = DivTransition.GetExtRef(containerID);
	eval(newInstance + " = new DivTransition('" + containerID + "', 'fadein', " + delay_ms + ", " + steps + ");");

	DivTransition.HookEvent(window, "load", Function(newInstance + ".Activate()"));
}

// behind-the-scenes class factory, creates Slide instance and adds it to global namespace
DivTransition.SlideUp = function(containerID, delay_ms, steps) {
	if (typeof delay_ms == "undefined")
		delay_ms = "";
	if (typeof steps == "undefined")
		steps = "";

	var newInstance = DivTransition.GetExtRef(containerID);
	eval(newInstance + " = new DivTransition('" + containerID + "', 'slideup', " + delay_ms + ", " + steps + ");");

	DivTransition.HookEvent(window, "load", Function(newInstance + ".Activate()"));
}

// simplistic event hooking for (on)load, (on)unload, etc.
DivTransition.HookEvent = function(obj, event, hook) {
	if (obj.addEventListener) obj.addEventListener(event, hook, false);
	else if (obj.attachEvent) obj.attachEvent("on" + event, hook);
}

// simplistic event unhooking for (on)load, (on)unload, etc.
DivTransition.UnhookEvent = function(obj, event, hook) {
	if (obj.addEventListener) obj.addEventListener(event, hook, false);
	else if (obj.attachEvent) obj.attachEvent("on" + event, hook);
}

// activate the class - start the div scrolling
DivTransition.prototype.Activate = function() {
	this.container = document.getElementById ? document.getElementById(this.containerID) : eval("document.all." + this.containerID);
	this.container.onmouseover = DivTransition.onmouseover;
	this.container.onmouseout = DivTransition.onmouseout;
	this.child_index = this.FindFirstChild();

	// select functions to suit browser
	if (this.container.filters)
		this.SetOpacity = DivTransition.SetOpacityIE;
	else
		this.SetOpacity = DivTransition.SetOpacityMoz;

	// kick it off
	if (this.container) {
		this.paused = false;
		window.setTimeout(this.extref + '.LoopForward()', this.delay_ms);
	}
}

// event: on mouse over, pause transitions
DivTransition.onmouseover = function() {
	var extref = DivTransition.GetExtRef(this.id);
	eval(extref + ".paused = true");
}

// event: on mouse out, restart transitions
DivTransition.onmouseout = function() {
	var extref = DivTransition.GetExtRef(this.id);
	eval(extref + ".paused = false");
}

// private: find the first child div (not necessarily the first child node!)
DivTransition.prototype.FindFirstChild = function() {
	var l = this.container.childNodes.length
	for (var i = 0; i < l && this.container.childNodes[i].tagName != "DIV"; ++i) ;
	return (i < l) ? i : 0;
}

// private: advance the loop forward one transition
DivTransition.prototype.LoopForward = function() {
	if (this.paused) {
		window.setTimeout(this.extref + '.LoopForward()', 100);
		return;
	}

	try {
		var l = this.container.childNodes.length;
		var i = this.child_index;
		for (;;) {
			if (++i == l)
				i = 0;
			if (this.container.childNodes[i].tagName == "DIV") {
				this.ShowChild(i);
				break;
			}
		}
	}
	catch(e) {
		window.status = e.description;
	}
}

// private: transition to the nominated child div
DivTransition.prototype.ShowChild = function(child_index) {
	try {
		this.action = "stepping";
		this.stepping = 0;
		for (var i = this.container.childNodes.length; --i >= 0; ) {
			var el = this.container.childNodes[i];
			if (el.tagName == "DIV") {
				if (i == child_index) {
					this.previous_child = this.child_index;
					this.child_index = child_index;

					switch (this.transition) {
						case 'fadein':
							this.container.childNodes[this.previous_child].style.display = "none";
							this.FadeInStep(this.stepping);
							break;
						case 'slideup':
//							this.container.childNodes[this.previous_child].style.display = "none";
							this.SlideUpStep(this.stepping);
							break;
					}
					break;	// out of for loop
				}
			}
		}
	}
	catch(e) {
		window.status = e.description;
	}
}

// private: perform another step in the fadein transition
DivTransition.prototype.FadeInStep = function(opacity) {
	if (this.paused) {
		window.setTimeout(this.extref + '.FadeInStep(' + opacity + ')', 100);
		return;
	}

	try {
		var el = this.container.childNodes[this.child_index];
		this.SetOpacity(el, opacity);

		if (opacity == 0)
			el.style.display = "block";

		if (opacity < 100) {
			opacity = Math.min(opacity + this.steps, 100);
			window.setTimeout(this.extref + '.FadeInStep(' + opacity + ')', 100);
		}
		else {
			window.setTimeout(this.extref + '.LoopForward()', this.delay_ms);
		}
	}
	catch(e) {
		window.status = e.description;
	}
}

// private: perform another step in the slideup transition
DivTransition.prototype.SlideUpStep = function(offset) {
	if (this.paused) {
		window.setTimeout(this.extref + '.SlideUpStep(' + offset + ')', 100);
		return;
	}

	try {
		var el = this.container.childNodes[this.child_index];

		if (offset == 0) {
			el.style.display = "block";
			el.style.position = "relative";
			el.style.top = this.container.clientHeight + "px";
			el.style.left = "0px";
		}
		else {
			el.style.top = (this.container.clientHeight - offset) + "px";
		}

		// move the last child up as well
		if (this.previous_child != -1) {
			var lc = this.container.childNodes[this.previous_child]
			lc.style.top = (-offset) + "px";
		}

		if (offset < this.container.clientHeight) {
			offset = Math.min(offset + this.steps, this.container.clientHeight);
			window.setTimeout(this.extref + '.SlideUpStep(' + offset + ')', 50);
		}
		else {
			if (this.previous_child != -1) {
				this.container.childNodes[this.previous_child].style.display = "none";
			}
			window.setTimeout(this.extref + '.LoopForward()', this.delay_ms);
		}
	}
	catch(e) {
		window.status = e.description;
	}
}

// private: set opacity on a Mozilla browser
DivTransition.SetOpacityMoz = function(el, opacity) {
	opacity /= 100.0;
	el.style.opacity = opacity;
	el.style.MozOpacity = opacity;
}

// private: set opacity on a Microsoft browser
DivTransition.SetOpacityIE = function(el, opacity) {
	el.style.filter = "alpha(opacity=" + opacity + ")";
}
