/*******************************************************************************
 * Gateway variables & constants 
 *******************************************************************************/

/** VARIABLES */
var objectsReady = new Array();
var pageloaded = false;
var animateFlag = false;	// Currently, I don't think we use this anywhere.. not sure what it is for.
var uimode = 'explore';			// uimode - stores the name of the selected tab
//var my_window = window.open();

/** CONSTANTS */
var SOLID = 0;
var TRANS = 1;
var OFF   = 2;

var XMLChunks = '';

var notLoaded = true;

/*******************************************************************************
 * UI functions 
 *******************************************************************************/

/**
 * Provides a browser-accurate reference to an <object> referenced by ID.
 * @return reference to an <object>
 */
function thisMovie(movieName) 
{
	//var isIE = navigator.appName.indexOf("Microsoft") != -1;
	//return (isIE) ? window[movieName] : document[movieName];
	if (window.document[movieName]) 
	{
		return window.document[movieName];
	}
	if (navigator.appName.indexOf("Microsoft Internet")==-1)
	{
		if (document.embeds && document.embeds[movieName])
			return document.embeds[movieName]; 
	}
	else
	{
		return document.getElementById(movieName);
	}
}

/**
 * Using the objectsReady array, tracks the number of UI Flash files that are loaded 
 * and when that number meets or exceeds three the Unitymodule is loaded
 */
function markReady(objName)
{
	//alert("MARK READY CALLED WITH: " + objName);
	objectsReady.push(objName);
	checkReady();
}

function checkReady()
{
	if (objectsReady.length >= 4 && notLoaded)
	{
		//initGUI();
		//alert("BEFORE WE EMBED THE UNITY, WE HAVE: " + thisMovie("mainUI"));
		//alert("BEFORE WE EMBED THE UNITY, WE HAVE: " + thisMovie("statusUI"));
		//embedUnity('vb/3d/body.unity3d');
		//alert("Calling START PRESENTATION IN UNITY!");
		
		// Check to ensure that SendMessage and the SWFs exist before loading.
		if (typeof GetUnity().SendMessage != "undefined" && thisMovie("mainUI") && thisMovie("statusUI"))
		{
			notLoaded = false;
			GetUnity().SendMessage("LoadCheck", "startPresentation", "jsReady");
			//alert("Message sent successfully!");
		}
		else
		{
			//alert("For some reason, the browser doesn't see the Unity object yet!");
			setTimeout("markReady('delay')", 1000);
		}
		
		//alert("Made it past send message?");
		//setXML('<menu id="396">Body<g id="402" active="false" size="7582" lo="7">Circulatory (Cardiovascular) System</g><g id="404" active="false" size="1354" lo="2">Digestive System</g><g id="406" active="false" size="377" lo="5">Endocrine System</g><g id="400" active="false" size="1005" lo="11">Integumentary System</g><g id="408" active="false" size="398" lo="4">Lymphatic System</g><g id="410" active="false" size="5770" lo="9">Muscular System</g><g id="412" active="false" size="7774" lo="8">Nervous System</g><g id="414" active="false" size="565" lo="10">Reproductive System</g><g id="416" active="false" size="1101" lo="3">Respiratory System</g><g id="398" active="false" size="5660" lo="1">Skeletal System</g><g id="392" active="false" size="738" lo="6">Urinary System</g></menu>');
		
		//alert("Tried to load!");
	}
}

/**
 * Indicates that a particular plug-in has initialized and is ready to be interacted with
 * and requests applicable data, such as XML, from the plug-in. Currently, we only care about Unity.
 * @param plugname		short-hand indicating which plug-in has loaded.
 */
function pluginReady(plugname)
{
	switch (plugname)
	{
		case 'unity':
		//	setUnityFocus();
		//	initGUI();
		//	alert("called requestXML!");
		//	GetUnity().SendMessage("Body", "requestXML", plugname);
		//	alert("done with requestXML!");
			markReady("unity");
			break;
		default:
			// do nothing.
			break;
	}
}

/*******************************************************************************
 * UI -=> Unity Commands 
 *******************************************************************************/

/**
 * Selects a 3D object or group in Unity and updates the status bar.
 * @param inValue	id of a 3D object or group in Unity
 */
function uiSelectObject(inValue) 
{
	//alert(inValue);
	GetUnity().SendMessage("Body", "selectObjectByID", inValue);
	thisMovie("statusUI").selectObject(inValue);
}

/**
 * Deselects a 3D object or group in Unity and updates the status bar.
 * @param inValue	id of a 3D object or group in Unity
 */
function uiDeselectObject(inValue) 
{
	GetUnity().SendMessage("Body", "deselectObjectByID", inValue);
	thisMovie("statusUI").deselectObject(inValue);
}

/**
 * Deselects a 3D object or group in Unity and updates the status bar.
 * @param inValue	id of a 3D object or group in Unity
 */
function uiDeselectAll()
{
	GetUnity().SendMessage("Body", "deselectAll", "all");
	thisMovie("statusUI").deselectAll();
}

/**
 * Updates the visibility of a 3D object or group in Unity to match that
 * of the item changed in a UI module.
 * @param inValue		an ID of a 3D object or group in Unity
 * @param visConstant	0, 1, or 2. 0 = solid, 1 = transparent, 2 = hidden/off.
 */
function uiSetObjectVisibility(inValue, visConstant)
{
	switch (visConstant)
	{		
		case OFF:
			GetUnity().SendMessage("Body", "hideObjectByID", inValue);
			break;
			
		case TRANS:
			GetUnity().SendMessage("Body", "transparentObjectByID", inValue);
			break;
			
		case SOLID:
			GetUnity().SendMessage("Body", "showObjectByID", inValue);
			break;
			
		default: break;
	}
}

function uiHideOthers(inValue)
{
	GetUnity().SendMessage("Body", "hideOthersByID", inValue);
}

function uiUserLoad(inValue)
{
	GetUnity().SendMessage("Body", "userActivate", inValue);
}

function jaredAlert(inValue)
{
	//my_window.document.write(inValue + "<br>");
	alert(inValue);
}

/**
 * Tells Unity to select and zoom in on the object or group matching in the ID provided
 * and updates the status bar. The zoom animation will first zoom out to the 'reset view' 
 * before zooming in to provide visual context.
 * @param inValue	id of a 3D object or group in Unity
 */
function uiZoomSelectObject(inValue) 
{
	animateFlag = true;
	GetUnity().SendMessage("Body", "deselectAll", "all");
	GetUnity().SendMessage("Body", "selectObjectByID", inValue);
	GetUnity().SendMessage("Body", "zoomObjectByID", inValue);
	
	thisMovie("statusUI").deselectAll();
	thisMovie("statusUI").selectObject(inValue);
}

/**
 * Tells Unity to zoom in on, but not select the object or group matching in the ID provided. 
 * The zoom animation will first zoom out to the 'reset view' before zooming in to provide visual context.
 * @param inValue	id of a 3D object or group in Unity
 */
function uiZoomObject(inValue) 
{
   animateFlag = true;
   GetUnity().SendMessage("Body", "zoomObjectByID", inValue);
}

// Send keyboard input from UI to Unity.
function uiKeys(inValue)
{
	//alert("UI KEYS CALLED WITH: " + inValue);
	GetUnity().SendMessage("Body", "updateKeyFocus", inValue);
	//alert("Go through function! " + inValue);
	//document.getElementById('anarkPlayer').internalCommand('flashKeys', inValue );
}

/* Performs double-click functionality from the status bar.  Tells Unity to zoom in.
 */
function sbDoubleClick(inValue) 
{
	animateFlag = true;

	GetUnity().SendMessage("Body", "deselectAll", "all");
	GetUnity().SendMessage("Body", "selectObjectByID", inValue);
	GetUnity().SendMessage("Body", "zoomObjectByID", inValue);
	
	thisMovie("statusUI").deselectAll();
	thisMovie("statusUI").selectObject(inValue);
	thisMovie("mainUI").selectObject(inValue);
	
	//GetUnity().SendMessage("Body", "zoomObjectByID", inValue);
} 

/* Performs single-click functionality from the status bar.  Selects the object and updates menu
 * accordingly. 
 */
function sbSelect(inValue)
{
	thisMovie("mainUI").selectObjectAndChildren(inValue);
	thisMovie("statusUI").selectObject(inValue);
}

function unitySelectedObject(value)
{
	/*if (animateFlag == true)
		thisMovie("mainUI").selectObjectAndChildren(value);
	else */
	thisMovie("mainUI").selectObject(value);
	thisMovie("statusUI").selectObject(value);
	animateFlag = false;
}

function unityDeselectObject(value) 
{
	thisMovie("mainUI").deselectObject(value);
	if (value == "all") thisMovie("statusUI").deselectAll();
	else thisMovie("statusUI").deselectObject(value);
}

function setXML(xml_str)
{
	//alert("BEFORE WE SET THE XML, WE HAVE: " + thisMovie("statusUI").setData);
	//alert("BEFORE WE SET THE XML, WE HAVE: " + thisMovie("mainUI").setData);
	
	thisMovie('statusUI').setData(xml_str);
	thisMovie('mainUI').setData(xml_str);
	uiUpdate('setXML');
	//my_window = window.open();
	//my_window.document.write(xml_str);
	/*if (thisMovie('mainUI').setData)
	{
		alert("SET XML: " + xml_str);
		thisMovie('statusUI').setData(xml_str);
		thisMovie('mainUI').setData(xml_str);
	}
	else
	{
		alert("FUNCTION IS NOT YET DEFINED!");
	}*/
	//alert("FINISHED SET XML!");
}

function chunkXML(str_part)
{
	XMLChunks = XMLChunks + str_part;
	GetUnity().SendMessage("Body", "chunkXMLCallback", "placeholder");
}

/**
 * The visibility of an object or group has been changed in Unity; 
 * tells the UI modules to update any corresponding UI elements.
 * @param value			an ID of a 3D object or group ID in Unity
 * @param visConstant	0, 1, or 2. 0 = solid, 1 = transparent, 2 = hidden/off.
 */

function unitySetObjectVisibility(value, visConstant)
{
	//alert("USOV: " + value + ", " + visConstant);
	thisMovie("mainUI").setVisibility(value, visConstant);
}

function unityGetVisibility(value, notVis)
{
	var visConstant = thisMovie("mainUI").getVisibility(value);
	
	var retStr = value + "," + visConstant + "," + notVis;
	GetUnity().SendMessage("Body", "getVisibilityCallback", retStr);
}

function unityZoomGetVisibility(value, sysIndex)
{
	var visConstant = thisMovie("mainUI").getVisibility(value);
	var retStr = sysIndex + "," + visConstant;

	GetUnity().SendMessage("Body", "zoomGetVisibilityCallback", retStr);
}

function unityHide(value)
{
	thisMovie("mainUI").hideSelectedObjects();
}

function unityShow(value)
{
	thisMovie("mainUI").showSelectedObjects();
}

function unityTransparent(value)
{
	thisMovie("mainUI").transparentSelectedObjects();
}

function unityShowAll(value)
{
	thisMovie("mainUI").setVisibilityAll(0);
}

function unityHideOthers(value)
{
	thisMovie("mainUI").hideOtherObjects();
}

function contextualSearch(string, parameter, engine)
{
	switch (engine)
	{
		case "google": //Google
				//window.open("http://www.google.com/search?hl=en&q=" + string + "&btnG=Google+Search");
				openWindow("http://www.google.com/search?hl=en&q=" + string + " " + parameter + "&btnG=Google+Search");
				break;
		case "webmd": //WebMD
				openWindow("http://www.webmd.com/search/search_results/default.aspx?query=" + string + " " + parameter  + "&sourceType=undefined");
				break;
		case "msn": //MSN
				openWindow("http://search.msn.com/results.aspx?q=" + string + " " + parameter  + "&FORM=MSNH");
				break;
		case "wikipedia": //Wikipedia
				openWindow("http://en.wikipedia.org/wiki/Special:Search?search=" + string + " " + parameter  + "&go=Go");
				break;
		default: break;
	}
}

function openWindow(url)
{
	var newWin = window.open(url)
	if( !newWin )
	{
		alert("Stop trying to protect me Safari!  I clicked a button!");
		newWin = window.open('', "newWin");
		alert(newWin);
		newWin.location.href = url;
	}
}

function appendXML(str_part)
{
	var glob_str = XMLChunks + str_part;

	XMLChunks = '';
	
	var dataArray = glob_str.split('$$');
	var id_str = dataArray[0];
	var xml_str = dataArray[1];
	
	//my_window.document.write(xml_str);
	thisMovie('statusUI').appendData(id_str, xml_str);
	thisMovie('mainUI').appendData(id_str, xml_str);
}

/**
 * A duplicate object has been selected in Unity; highlight the item in the Flash menu.
 * Do not update the status bar, and do not open the Flash menu to the duplicate item.
 * @param value		an ID of a 3D object or group ID in Unity
 */
function unitySelectDupe(value) 
{
	thisMovie("mainUI").selectDupe(value);
};

/**
 * A duplicate object has been deselected in Unity; deselect any corresponding UI elements in the UI modules.
 * @param value		an ID of a 3D object or group ID in Unity
 */
function unityDeselectDupe(value) 
{
	thisMovie("mainUI").deselectDupe(value);
};

/**
 * The load status of an Unity components has changed; update the UI elements.
 * States: 0 = not loaded, 1 = loading, 2 = loaded, -1 = error.
 * @param value		a string of ID/state pairs separated by commas. for example, "51103,1,51033,2";
 */
function setLoadState(value)
{
	//alert("IN SET LOADSTATE WITH VALUE: " + value);
	var pairs = value.split(',');
	for (i = 0; i < pairs.length; i += 2)
		thisMovie('mainUI').setLoadState(pairs[i], pairs[i + 1]);
}

/**
 * The Unity module has been reset; reset all UI modules.
 */
function unityReset() 
{
	thisMovie("mainUI").reset();
	thisMovie("mainUI").resetSearch();
	thisMovie("statusUI").deselectAll();
};

// Set the focus to the Unity player.
function setUnityFocus()
{
	parent.parent.focus();
	GetUnity().focus();
}

/*******************************************************************************
 * Helper functions 
 *******************************************************************************/

function stringToNumber(initialInput, unitStr)
{
	var initialStr = String(initialInput);
	var numStr = Number(initialStr.substring(0, initialStr.length - unitStr.length));
	return numStr;
}

/**
 * Updates the UI modules to reflect the current mode.
 */
function uiUpdate(str) 
{
	//alert("uiUpdate called by: " + str);
	thisMovie('mainUI').setMode(uimode);
};

// Add functions for handling mouse wheel; apparently the OS X Flash Player does not
// handle Flash's onMouseWheel event so we need to catch it in the JS.
function handle(delta) {
   	thisMovie('mainUI').flashScroll(delta);
}

function wheel(event){
	var delta = 0;
	var wheelTarget;

    if (!event) event = window.event;
    if (event.wheelDelta) {
		delta = event.wheelDelta / 240; 
        if (window.opera) delta = -delta;
    } else if (event.detail) {
		delta = -event.detail / 3;
    }
	
	// Find the target of the wheel event.
	if (event.target)
		wheelTarget = event.target;
	else if (event.srcElement)
		wheelTarget = event.srcElement;

	/*alert(event.clientX + ", " + event.clientY + " < " + mainUI_w + ", " + mainUI_h + "; " + mouseX + ", " + mouseY);
    if (delta && event.clientX <= mainUI_w && event.clientY <= mainUI_h)*/
	// Check the target of the wheel event before doing anything; if it is then we want Flash to scroll (otherwise not).
	if (delta && wheelTarget == thisMovie('mainUI'))
        handle(delta);
}

var upOutside = false;

function mouseUpOutsideUnity(inValue)
{
	//alert("here with: " + inValue);
	if (!notLoaded)
	{
		GetUnity().SendMessage("Body", "manualMouseUp", inValue);
		upOutside = true;
	}
}

function mouseUp()
{
	mouseUpOutsideUnity("js");
}

function mouseDown(event)
{
	if (upOutside)
	{
		GetUnity().SendMessage("Body", "manualMouseDown", "js");
	}
	
	upOutside = false;
	
	if (!event) event = window.event;
	
}

function synthesizeMouseUp(event)
{
	if (!event.relatedTarget)
	{
		//mouseUp();
		document.getElementById('dLogo').focus();
	}
}

if (window.addEventListener)
{
	// Wheel for Firefox.
	window.addEventListener('DOMMouseScroll', wheel, false);
	
	// Wheel for Safari.
	window.onmousewheel = wheel;
	
	//window.addEventListener('mouseout', synthesizeMouseUp, true);
	window.onmouseup = mouseUp;
	window.onmousedown = mouseDown;
}
else
{
	// Wheel for IE.
	document.onmousewheel = wheel;
	
	document.onmouseup = mouseUp;
	document.onmousedown = mouseDown;
}
