
var debugDiv = null;

var request = null;
var contentDIV = null;

var hotButtonId = null;
var hotOnMouseOver = null;
var hotOnMouseOut = null;



// ---- AJAX Navigation Functions ----

/**
 * Function to start navigation.
 * @param url The URL to navigate to.
 * @param objID The object to set as the "hot" button.
 * @param external true if using an external URL, false for an internal URL.
 * 		Internal URLs navigate using AJAX.
 * @return true when the browser should navigate, false when we are taking care of it
 */
function mainNavigate(url, objID, external)
{
	if (external == null)
	{
		external = false;	
	}
	
	if (request == null)
	{
		request = new AJAXRequest();
	}
	
	if (contentDIV == null)
	{
		contentDIV = document.getElementById('mainContent');
		if (contentDIV == null)
		{
			// can't go any further, allow the browser to navigate
			return true;
		}
	}
	
	setHotButton(objID);
	
	setLoadingBoxDimensions();	
	
	// "splash" whatever was clicked on
	splash(objID, 5, 5, true, null, 0, 0);
	
	var callback = function () { doMainNavigate(url, external); };
	return !fadeIn('loadingBox', callback);
}

/**
 * Function to perform the navigation.
 * @param url The URL to navigate to.
 * @param external true if using an external URL, false for an internal URL.
 * 		Internal URLs navigate using AJAX.
 */
function doMainNavigate(url, external)
{
	if (external)
	{
		// just navigate to the URL
		window.location.href = url;
	}
	else
	{
		// perform the AJAX request for new page
		var callback = function(response){ onMainNavigateComplete(response) }
		request.doGet(callback, url);
	}
}

/**
 * Called when the main navigation methods are finished.
 * Extracts data and populates it into the page.  Fades out the "loading" box when finished.
 * @param response The XML response.
 */
function onMainNavigateComplete(response)
{
	// extract the data from the XML
	var titleNodes = response.getElementsByTagName('title');
	var contentNodes = response.getElementsByTagName('body');
	
	// put the data into the page
	if (titleNodes != null && titleNodes[0].firstChild != null)
	{
		document.title = titleNodes[0].firstChild.nodeValue;
	}
	if (contentNodes != null && contentNodes[0].firstChild != null)
	{
		contentDIV.innerHTML = contentNodes[0].firstChild.nodeValue;
	}

	// hide the loading div
	fadeOut('loadingBox', null, true);
	
	setLoadingBoxDimensions();
}

function setLoadingBoxDimensions()
{
	var obj = document.getElementById('loadingBox');
	if (obj != null && contentDIV != null)
	{
		var width = contentDIV.offsetWidth + "px";
		obj.style.width = width;

		var heightComp = 0;

		// IE has a slightly different style offset than everything else
		if( navigator.appName != "Microsoft Internet Explorer")
		{
			heightComp = 15;
		}


		var height = contentDIV.offsetHeight + heightComp + "px";
		obj.style.height = height;	
	}
}


/**
 * Sets the provided object ID as the "hot" button.
 * If there is a previous "hot" button it is set to normal.
 * @param obj The object to set as the "hot" button.
 */
function setHotButton(objID)
{
	// re-set the old button
	if (hotButtonId)
	{
		var obj = document.getElementById(hotButtonId);
		
		obj.onmouseover = hotOnMouseOver;
		obj.onmouseout = hotOnMouseOut;
		
		fadeOut(hotButtonId);
	}
	
	// configure the current button
	obj = document.getElementById(objID);
	if (obj)
	{
		hotButtonId = objID;
		hotOnMouseOver = obj.onmouseover;
		hotOnMouseOut = obj.onmouseout;
				
		obj.onmouseover = null;
		obj.onmouseout = null;
		
		obj.opacity = 100;
		
		fadeIn(objID);
	}
}

// ---- Animation Functions ----

/**
 * Generates a "splash" effect on the provided object ID.
 * @param objID The ID of the object to splash.
 * @param rate The speed that the object grows.
 * @param steps The number of frames that the animation should be.
 * @param fade true to fade out while expanding.
 * @param onFinish A function to call when the animation is finished.
 * @param specialX How many pixels of horizontal position compensation.
 * @param specialY How many pixels of vertical position compensation.
 */
function splash(objID, rate, steps, fade, onFinish, specialX, specialY)
{
	var result = false;

	var obj = document.getElementById(objID);
	
	if (obj)
	{
		// get the current screen position
		var origPos = findPos(obj);
		
		// duplicate this object so that we can mess with it
		var objAnimID = objID + '_anim';
		var objAnim = obj.cloneNode(true);
		objAnim.id = objAnimID;
		obj.parentNode.appendChild(objAnim);
		objAnim = document.getElementById(objAnimID);

		objAnim.animSteps = steps;
		objAnim.animExpandRate = rate;
		
		if (objAnim.style.width == "")
		{
			var width = objAnim.offsetWidth + "px";
			objAnim.style.width = width;
		}
		if (objAnim.style.height == "")
		{
			var height = objAnim.offsetHeight + "px";
			objAnim.style.height = height;
		}
		if (objAnim.style.left == "")
		{
			var left = origPos[0] - specialX + "px";
			objAnim.style.left = left;
		}
		if (objAnim.style.right == "")
		{
			var top = origPos[1] - specialY + "px";	
			objAnim.style.top = top;
		}
		
		objAnim.animExpandRatio = parseInt(objAnim.style.width) / parseInt(objAnim.style.height);
		objAnim.animOnFinish = onFinish;

		objAnim.animFade = fade;
		if (fade)
		{
			objAnim.opacity = 100;
			objAnim.animFadeRate = Math.ceil(100 / steps);
			setOpacity(objAnim);
		}

		objAnim.style.visibility = "visible";
		objAnim.style.zIndex = 2;
		objAnim.style.position = "absolute";
		
		
		objAnim.onmouseover = null;
		objAnim.onmouseout = null;
		
		
		objAnim.interval = window.setInterval( function() { doSplash(objAnim) }, 30);

		result = true;
	}
	else
	{
		// couldn't do the animation, give onFinish a call anyway
		if (onFinish != null)
		{
			onFinish();
		}
		result = true;
	}
	
	return result;
}

/**
 * Perform splash operations based off of parameters attached to the provided object.
 * @param obj The object to splash.
 */
function doSplash(obj)
{
	
	var width = parseInt(obj.style.width) + Math.ceil((obj.animExpandRate * obj.animExpandRatio)) + "px";
	var height = parseInt(obj.style.height) + obj.animExpandRate + "px";
	
	var left = parseInt(obj.style.left) - Math.ceil((obj.animExpandRate * obj.animExpandRatio) / 2) + "px";
	var top = parseInt(obj.style.top) -  Math.ceil(obj.animExpandRate / 2) + "px";
	
	obj.style.width = width;
	obj.style.height = height;
	
	obj.style.left = left;
	obj.style.top = top;

	if (obj.animFade)
	{
		obj.opacity -= obj.animFadeRate;
		setOpacity(obj);
	}


	obj.animSteps--;
	if (obj.animSteps <= 0)
	{
		window.clearInterval(obj.interval);

		if (obj.animOnFinish != null)
		{
			obj.animOnFinish();	
		}
		
		obj.parentNode.removeChild(obj);
	}
}


/**
 * Fade in and object.
 * @param objId The ID of the object to fade in.
 * @param callback A function to call when finished.
 */
function fadeIn(objId, callback)
{
	var result = false;
	
    var obj = document.getElementById(objId);
	
	if (obj)
	{
		obj.style.visibility = 'visible';
		
		if (obj.interval != null)
		{
			window.clearInterval(obj.interval);
			obj.interval = null;
			if (obj.callback != null)
			{
				obj.callback();	
			}
		}
		
		obj.callback = callback;
		
		if (!obj.opacity)
		{
			obj.opacity = 0;
			setOpacity(obj);
		}

		obj.hide = false;
		
		obj.interval = window.setInterval( function() { doFade(obj, 40); }, 50);
		
		result = true;
	}
	else
	{
		if (callback != null)
		{
			callback();
		}
		
		result = true;
	}
	
	return result;
}

/**
 * Fade out an object.
 * @param objID The ID of the object to fade out.
 * @param callback A function to call when finished.
 * @param hide true to hide the object when finished.
 */
function fadeOut(objId, callback, hide)
{
	var result = false;
	
    var obj = document.getElementById(objId);
	
	if (obj)
	{
		if (obj.interval != null)
		{
			window.clearInterval(obj.interval);
			obj.interval = null;
			if (obj.callback != null)
			{
				obj.callback();	
			}			
		}
		
		obj.callback = callback;
		if (obj.hide != null)
		{
			obj.hide = hide;
		}
		else
		{
			obj.hide = false;	
		}
		
		if (obj.opacity)
		{
			obj.interval = window.setInterval( function() { doFade(obj, -20); }, 50);
		}
		
		result = true;
	}
	else
	{
		if (callback != null)
		{
			callback();
		}
		
		result = true;
	}
	
	return result;
}


/**
 * Function on an interval to perform the fade operation.
 * @param obj The object to fade.  Must have the properties: "opacity", "interval"
 * @param amount The amount to fade by.
 */
function doFade(obj, amount)
{
	obj.opacity += amount;
	
	if (obj.opacity > 100)
	{
		window.clearInterval(obj.interval);
		obj.interval = null;

		obj.opacity = 100;
	}
	else if (obj.opacity < 0)
	{
		window.clearInterval(obj.interval);
		obj.interval = null;				
		
		obj.opacity = 0;
	}
	
	if (obj.interval == null)
	{
		if (obj.callback != null)
		{
			obj.callback();	
		}
		
		if (obj.hide)
		{
			obj.style.visibility = 'hidden';
		}
		
	}
		
	setOpacity(obj);
}

/**
 * Sets the opacity of the provided DOM object.
 * @param obj The object to set the opacity of.
 */
function setOpacity(obj)
{
	var opacity = obj.opacity;
  
	// IE/Win
	obj.style.filter = "alpha(opacity:"+opacity+")";

	// prevent divide by zero errors
	opacity = (obj.opacity == 100)?99.999:obj.opacity;

	// Safari<1.2, Konqueror
	obj.style.KHTMLOpacity = opacity/100;
	
	// Older Mozilla and Firefox
	obj.style.MozOpacity = opacity/100;
	
	// Safari 1.2, newer Firefox and Mozilla, CSS3
	obj.style.opacity = opacity/100;
}


/**
 * Finds the X/Y position (top/left corner) of the provided DOM object.
 * @param obj The object to get the position of.
 * @return An array [x, y]
 */
function findPos(obj)
{
	var curleft = 0;
	var curtop = 0;
	
	if (obj.offsetParent) {
		do {
			curleft += obj.offsetLeft;
			curtop += obj.offsetTop;
		} while (obj = obj.offsetParent);
	}
	return [curleft,curtop];
}

