var g_arrWorkspaces = new Array();
var g_xtActiveWorkspace;
var g_strCookieID;
var loadFromCookie = true;

function function1(obj)
{
	//message(getStyleClassProperty(obj.className, "behavior"), true);
}

/// <summary>
/// Registers the containers on the page into the global container registration
/// </summary>
/// <param name="strID">The ID of said container</param>
function registerContainer(strWorkspaceID, strContainerID) 
{
	var intIndex = getWorkspaceIndexByID(strWorkspaceID)
	if(intIndex == null)
		intIndex = createNewWorkspace(strWorkspaceID);
		
	var obj = eval("g_doc." + strContainerID);
	
	var xtContainer = new XTContainerObject();
	xtContainer.ID = strContainerID;
	xtContainer.workspaceID = strWorkspaceID;
	xtContainer.container = obj;
	
	g_arrWorkspaces[intIndex].containers.push(xtContainer);
}

function scrollWindow(intPace)
{
	window.document.body.scrollTop += intPace;
}

/// <summary>
/// Creates a workspace object and adds it to the global collection of workspaces
/// </summary>
function createNewWorkspace(strID)
{
	var xtWorkspace = new XTWorkspaceObject();
	xtWorkspace.ID = strID;
	
	xtWorkspace.containers = new Array();
	g_arrWorkspaces.push(xtWorkspace);
	return (g_arrWorkspaces.length - 1);
}

/// <summary>
/// Stores data about each workspace
/// </summary>
function XTWorkspaceObject()
{
	var ID = null;
	var containers = null;
}

/// <summary>
/// Stores data about each container
/// </summary>
function XTContainerObject()
{
	var ID = null;
	var left = null;
	var top = null;
	var width = null;
	var height = null;
	var frames = null;
	var workspaceID = null;
	var container = null;
}

/// <summary>
/// Stores data about each frame
/// </summary>
function XTFrameObject()
{
	var ID = null;
	var left = null;
	var top = null;
	var width = null;
	var height = null;
	var containerID = null;
	var collapsed = null;
	var expanded = null;
	var index = null;
	var frame = null;
}

/// <summary>
/// Gathers position data about each container after all containers have
/// been registered
/// </summary>
/// <param name="blnInitialLoad">True if this data is being gathered for the first time</param>
function gatherContainerSpecs(blnInitialLoad)
{
	//message("Total Workspaces: " + g_arrWorkspaces.length);
	for(var k = 0; k < g_arrWorkspaces.length; k++)
	{
		var xtWorkspace = g_arrWorkspaces[k];

		//message("Workspace " + (k + 1));
		//message("Containers: " + xtWorkspace.containers.length);

		for(var i = 0; i < xtWorkspace.containers.length; i++)
		{
			try
			{
				var xtContainer = xtWorkspace.containers[i];
				var objContainer = eval("g_doc." + xtContainer.ID);
				var objContainer = xtContainer.container;
				//message(xtContainer.ID + " - " + objContainer.id, true)
				
				xtContainer.left = getLeftCoordinate(objContainer);
				xtContainer.top = getTopCoordinate(objContainer);
				xtContainer.width = objContainer.clientWidth;
				xtContainer.height = objContainer.clientHeight;

				if(blnInitialLoad)
				{
				
					/*message("Changing width for " + objContainer.id + " from " + objContainer.clientWidth + " to " + objContainer.clientWidth + "<br>", true);
					var cell = objContainer.rows[objContainer.rows.length - 1].cells[0];
					var img = cell.children[0];

					img.width = cell.clientWidth - 20;
					objContainer.saidWidth = cell.clientHeight;

					message("Changing width for " + objContainer.id + " from " + objContainer.clientWidth + " to " + objContainer.clientWidth + "<br>", true);
					*/
				}
				
				xtContainer.frames = registerFrameWithContainer(objContainer, blnInitialLoad);
				g_arrWorkspaces[k].containers[i] = xtContainer;
			}
			catch(e)
			{
				//message("Container: " + e.message, true);
			}
		}
	}

	if(blnInitialLoad)
	{
		var arrUserData = parseUserData();
	
		//if(arrUserData != null && loadFromCookie)
		//	applyUserData(arrUserData);
	}
}

function insertSpacerRow(objContainer)
{
	var objRow = objContainer.insertRow(-1);
	var objCell = objRow.insertCell(-1);
	objCell.innerHTML = "&nbsp;";
	objCell.style.height = "100%";
}

function GetClientWidth(objFrame)
{
	var objTemp = objFrame;
	
	while(objTemp.clientWidth == 0)
		objTemp = objTemp.children[0];
		
	return objTemp.clientWidth;
}

function GetClientHeight(objFrame)
{
	var objTemp = objFrame;
	
	while(objTemp.clientHeight == 0)
		objTemp = objTemp.children[0];
		
	return objTemp.clientHeight;
}

function GetFrameRowIndex(objContainer, strFrameID)
{
	for(var i = 0; i < objContainer.rows.length; i++)
	{
		var objFrame = objContainer.rows[i].cells[0].children[0];
		
		if(objFrame && objFrame.id == strFrameID)
			return i;
	}
	return null;
}

/// <summary>
/// Registers all frames in a given container
/// </summary>
/// <param name="objContainer">The container object</param>
/// <returns>An array of XTFrame Objects</returns>
function registerFrameWithContainer(objContainer, blnInitialLoad)
{
	var arrFrames = new Array();

	//We skip the last cell because it's a spacer cell
	for(var i = 0; i < objContainer.rows.length; i++)
	{
		var xtFrame = new XTFrameObject();
		var objFrame = objContainer.rows[i].cells[0].children[0];
		
		try
		{
		
			if(objFrame && objFrame.tagName.toLowerCase() == "div" && objFrame.part == "frame")
			{
				xtFrame.ID = objFrame.id;
				xtFrame.left = getLeftCoordinate(objFrame);
				xtFrame.top = getTopCoordinate(objFrame);
				xtFrame.width = GetClientWidth(objFrame);
				xtFrame.height = GetClientHeight(objFrame);
				xtFrame.containerID = objContainer.id;
				xtFrame.expanded = false;
				xtFrame.collapsed = false;
				xtFrame.index = i;
				xtFrame.frame = objFrame;
				
				arrFrames.push(xtFrame);
				
				if(blnInitialLoad)
					objFrame.columns = objContainer.columns;
			}
		}
		catch(e)
		{
			//message("Frame: " + e.message, true);
		}
	}
	
	return arrFrames;
}

/// <summary>
/// Saves frame/container data in a user cookie
/// </summary>
function saveUserData()
{
	var strUserData = "";

	for(var i = 0; i < g_arrWorkspaces.length; i++)
	{
		if(i > 0)
			strUserData += "&&";

		var xtWorkspace = g_arrWorkspaces[i];
		strUserData += joinXTWorkspace(xtWorkspace);
	}
	
	if (g_doc.ClientCookies != null)
	{
		g_doc.ClientCookies.setAttribute("user_data", strUserData);
		g_doc.ClientCookies.save(g_strCookieID);
	}
	
	return strUserData;
}

/// <summary>
/// Parses any data the user has already stored as a cookie
/// </summary>
function parseUserData()
{
	var xtContainerArray = new Array();
	var strUserData = null;
	
	try
	{
		if (g_doc.ClientCookies != null)
		{
			g_doc.ClientCookies.load(g_strCookieID);
			strUserData = g_doc.ClientCookies.getAttribute("user_data");
		}
	}
	catch(e) {}

	if(!strUserData)
		return null;
		
	//document.write(strUserData);
	
	var arrWorkspaces = strUserData.split("&&");
	var xtWorkspaceArray = new Array();
	
	for(var i = 0; i < arrWorkspaces.length; i++)
	{
		var xtWorkspace = new XTWorkspaceObject();
		xtWorkspace.ID = arrWorkspaces[i].split("##")[0];

		var arrContainers = arrWorkspaces[i].split("##")[1].split("$$");
		var xtContainerArray = new Array();
		
		for(var k = 0; k < arrContainers.length; k++)
		{
			var xtContainer = new XTContainerObject();
			xtContainer.ID = arrContainers[k].split("^^")[0];
			
			var xtFrameArray = new Array();
			if(arrContainers[k].split("^^")[1] != "")
			{
				var arrFrames = arrContainers[k].split("^^")[1].split("**");

				for(var j = 0; j < arrFrames.length; j++)
				{
					var arrFrame = arrFrames[j].split("@@");
					var xtFrame = new XTFrameObject();
					xtFrame.ID = arrFrame[0];
					xtFrame.containerID = xtContainer.ID;
					xtFrame.collapsed = arrFrame[1];
					xtFrame.expanded = arrFrame[2];

					xtFrameArray.push(xtFrame);
				}
			}
			xtContainer.frames = xtFrameArray;
			xtContainerArray.push(xtContainer);
		}
		xtWorkspace.containers = xtContainerArray;
		xtWorkspaceArray.push(xtWorkspace);
	}
	/*
	for(i = 0; i < xtWorkspaceArray.length; i++)
	{
		message("Workspace " + (i + 1) + ": " + xtWorkspaceArray[i].ID);
		for(j = 0; j < xtWorkspaceArray[i].containers.length; j++)
		{
			message("Container " + (j + 1) + ": " + xtWorkspaceArray[i].containers[j].ID + " " + xtWorkspaceArray[i].containers[j].frames.length + " frames");
		}
		message("");
	}
	*/
	
	return xtWorkspaceArray;
}

/// <summary>
/// Expands and collapses the appropriate parts of a frame
/// </summary>
/// <param name="xtWorkspace">The frame to alter</param>
function RefreshFrame(xtFrame)
{
	var frame = xtFrame.frame;
	frame.collapsed = xtFrame.collapsed;
	frame.grown = xtFrame.expanded;
}

/// <summary>
/// Relocates the frames on the page given a workspace based on the user cookies
/// </summary>
/// <param name="xtWorkspace">The source XTWorkspaceObject</param>
function applyUserData(XTWorkspaceArray)
{
	for(var k = 0; k < XTWorkspaceArray.length; k++)
	{
		var xtWorkspace = XTWorkspaceArray[k];
		for(var i = 0; i < xtWorkspace.containers.length; i++)
		{
			var xtContainer = xtWorkspace.containers[i];
			var objContainer = eval("g_doc." + xtContainer.ID);

			if(objContainer)
			{
				objContainer.deleteRow(objContainer.rows.length - 1);
				for(var j = 0; j < xtContainer.frames.length; j++)
				{
					var xtFrameUser = xtContainer.frames[j];
					//alert(g_arrWorkspaces.length);
					var xtFrameDefault = lookupXTFrameInWorkspace(xtFrameUser.ID, g_arrWorkspaces[k]);
					
					if(xtFrameDefault != null)
					{
						xtFrameDefault.collapsed = xtFrameUser.collapsed;
						xtFrameDefault.grown = xtFrameUser.expanded;
						var intOldIndex = lookupFrameIndex(xtFrameDefault.ID);
						var objOldContainer = eval("g_doc." + xtFrameDefault.containerID);
						RefreshFrame(xtFrameDefault);
						alterRowOrder(intOldIndex, objOldContainer, -1, objContainer);
					}
				}
				insertSpacerRow(objContainer);
				objContainer.refresh();
			}
		}
	}

	gatherContainerSpecs();
}

function lookupFrameIndex(strID)
{
	try
	{
		var objTemp = eval("g_doc." + strID);

		while(objTemp.tagName.toLowerCase() != "tr")
			objTemp = objTemp.parentElement;

		return objTemp.rowIndex;
	}
	catch(e)
	{
		//message(e)
	}
}

/// <summary>
/// Given a frame ID and workspace, it looks up and returns the matching XTFrameObject
/// </summary>
/// <param name="strID">The ID of the frame being sought</param>
/// <param name="xtWorkspace">The XTWorkspaceObject that frame belongs to</param>
/// <returns>The corresponding XTFrameObject()</returns>
function lookupXTFrameInWorkspace(strID, xtWorkspace)
{
	//FOR ERROR PROTECTION
	if(xtWorkspace == null) return;
	
	for(var i = 0; i < xtWorkspace.containers.length; i++)
	{
		var xtContainer = xtWorkspace.containers[i];
		for(var j = 0; j < xtContainer.frames.length; j++)
		{
			var xtFrame = xtContainer.frames[j];
			if(xtFrame.ID == strID)
			{
				return xtFrame;
			}
		}
	}
	
	return null;
}

function loopChildren(obj, strDisplayMode)
{
	if(!obj.canHaveChildren)
		return;

	for(var i = 0; i < obj.children.length; i++)
	{
		var objChild = obj.children[i];
		
		if(objChild.tagName.toLowerCase() == "span" && objChild.shrinkable == "true")
			objChild.style.display = strDisplayMode;

		loopChildren(objChild, strDisplayMode);
	}
}

/// <summary>
/// Relocates a frame on the page
/// </summary>
function handleFrameRelocation()
{
	var objNewContainer = eval("g_doc." + g_doc.DragDivider.destinationContainer);
	var objOldContainer = eval("g_doc." + g_doc.DragDivider.sourceContainer);
	
	var intNewIndex = g_doc.DragDivider.destinationRow;
	var intOldIndex = g_doc.DragDivider.sourceRow;

	alterRowOrder(intOldIndex, objOldContainer, intNewIndex, objNewContainer);
	gatherContainerSpecs();

	var objFrame = document.getElementById(g_doc.DragDivider.frameID);

	if(objNewContainer.columns > objOldContainer.columns)
	{
		loopChildren(objFrame, "");
		objFrame.grown = true;
	}
	
	if(objNewContainer.columns < objOldContainer.columns)
	{
		loopChildren(objFrame, "none");
		objFrame.grown = false;
	}

	saveUserData();
}

/// <summary>
/// Prepares a frame movement for animation - basically sets up some variables
/// </summary>
function prepareFrameAnimation()
{
	g_intIntervalSpeed = 10;
	g_intIntervalSteps = 10;
	g_intCurrentInterval = 0;

	g_intHeightInterval = Math.round(parseInt(g_doc.FrameGhost.style.height) / (g_intIntervalSteps - 1));

	var intTopTarget = parseInt(g_doc.DragDivider.runtimeStyle.top);
	var intTopCurrent = parseInt(g_doc.FrameGhost.runtimeStyle.top);
	var intTopToGo = intTopTarget - intTopCurrent;

	g_intTopInterval = Math.floor(intTopToGo / g_intIntervalSteps);
	g_intTopOverflow = intTopToGo % g_intIntervalSteps

	g_strInterval = setInterval(animateFrame, g_intIntervalSpeed);
}

/// <summary>
/// Animates the frame movement
/// </summary>
function animateFrame()
{
	if(g_intCurrentInterval == g_intIntervalSteps)
	{
		clearInterval(g_strInterval);
		g_intCurrentInterval = 0;
		var intDistance = parseInt(g_doc.DragDivider.runtimeStyle.left) - parseInt(g_doc.FrameGhost.runtimeStyle.left);
		g_intLeftInterval = Math.floor(intDistance / g_intIntervalSteps);
		g_intLeftOverflow = intDistance % g_intIntervalSteps;
		g_doc.FrameGhost.style.width = g_doc.DragDivider.clientWidth;
		
		g_strInterval = setInterval(slideFrame, g_intIntervalSpeed);
		return;
	}

	if(g_intCurrentInterval == g_intIntervalSteps - 1)
	{	
		g_doc.FrameGhost.runtimeStyle.top = g_doc.DragDivider.runtimeStyle.top;
		g_intCurrentInterval++;
		return;
	}

	var intNewHeight = parseInt(g_doc.FrameGhost.style.height) - g_intHeightInterval;
	var intNewTop = Math.round(parseInt(g_doc.FrameGhost.runtimeStyle.top) + g_intTopInterval);

	if(intNewHeight <= 0)
		intNewHeight = 3;

	if(g_intCurrentInterval <= g_intTopOverflow)
		intNewTop++;

	g_doc.FrameGhost.runtimeStyle.top = intNewTop;
	g_doc.FrameGhost.style.height = intNewHeight;
	g_intCurrentInterval++;
}

/// <summary>
/// Slides the frame into the appropraite position
/// </summary>
function slideFrame()
{
	if(g_intCurrentInterval == g_intIntervalSteps)
	{
		clearInterval(g_strInterval);
		hideDragDivider();
		handleFrameRelocation();
		g_doc.FrameGhost.style.visibility = "hidden";
	}

	if(g_intCurrentInterval == (g_intIntervalSteps - 1))
	{
		g_doc.FrameGhost.runtimeStyle.left = g_doc.DragDivider.runtimeStyle.left;
		g_intCurrentInterval++;
		return;
	}
	
	var intNewLeft = parseInt(g_doc.FrameGhost.runtimeStyle.left) + g_intLeftInterval;
	
	if(g_intCurrentInterval <= g_intLeftOverflow)
		intNewLeft++;
			
	g_doc.FrameGhost.runtimeStyle.left = intNewLeft;
	g_intCurrentInterval++;	
}

/// <summary>
/// Handles the cases where the frame being dragged is hovering over the
/// containers
/// </summary>
function handleMouseOverContainers(xtWorkspace, objFrame)
{
	for(var i = 0; i < xtWorkspace.containers.length; i++)
	{	
		var xtContainer = xtWorkspace.containers[i];
		var objContainer = eval("g_doc." + xtContainer.ID);
		var intLeft = getLeftCoordinate(objContainer);
		
		var intRight = xtContainer.left + xtContainer.width;
		var intBottom = xtContainer.top + xtContainer.height;
		
		var intPointX = getLeftCoordinate(g_doc.FrameGhost) + (g_doc.FrameGhost.clientWidth / 2);
		var intPointY = getTopCoordinate(g_doc.FrameGhost) + 5;
		
		if(intPointX > xtContainer.left && intPointX < intRight &&
			intPointY > (xtContainer.top - 40) && intPointY < intBottom)
		{
			var intOverHeight = objContainer.rows[objContainer.rows.length - 1].cells[0].clientHeight;
			g_doc.ContainerGhost.style.height = objContainer.clientHeight - intOverHeight + 3;
			g_doc.ContainerGhost.style.width = objContainer.clientWidth + 10;
			
			if(g_doc.ContainerGhost.clientHeight < 20)
				g_doc.ContainerGhost.style.height = g_doc.FrameGhost.clientHeight;
			
			if(g_doc.DragDivider.sourceColumns > objContainer.columns)
			{
				g_doc.ContainerGhost.style.border = "2px #800000 solid";
				g_doc.ContainerGhost.runtimeStyle.left = xtContainer.left - 5;
				g_doc.ContainerGhost.runtimeStyle.top = xtContainer.top - 5;
				hideDragDivider();
				
				if(objFrame != null)
					eval("g_doc.MoveHandle" + objFrame.id).style.cursor = "not-allowed";

				return null;
			}

			eval("g_doc.MoveHandle" + objFrame.id).style.cursor = "move";
			g_doc.ContainerGhost.style.border = "2px #008000 solid";
			g_doc.ContainerGhost.runtimeStyle.left = xtContainer.left - 5;
			g_doc.ContainerGhost.runtimeStyle.top = xtContainer.top - 5;

			var intHeight = g_doc.DragDivider.height;
			g_doc.DragDivider.width = g_doc.ContainerGhost.clientWidth + 2;
			g_doc.DragDivider.height = intHeight;
			g_doc.DragDivider.runtimeStyle.left = g_doc.ContainerGhost.runtimeStyle.left;
			g_doc.DragDivider.destinationContainer = xtContainer.ID;
			return xtContainer;
		}
	}
	
	hideDragDivider();

	return null;
}

/// <summary>
/// Handles the cases where the frame being dragged is hovering over
/// other frames
/// </summary>
/// <param name="xtContainer">The XTContainer object for the container the
/// frame is currently hovering over</param>
/// <returns>The XTContainer object for the container found</returns>
function handleMouseOverFrames(xtContainer, objFrame)
{
	var strCurrentContainerID = xtContainer.ID;
	var strFrameContainerID = getContainerID(objFrame, 2);
	
	var intFrameIndex = lookupFrameIndex(objFrame.id);
	var blnOverFrame = false;
		
	var intPointY = getTopCoordinate(g_doc.FrameGhost) + 5;
	//var intPointBottom = intPointY + g_doc.FrameGhost.clientHeight;

	for(var i = 0; i < xtContainer.frames.length; i++)
	{
		var xtFrame = xtContainer.frames[i];
		var intBottom = xtFrame.top + xtFrame.height;
		
		//var intCurrentFrameIndex = lookupFrameIndex(xtFrame.ID);
		if(intPointY > xtFrame.top && intPointY < intBottom)
		{
			if(strCurrentContainerID == strFrameContainerID)
			{
				if(intFrameIndex == xtFrame.index || intFrameIndex == xtFrame.index + 1)
					return;
			}

			blnOverFrame = true;
			g_doc.DragDivider.runtimeStyle.top = intBottom + 3;
			g_doc.DragDivider.valid = "true";
			g_doc.DragDivider.destinationRow = xtFrame.index + 1;
		}
	}

	if(!blnOverFrame)
	{
		if(strCurrentContainerID == strFrameContainerID && intFrameIndex < 1)
			return;

		var objContainer = eval("g_doc." + xtContainer.ID);
		var intTop = getTopCoordinate(objContainer);
		
		if(intPointY < intTop && intPointY > (intTop - 40))
		{
			blnOverFrame = true;
			g_doc.DragDivider.runtimeStyle.top = intTop - g_doc.DragDivider.clientHeight;
			g_doc.DragDivider.valid = "true";
			g_doc.DragDivider.destinationRow = 0;
		}
	}

	if(!blnOverFrame)
	{
		hideDragDivider();
		handleMouseOverContainers(g_xtActiveWorkspace, objFrame);
	}
}

/// <summary>
/// Hides the "Droppable" divider from view
/// </summary>
function hideDragDivider()
{
	g_doc.DragDivider.runtimeStyle.top = -100;
	g_doc.DragDivider.valid = "false";
}

/// <summary>
/// Alters the orders of rows in tables
/// </summary>
/// <param name="intOldIndex">The row index of the old row</param>
/// <param name="objOldContainer">The old container object containing the old row</param>
/// <param name="intNewIndex">The row index of the new row</param>
/// <param name="objNewContainer">The new container object containing the new row</param>
function alterRowOrder(intOldIndex, objOldContainer, intNewIndex, objNewContainer)
{
	//message(intOldIndex + " to " + intNewIndex);

	if(intNewIndex == intOldIndex && objOldContainer.id == objNewContainer.id)
		return;

	if(objOldContainer.id == objNewContainer.id && intNewIndex == (intOldIndex + 1))
		var intInsertRowAt = intNewIndex + 1;
	else
		var intInsertRowAt = intNewIndex

	var objOldRow = objOldContainer.rows[intOldIndex];
	objRow = objNewContainer.insertRow(intInsertRowAt);

	copyAttributes(objRow, objOldRow);
	objRow.style.behavior = objRow.style.behavior;

	for(i = 0; i < objOldRow.cells.length; i++)
	{
		objCell = objRow.insertCell(i);
		objCell.innerHTML = objOldRow.cells[i].innerHTML;
		copyAttributes(objCell, objOldRow.cells[i]);
	}

	if(intNewIndex < intOldIndex && objOldContainer.id == objNewContainer.id && intNewIndex > -1)
		objOldContainer.deleteRow(intOldIndex + 1);
	else
		objOldContainer.deleteRow(intOldIndex);
}

/// <summary>
/// Copies the attributes from one object to another
/// </summary>
/// <param name="objNew">The new object to copy attributes to</param>
/// <param name="objOld">The old object to copy attributes from</param>
function copyAttributes(objNew, objOld)
{
	objNew.style.cssText = objOld.style.cssText;

	for(var i = 0; i < objOld.attributes.length; i++)
	{
		var objOldAtt = objOld.attributes[i];
		if(objOldAtt.specified)
		{
			if(objOldAtt.name != "style")
			{
				objAtt = document.createAttribute(objOldAtt.name);
				objAtt.value = objOldAtt.value;
				objNew.attributes.setNamedItem(objAtt);
			}
		}
	}
}

/// <summary>
/// Collaborates all the workspace data into a string for storage
/// </summary>
/// <param name="xtWorkspace">The XTWorkspaceObject of said workspace</param>
/// <returns>A string representing states</returns>
function joinXTWorkspace(xtWorkspace)
{
	var strWs = xtWorkspace.ID + "##"

	for(var i = 0; i < xtWorkspace.containers.length; i++)
	{
		//message("Container " + xtWorkspace.containers[i].ID)
		if(i > 0)
			strWs += "$$";
			
		strWs += joinXTContainer(xtWorkspace.containers[i]);
	}
	
	return strWs;
}
/// <summary>
/// Collaborates all the container data into a string for storage
/// </summary>
/// <param name="xtContainer">The XTContainer object of said container</param>
/// <returns>A string representing states</returns>
function joinXTContainer(xtContainer)
{
	var strCont = xtContainer.ID + "^^"

	if(!xtContainer.frames)
		gatherContainerSpecs(false);
		
	for(var i = 0; i < xtContainer.frames.length; i++)
	{
		if(i > 0)
			strCont += "**";
			
		strCont += joinXTFrame(xtContainer.frames[i]);
	}
	
	return strCont;
}

/// <summary>
/// Collaborates all the frame data into a string for storage
/// </summary>
/// <param name="xtFrame">The XTFrame object of said frame</param>
/// <returns>A string representing states</returns>
function joinXTFrame(xtFrame)
{
	var strCollapsed = xtFrame.frame.collapsed;
	var strExpanded =  xtFrame.frame.grown;
	
	if(strCollapsed == null)
		strCollapsed = false;
	if(strExpanded == null)
		strExpanded = false;
		
	var strFrame = xtFrame.ID + "@@" + strCollapsed + "@@" + strExpanded
	return strFrame;
}

/// <summary>
/// Returns an XTWorkspaceObject given an ID
/// </summary>
/// <param name="strID">The ID of said workspace</param>
/// <returns>An XTWorkspaceObject</returns>
function getXTWorkspaceByID(strID)
{
	for(var i = 0; i < g_arrWorkspaces.length; i++)
	{
		if(g_arrWorkspaces[i].ID == strID)
			return g_arrWorkspaces[i];
	}

	return null;
}

/// <summary>
/// Returns the index of a workspace in a collection given an ID
/// </summary>
/// <param name="strID">The ID of said workspace</param>
/// <returns>The index of said workspace in it's collection</returns>
function getWorkspaceIndexByID(strID)
{
	for(var i = 0; i < g_arrWorkspaces.length; i++)
	{
		if(g_arrWorkspaces[i].ID == strID)
			return i;
	}
	
	return null;
}

/// <summary>
/// Returns an XTContainerObject given an ID
/// </summary>
/// <param name="strID">The ID of said container</param>
/// <param name="xtWorkspace">The XTWorkspaceObject containing the container</param>
/// <returns>An XTContainerObject</returns>
function getXTContainerByID(strID, xtWorkspace)
{
	for(var i = 0; i < xtWorkspace.containers.length; i++)
	{
		if(xtWorkspace.containers[i].ID == strID)
			return xtWorkspace.containers[i];
	}
	
	return null;
}

/// <summary>
/// Returns an XTContainerObject given an ID
/// </summary>
/// <param name="strID">The ID of said container</param>
/// <returns>An XTContainerObject</returns>
function getXTContainerByID(strID, xtWorkspace)
{
	for(var j = 0; j< g_arrWorkspaces.length; j++)
	{
		var xtWorkspace = g_arrWorkspaces[j];
		for(var i = 0; i < xtWorkspace.containers.length; i++)
		{
			if(xtWorkspace.containers[i].ID == strID)
				return xtWorkspace.containers[i];
		}
	}
	
	return null;
}
/// <summary>
/// Returns the index of a container in a collection given an ID
/// </summary>
/// <param name="strID">The ID of said container</param>
/// <returns>The index of said container in it's collection</returns>
function getContainerIndexByID(strID, xtWorkspace)
{
	for(var i = 0; i < xtWorkspace.containers.length; i++)
	{
		if(xtWorkspace.containers[i].ID == strID)
			return i;
	}

	return null;
}

/// <summary>
/// Returns an XTFrameObject given an ID
/// </summary>
/// <param name="strID">The ID of said frame</param>
/// <returns>An XTFrameObject</returns>
function getXTFrameByID(strID, xtContainer)
{
	for(var i = 0; i < xtContainer.frames.length; i++)
	{
		if(xtContainer.frames[i].ID == strID)
			return xtContainer.frames[i];
	}

	return null;
}

/// <summary>
/// Returns the index of a frame in a collection given an ID
/// </summary>
/// <param name="strID">The ID of said frame</param>
/// <returns>The index of said frame in it's collection</returns>
function getFrameIndexByID(strID, xtContainer)
{
	for(var i = 0; i < xtContainer.frames.length; i++)
	{
		if(xtContainer.frames[i].ID == strID)
			return i;
	}

	return null;
}

/// <summary>
/// Returns the ID of the parent container given a frame object
/// </summary>
/// <param name="objFrame">The frame object whose container's ID is being sought</param>
/// <param name="intMode">1 - returns the whole object, 2 - returns the ID</param>
/// <returns>The ID of the frame's container</returns>
function getContainerID(objFrame, intMode)
{
	var objTemp = objFrame;
	
	while(objTemp.part != "container")
		objTemp = objTemp.offsetParent;

	switch(intMode)
	{
		case 1 :
		{
			return objTemp;	
			break;
		}
		case 2 :
		{
			return objTemp.id;
			break;
		}
	}
}