// Interval (ms) for setInterval calls -- doesn't matter that much because
// the changes are done according to the amount of time that has elapsed.
var swfxStepInterval = 50;

// Duration (ms) for things; if greater than 500, funny things might happen
// if something gets told to fade twice very quickly
var swfxDefaultDuration = 500;

// this time-position, sinoidal transition thing is from script.aculo.us
// via moofx
// Note that this version is set up to return integers only
function SinVal(from, to, now, startTime, duration) {
	var Tpos = (now - startTime) / (duration);
	return Math.round(((-Math.cos(Tpos*Math.PI)/2) + 0.5) * (to - from) + from);
}


// ****************************************************
// Expanding in/out

// Have to pass in the ids of the image and the enclosing div
function ResizeTo(did, iid, widthTo, heightTo, duration, postFn) {
	// Get the elements; if we can't find it, return
	var el = document.getElementById(did);
	if (el == null) {
		return;
	}
	var eli = document.getElementById(iid);
	if (eli == null) {
		return;
	}
	
	// use default duration if none given
	if (duration == null) {
		duration = swfxDefaultDuration;
	}
	
	// Clear the expansionTimer if it's already running
	if (el.expansionTimer != null) {
		clearInterval(el.expansionTimer);
		el.expansionTimer = null;
	}

	// If width and height have already reached where we're going, nothing to do
	if (eli.width == widthTo && eli.height == heightTo) {
		return;
	}
	
	// If this is the first time the fn is called, check to see which way
	// we have to resize -- from the right or left / top or bottom
	if (el.cornerFrom == null) {
		// Get window size -- from quirksmode.com
		// won't work in explorer mac, but who cares?
		var screenW = document.body.scrollWidth;
		var screenH = document.body.scrollHeight;
		
		// Get absolute position of left and top of image
		var divLeft = findPosX(el);
		var divTop = findPosY(el);
		
		// If when we resize the image its right side would be too far right,
		// resize from the right side
		if ((divLeft + widthTo) >= (screenW * .85)
			|| (divLeft + widthTo) >= (screenW - 25)) {
			el.cornerFrom = "r";
			// Also store where the right corner should be
			// Here we want the item's relative left, 
			// since we're going to use this to reposition it
			el.cornerRPos = RemovePx(el.style.left) + eli.width;
		} else {
			el.cornerFrom = "l";
		}

		// If when we resize the image its bottom side would be too far down,
		// resize from the bottom side
		if (((divTop + heightTo) >= (screenH * .90)
			|| (divTop + heightTo) >= (screenH - 25))
			&& ((divTop - heightTo) > 10)) {		// 
			el.cornerFrom += "b";
			// Also store where the bottom corner should be
			// Here we want the item's relative left, 
			// since we're going to use this to reposition it
			el.cornerBPos = RemovePx(el.style.top) + eli.height;
		} else {
			el.cornerFrom += "t";
		}
	}

	el.widthFrom = eli.width;
	el.widthTo = widthTo;
	el.heightFrom = eli.height;
	el.heightTo = heightTo;
	el.resizeStartTime = (new Date).getTime();
	el.resizeDuration = duration;
	el.resizeTimer = setInterval("Resize('" + did + "','" + iid + "')", swfxStepInterval);
	el.resizePostFn = postFn;
}

function Resize(did, iid) {
	var el = document.getElementById(did);
	if (el == null) {
		return;
	}
	var eli = document.getElementById(iid);
	if (eli == null) {
		return;
	}
		
	// Update size
	// The following adapted from moofx.mad4milk.net
	var now = (new Date).getTime();
	var newWidth, newHeight;
	var doPostFn = false;
	if (now >= el.resizeStartTime + el.resizeDuration) {
		newWidth = el.widthTo;
		newHeight = el.heightTo;
		clearInterval(el.resizeTimer);
		el.resizeTimer = null;
		doPostFn = true;
	} else {
		newWidth = SinVal(el.widthFrom, el.widthTo, now, el.resizeStartTime, el.resizeDuration);
		newHeight = SinVal(el.heightFrom, el.heightTo, now, el.resizeStartTime, el.resizeDuration);
	}
	eli.width = newWidth;
	eli.height = newHeight;

	
	// If we're resizing from the right, update position
	if (el.cornerFrom.substr(0,1) == "r") {
		// Move to el.cornerRPos - width
		el.style.left = (el.cornerRPos - newWidth) + "px";
	}

	// If we're resizing from the bottom, update position
	if (el.cornerFrom.substr(1,1) == "b") {
		// Move to el.cornerRPos - width
		el.style.top = (el.cornerBPos - newHeight) + "px";
	}

	if (doPostFn && el.resizePostFn != null) {
		eval(el.resizePostFn);
		el.resizePostFn = null;
	}
}


// ****************************************************
// Slide something out in any direction
// Here we assume you want to slide until the top is one pixel lower than what was
// the bottom (assuming you're going down)

// Important Note: we're sliding a div here, and the width/height of the div must
// be set in the style attribute of the div.  Also, you can't use padding in the
// div that you're sliding.  (You could enclose another div that does have padding.)

function SlideOut(direction, id, duration, postFn) {
	// Get the element; if we can't find it, return
	var el = document.getElementById(id);
	if (el == null) {
		return;
	}
	
	// use default duration if none given
	if (duration == null) {
		duration = swfxDefaultDuration;
	}
	
	// Clear the slideTimer if it's already running
	if (el.slideTimer != null) {
		clearInterval(el.slideTimer);
		el.slideTimer = null;
	}
	
	// Get the current value of left, top, width, height
	var width = RemovePx(el.style.width);
	var height = RemovePx(el.style.height);
	var curLeft = RemovePx(el.style.left);
	var curTop = RemovePx(el.style.top);
	
	// If we haven't yet set the original top/left, do so
	if (el.origTop == null) {
		el.origTop = curTop;
		el.origLeft = curLeft;
	}
	
	// If we've already reached where we're going, nothing to do
	if (curTop == el.topTo && curLeft == el.leftTo) {
		return;
	}
	
	el.leftFrom = curLeft;
	el.topFrom = curTop;
	
	// Set topTo and leftTo, depending on direction
	if (direction == "down") {
		el.topTo = el.origTop + height;
		el.leftTo = curLeft;
	} else if (direction == "up") {
		el.topTo = el.origTop - height;
		el.leftTo = curLeft;
	} else if (direction == "right") {
		el.topTo = curTop;
		el.leftTo = el.origLeft + width;
	} else if (direction == "left") {
		el.topTo = curTop;
		el.leftTo = el.origLeft - width;
	}
	
	el.slideStartTime = (new Date).getTime();
	el.slideDuration = duration;
	el.slideTimer = setInterval("Slide('" + id + "')", swfxStepInterval);
	el.slidePostFn = postFn;
}

function SlideBack(id, duration, postFn) {
	// Get the element; if we can't find it, return
	var el = document.getElementById(id);
	if (el == null) {
		return;
	}

	// If we don't have an origTop are null, we haven't slid TO anywhere yet
	if (el.origTop == null) {
		return;
	}
	
	// use default duration if none given
	if (duration == null) {
		duration = swfxDefaultDuration;
	}
	
	// Clear the slideTimer if it's already running
	if (el.slideTimer != null) {
		clearInterval(el.slideTimer);
		el.slideTimer = null;
		if (el.slidePostFn != null) {
			eval(el.slidePostFn);
			el.slidePostFn = null;
		}
	}

	// Get the current value of left, top, width, height
	var width = RemovePx(el.style.width);
	var height = RemovePx(el.style.height);
	var curLeft = RemovePx(el.style.left);
	var curTop = RemovePx(el.style.top);
	
	// Slide back to what was leftFrom/topFrom
	el.leftTo = el.origLeft;
	el.topTo = el.origTop;
	el.leftFrom = curLeft;
	el.topFrom = curTop;

	el.slideStartTime = (new Date).getTime();
	el.slideDuration = duration;
	el.slideTimer = setInterval("Slide('" + id + "')", swfxStepInterval);
	el.slidePostFn = postFn;
}

function Slide(id) {
	// Get the element; if we can't find it, return
	var el = document.getElementById(id);
	if (el == null) {
		return;
	}
	
	// Update position
	// The following adapted from moofx.mad4milk.net
	var now = (new Date).getTime();
	var newLeft, newTop;
	var doPostFn = false;
	if (now >= el.slideStartTime + el.slideDuration) {
		newLeft = el.leftTo;
		newTop = el.topTo;
		el.leftTo = el.topTo = null;
		clearInterval(el.slideTimer);
		el.slideTimer = null;
		doPostFn = true;
	} else {
		newLeft = SinVal(el.leftFrom, el.leftTo, now, el.slideStartTime, el.slideDuration);
		newTop = SinVal(el.topFrom, el.topTo, now, el.slideStartTime, el.slideDuration);
	}
	el.style.left = newLeft + "px";
	el.style.top = newTop + "px";

	if (doPostFn && el.slidePostFn != null) {
		eval(el.slidePostFn);
		el.slidePostFn = null;
	}
}


// ****************************************************
// Fading in/out

// ****** Public functions ***********
function FadeTo(id, level, duration, postFn) {
	StartFade(id, level, duration, postFn);
}

function FadeIn(id, duration, postFn) {
	// Fade to 100
	StartFade(id, 100, duration, postFn);
}

function FadeOut(id, duration, postFn) {
	// Fade to 0
	StartFade(id, 0, duration, postFn);
}

// ****** Private functions follow **********

// Sets up necessary object properties if they don't yet exist,
// then returns the DOM element
function InitializeForFading(id) {
	var el = document.getElementById(id);
	if (el == null) {
		return null;
	}
	
	// If the element's alpha property is already set, assume it's already
	// been initialized, so return it
	if (el.alpha != null) {
		return el;
	}
	
	// If element's visibility is set to none, assume its alpha is 0
	if (el.style.visibility == "hidden") {
		el.alpha = 0;
	
	// Otherwise assume its alpha is 100
	} else {
		el.alpha = 100;
	}
	
	return el;
}

function StartFade(id, alphaTo, duration, postFn) {
	// Get the element; if we can't find it, return
	var el = InitializeForFading(id);
	if (el == null) {
		return;
	}
	
	// use default duration if none given
	if (duration == null) {
		duration = swfxDefaultDuration;
	}
	
	// Clear the alphaTimer if it's already running
	if (el.alphaTimer != null) {
		clearInterval(el.alphaTimer);
		el.alphaTimer = null;
	}

	// If alpha has already reached where we're going, nothing to do
	if (el.alpha == alphaTo) {
		return;
	}

	el.alphaFrom = el.alpha;
	el.alphaTo = alphaTo;
	el.alphaStartTime = (new Date).getTime();
	el.alphaDuration = duration;
	el.alphaTimer = setInterval("Fade('" + id + "')", swfxStepInterval);
	el.alphaPostFn = postFn;
}

function Fade(id) {
	var el = InitializeForFading(id);
	if (el == null) {
		return;
	}
	
	// Update alpha
	// The following adapted from moofx.mad4milk.net
	var now = (new Date).getTime();
	var doPostFn = false;
	if (now >= el.alphaStartTime + el.alphaDuration) {
		el.alpha = el.alphaTo;
		clearInterval(el.alphaTimer);
		el.alphaTimer = null;
		doPostFn = true;
	} else {
		el.alpha = SinVal(el.alphaFrom, el.alphaTo, now, el.alphaStartTime, el.alphaDuration);
	}
	
	// Set the new alpha
	SetAlpha(el);

	if (doPostFn && el.alphaPostFn != null) {
		eval(el.alphaPostFn);
		el.alphaPostFn = null;
	}
}

function SetAlpha(el) {
	// If el is hidden and alpha is > 0, show it
	if (el.alpha > 0 && el.style.visibility == "hidden") {
		el.style.visibility = "visible";
	}
	
	// If alpha is 0, hide el
	if (el.alpha == 0) {
		el.style.visibility = "hidden";
	}
	
	var alphaVal = el.alpha;
	// Firefox flickers if we get all the way to 100
	if (alphaVal == 100) {
		alphaVal = 99.99;
	}
	
	// Set the filter (for IE) - 0 to 100
	if (window.ActiveXObject) {
		el.style.filter = "alpha(opacity=" + alphaVal + ")";
	}
	
	// Set the opacity element (for Mozilla and Safari) - 0 to 1
	el.style.opacity = (alphaVal/100);
}

// Utility functions
function RemovePx(s) {
	var pxPos = s.indexOf("px");
	if (pxPos != -1) {
		s = s.substring(0, pxPos);
	}
	return s * 1;
}

// Find absolute position of an object on the screen -- from quirksmode
function findPosX(obj) {
	var curleft = 0;
	if (obj.offsetParent) {
		while (obj.offsetParent) {
			curleft += obj.offsetLeft
			obj = obj.offsetParent;
		}
	}
	return curleft;
}

function findPosY(obj) {
	var curtop = 0;
	if (obj.offsetParent) {
		while (obj.offsetParent) {
			curtop += obj.offsetTop
			obj = obj.offsetParent;
		}
	}
	return curtop;
}