var gTreeArray = new Array();


//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// OBJECTS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 * Node object.
 */
function Node(aId, 
			  aFullPath,
			  aParentId, 
			  aName, 
			  aUrl, 
			  aUploadURL, 
			  aTitle, 
			  aTarget, 
			  aIcon, 
			  aIconOpen, 
			  open, 
			  aDeleteCommand, 
			  aForceAsDirectory, 
			  aToken) 
{
	this.mFullPath = aFullPath;
	this.id = aId;	// id
	this.pid = aParentId;	// parent id
	this.name = aName;	// name
	this.url = aUrl;	// url
	this.title = aTitle;	// mouseover title
	this.target = aTarget;	// ???
	this.icon = aIcon;	// icon
	this.iconOpen = aIconOpen;	// opened icon
	this.deleteCommand = aDeleteCommand || false;
	this._io = open || false;	// ???
	this._is = false;	// ??
	this._ls = false;	// ??
	this._hc = aForceAsDirectory || false;	// ??
	this._ai = 0;	// ??
	this._p;	// ??
	this.uploadURL = aUploadURL || false;
	this.token = aToken;
	this.mBulkChosen = false;
//	this.downloadForm = "<form name='dmsRequestDownload_" + aId + "' method='POST' action=''><input type='hidden' name='dmsRequestDownload' value='" + this.url + "'/><input type='hidden' name='token' value='" + this.token + "'/></form>";
	this.deleteForm = "<form name='dmsRequestDelete_" + aId + "' method='POST' action=''><input type='hidden' name='dmsRequestDelete' value='" + aDeleteCommand + "'/><input type='hidden' name='token' value='" + this.token + "'/></form>";
};


/**
 * Tree object.
 */
function dTree(objName) 
{
	this.config = 
	{
		target: null,
		folderLinks: true,
		useSelection: true,
		useCookies: true,
		useLines: false,//true,
		useIcons: true,
		useStatusText: false,
		closeSameLevel: false,
		inOrder: false
	}

	this.icon = 
	{
		root: 'img/folderopen.gif',
		folder: 'img/folder.gif',
		folderOpen: 'img/folderopen.gif',
		node: 'img/page.gif',
		trash: 'img/x.gif',
		downloadIcon	: 'img/down.gif',
		empty				: 'img/empty.gif',
		line				: 'img/line.gif',
		join				: 'img/join.gif',
		joinBottom	: 'img/joinbottom.gif',
		plus				: 'img/plus.gif',
		plusBottom	: 'img/plusbottom.gif',
		minus				: 'img/minus.gif',
		minusBottom	: 'img/minusbottom.gif',
		nlPlus			: 'img/nolines_plus.gif',
		nlMinus			: 'img/nolines_minus.gif'

	};

	this.obj = objName;
	this.aNodes = [];
	this.aIndent = [];
	this.root = new Node(-1);
	this.selectedNode = 0;
	this.selectedFound = false;
	this.completed = false;
	this.provideUploadForm = false;
	this.TEXT_SELECTDIRECTORY = "Please select a directory";
	this.token;
	this.mCreateDirectory = false;
	this.mUpload = false;
	this.mUseBulkDownload = false;
	this.mLeavesInTree = false;
	gTreeArray.push(this);
};

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// FUNCTIONS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
dTree.prototype.provideUpload = function(aUpload)
{
		this.provideUploadForm = aUpload;
};


dTree.prototype.useBulkDownload = function(aAllow)
{
	this.mUseBulkDownload = aAllow;	
}


dTree.prototype.setToken = function(aToken)
{
		this.token = aToken;
};


dTree.prototype.setCreateDirectory = function(aFlag)
{
	this.mCreateDirectory = aFlag;
};

dTree.prototype.setUpload = function(aUpload)
{
	this.mUpload;	
};

dTree.prototype.getSelectedFound = function()
{
	return this.selectedFound;	
}

dTree.prototype.setLeavesInTree = function(aLeavesInTree)
{
	this.mLeavesInTree = aLeavesInTree;	
}
	

// Adds a new node to the node array
dTree.prototype.add = function(aFullPath, id, pid, name, url, aUploadURL, title, target, icon, iconOpen, open, deleteCommand, forceAsDirectory, aToken) 
{
	this.aNodes[this.aNodes.length] = new Node(id, aFullPath, pid, name, url, aUploadURL, title, target, icon, iconOpen, open, deleteCommand, forceAsDirectory, aToken);
};



// Open/close all nodes

dTree.prototype.openAll = function() {

	this.oAll(true);

};

dTree.prototype.closeAll = function() {

	this.oAll(false);

};


/**
 * Output to string.
 */
dTree.prototype.toString = function() 
{
	var str = "";
	
	// Only use border on side if not leaves in tree.
	if(!this.mLeavesInTree)
	{
		str += '<div class="dtree" style="border-right: solid thin;">';
	}
	str += "<div class='ColorBlack FontTitleLight FontBold PaddingBottomLight'>Folders</div>";
	str += "<div>";
	if(document.getElementById) 
	{
		if(this.config.useCookies)
		{
			this.selectedNode = this.getSelected();
		}
		str += this.addNode(this.root);
	} 
	else
	{
		str += 'Browser not supported.';
	}
	str += '</div>';
	str += "</div>";
	
	// Create command window, but only if leaves in tree.
	if(!this.mLeavesInTree)
	{
		str += '<div style="float: left; padding-left: 10px; margin-bottom: 10px; border-left: solid thin;">';
		str += "<div class='ColorBlack FontTitleLight FontBold PaddingBottomLight'>Files</div>";
		str += '<div id="dTreeFileList_' + this.obj + '" >' + this.TEXT_SELECTDIRECTORY + '</div>';
		str += '</div>';
	}

	// Deal with selected/cookie.
	if(!this.selectedFound)
	{
		this.selectedNode = 0;
		this.selectedFound = true;
	}
	this.completed = true;
	return str;
};



// Creates the tree structure
dTree.prototype.addNode = function(pNode) 
{
	// Init.
	var str = '';
	var n = 0;
	
	// Check if in order.
	if(this.config.inOrder) 
	{
		n = pNode._ai;
	}

	// Go thorugh all the nodes.
	for(n; n < this.aNodes.length; n++) 
	{
		// Check if the provided node is a parent.
		if(this.aNodes[n].pid == pNode.id)
		{
			// Set pointers to parent and current.
			var cn = this.aNodes[n];
			cn._p = pNode;
			cn._ai = n;
			
			// Determine children and siblings.
			this.setCS(cn);
			if(!cn.target && this.config.target)
			{
				cn.target = this.config.target;
			}
			
			// Check if is open and cookies enabled.
			if(cn._hc && !cn._io && this.config.useCookies)
			{
				cn._io = this.isOpen(cn.id);
			}
			
			// If no folder links and has children, URL is null.
			if(!this.config.folderLinks && cn._hc)
			{
				cn.url = null;
			}
			if(this.config.useSelection && cn.id == this.selectedNode && !this.selectedFound) 
			{
				cn._is = true;
				this.selectedNode = n;
				this.selectedFound = true;
			}
			
			// Add node to string, but only if has children/directory.
			if(this.mLeavesInTree || cn._hc)
			{
				str += this.node(cn, n);
			}
			if(cn._ls)
			{
				break;
			}
		}
	}
	return str;
};



// Creates the node icon, url and text
dTree.prototype.node = function(node, nodeId) 
{
	var str = "<div class='dTreeNode'>" + this.indent(node, nodeId);
	if(this.config.useIcons) 
	{
		if(!node.icon) 
		{
			node.icon = (this.root.id == node.pid) ? this.icon.root : ((node._hc) ? this.icon.folder : this.icon.node);
		}

		if(!node.iconOpen)
		{
			node.iconOpen = (node._hc) ? this.icon.folderOpen : this.icon.node;
		}

		if(this.root.id == node.pid) 
		{
			node.icon = this.icon.root;
			node.iconOpen = this.icon.root;
		}
		
		// If using bulk download, output checkbox.
		if(this.mUseBulkDownload)
		{
			str += '<input class="checkbox_' + nodeId + '" type="checkbox" onclick="handleCheckboxClick(' + nodeId + ', \'' + this.obj + '\', this.checked == true);"/>';
		}
		str += '<img id="i' + this.obj + nodeId + '" src="' + ((node._io) ? node.iconOpen : node.icon) + '" alt="" />';		
	}
	
	// If selected, select.
	if(this.selectedNode == nodeId)
	{
		str += '<a id="nodelink_' + this.obj + '_' + nodeId + '" href="javascript: ' + this.obj + '.o(' + nodeId + ');" class="nodeSel">';
	}
	else
	{
		str += '<a id="nodelink_' + this.obj + '_' + nodeId + '" href="javascript: ' + this.obj + '.o(' + nodeId + ');" class="node">';
	}
	str += node.name;

	if(node.url || ((!this.config.folderLinks || !node.url) && node._hc)) 
	{
		str += '</a>';
	}
	str += '</div>';

	if(node._hc) 
	{
		str += '<div id="d' + this.obj + nodeId + '" class="clip" style="display:' + ((this.root.id == node.pid || node._io) ? 'block' : 'none') + ';">';
		str += this.addNode(node);
		str += '</div>';
	}
	this.aIndent.pop();
	return str;
};



// Adds the empty and line icons

dTree.prototype.indent = function(node, nodeId) 
{
	var str = '';
	if(this.root.id != node.pid) 
	{
		for(var n = 0; n < this.aIndent.length; n++)
		{
			str += '<img src="' + ( (this.aIndent[n] == 1 && this.config.useLines) ? this.icon.line : this.icon.empty ) + '" alt="" />';
		}
		(node._ls) ? this.aIndent.push(0) : this.aIndent.push(1);
		if(node._hc)
		{
			str += '<a href="javascript: ' + this.obj + '.o(' + nodeId + ');"><img id="j' + this.obj + nodeId + '" src="';
			if(!this.config.useLines)
			{
				str += (node._io) ? this.icon.nlMinus : this.icon.nlPlus;
			}
			else
			{
				str += ( (node._io) ? ((node._ls && this.config.useLines) ? this.icon.minusBottom : this.icon.minus) : ((node._ls && this.config.useLines) ? this.icon.plusBottom : this.icon.plus ) );
			}
			str += '" alt="" /></a>';
		}
		else
		{
			str += '<img src="' + ( (this.config.useLines) ? ((node._ls) ? this.icon.joinBottom : this.icon.join ) : this.icon.empty) + '" alt="" />';
		}
	}
	return str;
};



// Checks if a node has any children and if it is the last sibling

dTree.prototype.setCS = function(node) {

	var lastId;

	for (var n=0; n<this.aNodes.length; n++) {

		if (this.aNodes[n].pid == node.id) node._hc = true;

		if (this.aNodes[n].pid == node.pid) lastId = this.aNodes[n].id;

	}

	if (lastId==node.id) node._ls = true;

};



// Returns the selected node

dTree.prototype.getSelected = function() 
{
	var sn = this.getCookie('cs' + this.obj);
	return (sn) ? sn : null;
};



// Highlights the selected node

dTree.prototype.s = function(id) {

	if (!this.config.useSelection) return;

	var cn = this.aNodes[id];
//	if (cn._hc && !this.config.folderLinks) return;
	if(this.selectedNode != id) 
	{
		if (this.selectedNode || this.selectedNode==0) 
		{
			var fieldNameElementOld = document.getElementById("nodelink_" + this.obj + "_" + this.selectedNode);
			if(fieldNameElementOld != null)
			{
				fieldNameElementOld.className = "node";
			}
		}
	}
	var fieldNameElementNew = document.getElementById("nodelink_" + this.obj + "_" + id);
	if(fieldNameElementNew != null)
	{
		fieldNameElementNew.className = "nodeSel";
		this.selectedNode = id;
		if (this.config.useCookies)
		{
			this.setCookie('cs' + this.obj, cn.id);
		}
	}
};


/**
 * Returns array of indecies for leaves of provided node ID.
 */
dTree.prototype.getLeafIndecies = function(id)
{
	var commandArray = new Array();
	for(var n = 0; n < this.aNodes.length; n++) 
	{
		if(this.aNodes[n].pid == id && !this.aNodes[n]._hc)
		{
			commandArray[commandArray.length] = this.aNodes[n]._ai;
		}
	}
	return commandArray;
}



/**
 * Toggles open/close of node with provided ID.
 */
dTree.prototype.o = function(id) 
{
	var cn = this.aNodes[id];
	
	// Select him.
	this.s(id);
	
	// update status only if not root.
	if(cn.pid != -1)
	{
		this.nodeStatus(!cn._io, id, cn._ls);
	}
	cn._io = !cn._io;
	if (this.config.closeSameLevel) this.closeLevel(cn);
	if (this.config.useCookies) this.updateCookie();
	
	// Set file list for clicked node.
	var leafIndecies = this.getLeafIndecies(cn.id);
	
	// Determine output files.
	var leavesString = "<table>";
	var hasLeaves = false;
	for(var i = 0; i < leafIndecies.length; i++)
	{
		leavesString += "<tr><td>";
		var index = leafIndecies[i];
		var leafNode = this.aNodes[index];
		var leafName = "<span style='" + nameStyle + "'>" + leafNode.name + "</span>";
		if(leafNode.url)
		{
			// If using bulk download, output this.  Else, simple download.
			if(this.mUseBulkDownload)
			{
				leavesString += '<input class="checkbox_' + leafNode.id + '" type="checkbox" onclick="handleCheckboxClick(' + leafNode.id + ', \'' + this.obj + '\', this.checked == true);" ';
				leavesString += leafNode.mBulkChosen ? 'checked="true" />' : '/>';
			}
			else
			{
				leavesString += leafNode.downloadForm;
				leavesString += "<a href='#' onclick='dmsRequestDownload_" + leafNode.id + ".submit();'><img src='" + this.icon.downloadIcon + "'/></a>";
			}
			hasLeaves = true;
		}
		leavesString += "</td>";
	
		// Check for delete option.
		leavesString += "<td>";
		if(leafNode.deleteCommand)
		{
			leavesString += leafNode.deleteForm;
			leavesString += " <a href='#' onclick=\"if(confirm('Are you sure you want to delete the file " + addslashes(leafNode.name) + "?')) { dmsRequestDelete_" + leafNode.id + ".submit(); }\"><img style='border-style: none' src='img/x.gif'/></a>";
		}
		leavesString += "</td><td>" + leafName + "</td></tr>";
	}
	leavesString += "</table>";
	
	// Start out.
	outputString = "<table><tr><td>";
	var nameStyle = "";
//	var folderName = cn.pid == this.root.id ? "<span style='" + nameStyle + "'>root</span>" : "<span style='" + nameStyle + "'>" + cn.name + "</span>";
	var folderName = "<span style='" + nameStyle + "'>" + cn.name + "</span>";
	if(cn.url)
	{
		if(hasLeaves)
		{
			// If using bulk download, output checkbox.  Else, simple.
			if(this.mUseBulkDownload)
			{
		//		outputString += '<input class="checkbox_' + cn.id + '" type="checkbox" onclick="handleCheckboxClick(' + cn.id + ', \'' + this.obj + '\', this.checked == true);"/>';
			}
			else
			{
				outputString += cn.downloadForm;
				outputString += "<a href='#' onclick='dmsRequestDownload_" + cn.id + ".submit();'><img src='" + this.icon.downloadIcon + "'/></a>";
			}
		}
	}
	outputString += "</td><td>";

	// Check for delete option.
	if(cn.deleteCommand)
	{
		outputString += " <a href='#' onclick=\"if(confirm('Are you sure you want to delete the folder " + addslashes(cn.name) + " and all of its contents?')) { dmsRequestDelete_" + cn.id + ".submit(); }\"><img style='border-style: none' src='img/x.gif'/></a>";
		outputString += cn.deleteForm;
	}
	outputString += "</td><td>Folder '" + folderName + "' selected</td></table>";
	outputString += "<hr size='1' width='100%'>";
	
	// Add leaves commands.
	outputString += leavesString;
	
	// Output.
	this.populateCommandDiv(outputString);
	
	// Upload.
	this.setFolder(cn.id);
};


/**
 * Sets upload folder.
 */
dTree.prototype.setFolder = function(id)
{
	var cn = this.aNodes[id];
/*	if(this.provideUploadForm && (cn._hc || cn.pid == this.root.id))
	{
		if(cn.pid == this.root.id)
		{
			this.populateFolderIDDiv("Upload to folder/create directory in 'root'");
		}
		else
		{
			this.populateFolderIDDiv("Upload to folder/create directory in '" + cn.name + "'");
		}
	}*/
	
	// If directory field exists for upload, fill it.
	var fieldNameElement = document.getElementById(this.obj + "_folderIDFull");
	if(fieldNameElement != null)
	{
		if(fieldNameElement.getAttributeNode('value') == null)
		{
			fieldNameElement.value = cn.uploadURL;
		}
		else
		{
			fieldNameElement.getAttributeNode('value').nodeValue = cn.uploadURL;
		}
	}
	
	// If directory field exists for creation, fill it.
	if(this.mCreateDirectory)
	{
		var fieldNameElement = document.getElementById(this.obj + "_folderIDCreateDirectory");
		if(fieldNameElement != null)
		{
			var foundNode = fieldNameElement.getAttributeNode("value");
			if(foundNode != null)
			{
				foundNode.nodeValue = cn.uploadURL;
			}
		}
	}
}


/**
 * Populates the command list div.
 */
dTree.prototype.populateCommandDiv = function(aContents) 
{
	var fieldNameElement = document.getElementById("dTreeFileList_" + this.obj);
	if(fieldNameElement != null)
	{
		while(fieldNameElement.childNodes.length >= 1) 
		{
			fieldNameElement.removeChild(fieldNameElement.firstChild);
		}
		fieldNameElement.innerHTML = aContents;
	}
}


/**
 * Populates the upload div.
 */
dTree.prototype.populateFolderIDDiv = function(aContents) 
{
	var fieldNameElement = document.getElementById("folderID" + this.obj);
	while(fieldNameElement.childNodes.length >= 1) 
	{
		fieldNameElement.removeChild(fieldNameElement.firstChild);
	}
	fieldNameElement.innerHTML = aContents;
}


// Open or close all nodes

dTree.prototype.oAll = function(status) {

	for (var n=0; n<this.aNodes.length; n++) {

		if (this.aNodes[n]._hc && this.aNodes[n].pid != this.root.id) {

			this.nodeStatus(status, n, this.aNodes[n]._ls)

			this.aNodes[n]._io = status;

		}

	}

	if (this.config.useCookies) this.updateCookie();

};



// Opens the tree to a specific node

dTree.prototype.openTo = function(nId, bSelect, bFirst) {

	if (!bFirst) {

		for (var n=0; n<this.aNodes.length; n++) {

			if (this.aNodes[n].id == nId) {

				nId=n;

				break;

			}

		}

	}

	var cn=this.aNodes[nId];

	if (cn.pid==this.root.id || !cn._p) return;

	cn._io = true;

	cn._is = bSelect;

	if (this.completed && cn._hc) this.nodeStatus(true, cn._ai, cn._ls);

	if (this.completed && bSelect) 
	{
		this.s(cn._ai);
	}
	else if (bSelect)
	{
		this._sn=cn._ai;
	}
	this.openTo(cn._p._ai, false, true);

};



// Closes all nodes on the same level as certain node

dTree.prototype.closeLevel = function(node) {

	for (var n=0; n<this.aNodes.length; n++) {

		if (this.aNodes[n].pid == node.pid && this.aNodes[n].id != node.id && this.aNodes[n]._hc) {

			this.nodeStatus(false, n, this.aNodes[n]._ls);

			this.aNodes[n]._io = false;

			this.closeAllChildren(this.aNodes[n]);

		}

	}

}



// Closes all children of a node

dTree.prototype.closeAllChildren = function(node) {

	for (var n=0; n<this.aNodes.length; n++) {

		if (this.aNodes[n].pid == node.id && this.aNodes[n]._hc) {

			if (this.aNodes[n]._io) this.nodeStatus(false, n, this.aNodes[n]._ls);

			this.aNodes[n]._io = false;

			this.closeAllChildren(this.aNodes[n]);		

		}

	}

}



// Change the status of a node(open or closed)

dTree.prototype.nodeStatus = function(status, id, bottom) {

	eDiv	= document.getElementById('d' + this.obj + id);

	eJoin	= document.getElementById('j' + this.obj + id);

	if (this.config.useIcons) {

		eIcon	= document.getElementById('i' + this.obj + id);

		eIcon.src = (status) ? this.aNodes[id].iconOpen : this.aNodes[id].icon;

	}

	eJoin.src = (this.config.useLines)?

	((status)?((bottom)?this.icon.minusBottom:this.icon.minus):((bottom)?this.icon.plusBottom:this.icon.plus)):

	((status)?this.icon.nlMinus:this.icon.nlPlus);

	eDiv.style.display = (status) ? 'block': 'none';

};





// [Cookie] Clears a cookie

dTree.prototype.clearCookie = function() {

	var now = new Date();

	var yesterday = new Date(now.getTime() - 1000 * 60 * 60 * 24);

	this.setCookie('co'+this.obj, 'cookieValue', yesterday);

	this.setCookie('cs'+this.obj, 'cookieValue', yesterday);

};



// [Cookie] Sets value in a cookie

dTree.prototype.setCookie = function(cookieName, cookieValue, expires, path, domain, secure) {

	document.cookie =

		escape(cookieName) + '=' + escape(cookieValue)

		+ (expires ? '; expires=' + expires.toGMTString() : '')

		+ (path ? '; path=' + path : '')

		+ (domain ? '; domain=' + domain : '')

		+ (secure ? '; secure' : '');

};



// [Cookie] Gets a value from a cookie
dTree.prototype.getCookie = function(cookieName) 
{
	var cookieValue = '';
	var posName = document.cookie.indexOf(escape(cookieName) + '=');
	if(posName != -1) 
	{
		var posValue = posName + (escape(cookieName) + '=').length;
		var endPos = document.cookie.indexOf(';', posValue);
		if(endPos != -1)
		{
			cookieValue = unescape(document.cookie.substring(posValue, endPos));
		}
		else
		{
			cookieValue = unescape(document.cookie.substring(posValue));
		}
	}
	return (cookieValue);
};



// [Cookie] Returns ids of open nodes as a string

dTree.prototype.updateCookie = function() 
{
	var str = '';
	for(var n=0; n<this.aNodes.length; n++) 
	{
		if(this.aNodes[n]._io && this.aNodes[n].pid != this.root.id) 
		{
			if(str)
			{
				str += '.';
			}
			str += this.aNodes[n].id;
		}
	}
	this.setCookie('co' + this.obj, str);
};



// [Cookie] Checks if a node id is in a cookie

dTree.prototype.isOpen = function(id) {

	var aOpen = this.getCookie('co' + this.obj).split('.');

	for (var n=0; n<aOpen.length; n++)

		if (aOpen[n] == id) return true;

	return false;

};



// If Push and pop is not implemented by the browser

if (!Array.prototype.push) {

	Array.prototype.push = function array_push() {

		for(var i=0;i<arguments.length;i++)

			this[this.length]=arguments[i];

		return this.length;

	}

};

if (!Array.prototype.pop) {

	Array.prototype.pop = function array_pop() {

		lastElement = this[this.length-1];

		this.length = Math.max(this.length-1,0);

		return lastElement;

	}

};




//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// UTILITY FUNCTIONS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
function addslashes(str) 
{	
	if(str != null)
	{
		str=str.replace(/\\/g,'\\\\');
		str=str.replace(/\'/g,'\\\'');
		str=str.replace(/\"/g,'\\"');
		str=str.replace(/\0/g,'\\0');
	}
	else
	{
		str = '';	
	}
	return str;
};


function stripslashes(str)
{
	if(str != null)
	{
		str=str.replace(/\\'/g,'\'');
		str=str.replace(/\\"/g,'"');
		str=str.replace(/\\0/g,'\0');
		str=str.replace(/\\\\/g,'\\');
	}
	else
	{
		str = '';	
	}
	return str;
};


/**
 * Handles checkbox click.
 * It goes through all the checkboxes that should be checked/unchecked according to the last action.
 */
function handleCheckboxClick(aNodeId, aTreeName, aSelect)
{
	// Find the tree.
	var tree = null;
	for(var i = 0; i < gTreeArray.length; i++)
	{
		if(gTreeArray[i].obj == aTreeName)
		{
			tree = gTreeArray[i];
			break;
		}
	}
	
	// Find the node in the tree.  Mark it and it's descendents.
	if(tree != null)
	{
		var node = tree.aNodes[aNodeId];
		setBulkChosenOfBranch(node, aSelect, tree);
	}
	
	// Consolidate selected nodes for post.
	consolidateSelectedNodes(tree);
}


/**
 * Given a node, selects or deselects the descendents.
 * 
 * @param aSelect true iff select
 * @param aNode root node
 * @param aTree tree
 */
function setBulkChosenOfBranch(aNode, aSelect, aTree)
{
	aNode.mBulkChosen = aSelect;
	$(".checkbox_" + aNode.id).attr("checked", aSelect);
	for(var n = 0;  n < aTree.aNodes.length; n++) 
	{
		if(aTree.aNodes[n].pid == aNode.id) 
		{
			aTree.aNodes[n].mBulkChosen = aSelect;
			setBulkChosenOfBranch(aTree.aNodes[n], aSelect, aTree);	
		}
	}
}


/**
 * Determines selected nodes and readies for POST send.
 *
 * @param aTree tree to search
 */
function consolidateSelectedNodes(aTree)
{
	var pathArray = new Array();
	for(var i = 0; i < aTree.aNodes.length; i++)
	{
		if(aTree.aNodes[i].mBulkChosen)
		{
			pathArray.push(aTree.aNodes[i].mFullPath);
		}
	}
	var joinedString = pathArray.join("###");
	$("#bulkDownloadList").val(joinedString);
}
