/**
* Original Author of this file: Martin Mouritzen. (martin@nano.dk)
*
*
* (Lack of) Documentation:
*
*
* If a finishedLoading method exists, it will be called when the tree is loaded.
* (good to display a div, etc.).
*
*
* You have to set the variable rootNode (as a TreeNode).
*
* You have to set a container element, this is the element in which the tree will be.
*
*
* TODO: 
* Save cookies better (only 1 cookie for each tree). Else the page will totally cookieclutter.
*
***********************************************************************
* Configuration variables.
************************************************************************/

// Should the rootNode be displayed.
var showRootNode = false;

// Should the dashed lines between nodes be shown.
var showLines = true;

// Should the nodes be sorted? (You can either specify a number, then it will be sorted by that, else it will
// be sorted alphabetically (by name).
var sortNodes = true;

// This is IMPORTANT... use an unique id for each document you use the tree in. (else they'll get mixed up).
var documentID = window.location.href;

// being read from cookie.
var nodesOpen = new Array();

// RootNode of the tree.
var rootNode;

// Container to display the Tree in.
var container;

// Shows/Hides subnodes on startup
var showAllNodesOnStartup = false;

// Is the roots dragable?
var dragable = false;

// Should node hover be displayed.
var showHover = false;
/************************************************************************
* The following is just instancevariables.
************************************************************************/
var href = '';

// rootNodeCallBack name (if null, it's not selectable).
var rootNodeCallBack = null;

// selectedNode
var selectedNode = null;

var states = '';
var statearray = new Array();

var treeNodeEdited = null;

var editaborted = false;

var floatDragElement = null;
var colouredElement = null;
var draggedNodeID = null;
var lastDraggedOnNodeID = null;


/**
* The TreeNode Object
* @param id unique id of this treenode
* @param name The title of this node
* @param icon The icon if this node (Can also be an array with 2 elements, the first one will represent the closed state, and the next one the open state)
* @param param A parameter, this can be pretty much anything. (eg. an array with information).
* @param orderNumber an orderNumber If one is given the nodes will be sorted by this (else they'll be sorted alphabetically (If sorting is on).
*/
function TreeNode(id,name,icon,param,orderNumber) {
	this.id = id;
	this.childs = new Array();
	this.name = (name == null ? 'unset name' : name);
	this.icon = (icon == null ? '' : icon);
	this.parent = null;
	this.handler = null;
	this.param = (param == null ? '' : param);
	this.orderNumber = (orderNumber == null ? -1 : orderNumber);
	
	this.openeventlisteners = new Array();
	this.editeventlisteners = new Array();
	this.moveeventlisteners = new Array();
	this.hovereventlisteners = new Array();
	this.haschilds = false;
	this.editable = false;
	this.linestring = '';
	
	this.nextSibling = null;
	this.prevSibling = null;
	
	this.childsHasBeenFetched = false;

	this.getID = function() {
		return this.id;
	}
	this.setName = function(newname) {
		this.name = newname;
	}
	this.getName = function() {
		return this.name;
	}
	this.getParam = function() {
		return this.param;
	}
	this.setIcon = function(icon) {
		this.icon = icon;
	}
	this.getIcon = function() {
		if (typeof(this.icon) == 'object') {
			return this.icon[0];
		}
		return this.icon;
	}
	this.getOpenIcon = function() {
		if (typeof(this.icon) == 'object') {
			return this.icon[1];
		}
		return this.icon;
	}
	this.hasIcon = function () {
		return this.icon != '';
	}
	this.getOrderNumber = function() {
		return this.orderNumber;
	}
	this.addHoverEventListener = function(event) {
		this.hovereventlisteners[this.hovereventlisteners.length] = event;
	}
	this.gotHoverEventListeners = function() {
		return (this.hovereventlisteners.length > 0);
	}
	this.addOpenEventListener = function(event) {
		this.openeventlisteners[this.openeventlisteners.length] = event;
	}
	this.gotOpenEventListeners = function() {
		return (this.openeventlisteners.length > 0);
	}
	this.addEditEventListener = function(event) {
		this.editeventlisteners[this.editeventlisteners.length] = event;
	}
	this.gotEditEventListeners = function() {
		return (this.editeventlisteners.length > 0);
	}
	this.addMoveEventListener = function(event) {
		this.moveeventlisteners[this.moveeventlisteners.length] = event;
	}
	this.gotMoveEventListeners = function() {
		return (this.moveeventlisteners.length > 0);
	}
	this.addChild = function(childNode) {
		var possiblePrevNode = this.childs[this.childs.length - 1]
		if (possiblePrevNode) {
			possiblePrevNode.nextSibling = childNode;
			childNode.prevSibling = possiblePrevNode;
			// alert(childNode.prevSibling);
		}

		this.childs[this.childs.length] = childNode;
		childNode.setParent(this);

		if (sortNodes) {
			function sortByOrder(a,b) {
				var order1 = a.getOrderNumber();
				var order2 = b.getOrderNumber();
				if (order1 == -1 || order2 == -1) {
					return a.getName().toLowerCase() > b.getName().toLowerCase() ? 1 : -1;
				}
				else {
					if (order1 == order2) {
						// If they got the same order number, then we'll sort by their title.
						return a.getName().toLowerCase() > b.getName().toLowerCase() ? 1 : -1;
					}
					else {
						return order1 - order2;
					}
				}
			}
			this.childs.sort(sortByOrder);
		}
	}
	this.removeChild = function(childNode) {
		var found = false;
		for (var i=0;i<this.childs.length;i++) {
			if (found) {
				this.childs[i] = this.childs[i + 1];
			}
			if (this.childs[i] == childNode) {
				if (i == (this.childs.length - 1)) {
					this.childs[i] = null;
				}
				else {
					this.childs[i] = this.childs[i + 1];
				}
				found = true;
			}
		}
		if (found) {
			this.childs.length = this.childs.length-1;
		}
	}
	this.resetChilds = function() {
		this.childs = new Array();
	}
	this.setHasChilds = function(hasChilds) {
		this.haschilds = hasChilds;
	}
	this.hasChilds = function() {
		if (this.haschilds == true) {
			return true;
		}
		return (this.childs.length > 0);
	}
	this.getChildCount = function() {
		return this.childs.length;
	}
	this.getFirstChild = function() {
		if (this.hasChilds()) {
			return this.childs[0];
		}
		return null;
	}
	this.gotHandler = function() {
		return this.handler != null;
	}
	this.setHandler = function(handler) {
		this.handler = handler;
	}
	this.getHandler = function() {
		return this.handler;
	}
	this.setParent = function(parent) {
		this.parent = parent;
	}
	this.getParent = function() {
		return this.parent;
	}
	this.getLineString = function() {
		return this.linestring;
	}
	this.setLineString = function(string) {
		this.linestring = string;
	}
	this.isEditable = function() {
		return this.editable;
	}
	this.setEditable = function(editable) {
		this.editable = editable;
	}
	
}
function standardClick(treeNode)
{}
function standardHover(treeNode)
{}
function getTreeNode(nodeID) {
	return findNodeWithID(rootNode,nodeID);
}
function findNodeWithID(node,nodeID) {
	if (node.getID() == nodeID) {
		return node;
	}
	else {
		if (node.hasChilds()) {
			for(var i=0;i<node.getChildCount();i++) {
				var value = findNodeWithID(node.childs[i],nodeID);
				if (value != false) {
					return value;
				}
			}
		}
		return false;
	}
}
function readStates() {
	//setCookie('tree' + documentID,'');
	states = getCookie('tree' + documentID);
	if (states != null) {
		var array = states.split(';');
		for(var i=0;i<array.length;i++) {
			var singlestate = array[i].split('|');
			statearray[i] = new Array();
			statearray[i]["key"] = singlestate[0];
			statearray[i]["state"]  = singlestate[1];
		}
	}
}
function getState(nodeID) {
	for(var i=0;i<statearray.length;i++) {
		if (statearray[i]["key"] == nodeID) {
			state = statearray[i]["state"];
			if (state == null || state == '') {
				state = 'closed';
			}
			return state;
		}
	}
	return "closed";
}
function writeStates(nodeID,newstate) {
	//alert(nodeID);
	var str = '';
	var found = false;
	for(var i=0;i<statearray.length;i++) {
		if (statearray[i]["key"] == nodeID) {
			statearray[i]["state"] = newstate;
			found = true;
		}
		if (statearray[i]["state"] != null) {
			str += statearray[i]["key"] + '|' + statearray[i]["state"] + ';';
		}
	}
	if (found == false) {
		statearray[statearray.length] = new Array();
		statearray[statearray.length - 1]["key"] = nodeID;
		statearray[statearray.length - 1]["state"] = newstate;
		if (newstate != null) {
			str += nodeID + '|' + newstate + ';';
		}
	}
	setCookie('tree' + documentID,str);
}
function showTree(path) {
	readStates();
	
	href = path;
	window.focus();
	window.onblur = blurSelection;
	window.onfocus = focusSelection;
	var str = '';
	str = '<div id="node' + rootNode.getID() + '" class="treetitle" style="display:' + (showRootNode == true ? 'block' : 'none') + '">';
	str += '<nobr>';
	if (rootNode.hasIcon()) {
		str += '<img src="' + rootNode.getIcon() + '" style="vertical-align:middle;">';
	}
	str += '<span style="vertical-align:middle;">&nbsp;' + rootNode.getName() + '</span>';
	str += '</nobr></div>';
	
	if (rootNode.hasChilds()) {
		for(i=0;i<rootNode.childs.length;i++) {
			nodeContents = showNode(rootNode.childs[i],(i == (rootNode.getChildCount() -1)));
			str = str + nodeContents;
		}
	}
	container.innerHTML = str;
	if (window.finishedLoading) {
		finishedLoading();
	}
}
/**
* Shows the given node, and subnodes.
*/
function showNode(treeNode,lastNode) {
	linestring = treeNode.getLineString();
	var state = getState(treeNode.getID());
	var str;
	str = '<div style="filter:alpha(opacity=100);" ondragenter="dragEnter(\'' + treeNode.getID() + '\');" ondragleave="dragLeave();" ondragstart="startDrag(\'' + treeNode.getID() + '\');" ondrag="dragMove();" ondragend="endDrag(\'' + treeNode.getID() + '\')" id="node' + treeNode.getID() + '">';
	str += '<nobr>';
	for(var y=0;y<linestring.length;y++) {
		if (linestring.charAt(y) == 'I') {
			str += '<img src="' + href + 'images/' + (showLines ? 'line' : 'white') + '.gif" style="width:19px;height:20px;vertical-align:middle;">';
		}
		else if (linestring.charAt(y) == 'B') {
			str += '<img src="' + href + 'images/white.gif" style="width:19px;height:20px;vertical-align:middle;">';
		}
	}
	if (treeNode.hasChilds()) {
		// If this is the first child of the rootNode, and showRootNode is false, we want to display a different icon.
		if (!showRootNode && (treeNode.getParent() == rootNode) && (treeNode.getParent().getFirstChild() == treeNode)) {
			if (!lastNode) {
				str += '<img id="handler' + treeNode.getID() + '" src="' + href + 'images/' + (state == 'open' ? (showLines ? 'minus_no_root' : 'minus_nolines') : (showLines ? 'plus_no_root' : 'plus_nolines')) + '.gif" style="width:19px;height:20px;vertical-align:middle;" OnClick="handleNode(\'' + treeNode.getID() + '\');">';
			}
			else {
				str += '<img id="handler' + treeNode.getID() + '" src="' + href + 'images/' + (state == 'open' ? 'minus_last' : 'plus_last') + '_no_root.gif" style="width:19px;height:20px;vertical-align:middle;" OnClick="handleNode(\'' + treeNode.getID() + '\');">';
			}
		}
		else {
			if (!lastNode) {
				str += '<img id="handler' + treeNode.getID() + '" src="' + href + 'images/' + (state == 'open' ? (showLines ? 'minus' : 'minus_nolines') : (showLines ? 'plus' : 'plus_nolines')) + '.gif" style="width:19px;height:20px;vertical-align:middle;" OnClick="handleNode(\'' + treeNode.getID() + '\');">';
			}
			else {
				str += '<img id="handler' + treeNode.getID() + '" src="' + href + 'images/' + (state == 'open' ? (showLines ? 'minus_last' : 'minus_nolines') : (showLines ? 'plus_last' : 'plus_nolines')) + '.gif" style="width:19px;height:20px;vertical-align:middle;" OnClick="handleNode(\'' + treeNode.getID() + '\');">';
			}
		}
	}
	else {
		// If this is the first child of the rootNode, and showRootNode is false, we want to display a different icon.
		if (!showRootNode && (treeNode.getParent() == rootNode) && (treeNode.getParent().getFirstChild() == treeNode)) {
			if (!lastNode) {
				str += '<img id="handler' + treeNode.getID() + '" src="' + href + 'images/' + (showLines ? 't_no_root' : 'white') + '.gif" style="width:19px;height:20px;vertical-align:middle;">';
			}
			else {
				str += '<img id="handler' + treeNode.getID() + '" src="' + href + 'images/white.gif" style="width:19px;height:20px;vertical-align:middle;">';
			}
		}
		else {
			if (!lastNode) {
				str += '<img id="handler' + treeNode.getID() + '" src="' + href + 'images/' + (showLines ? 't' : 'white') + '.gif" style="width:19px;height:20px;vertical-align:middle;">';
			}
			else {
				str += '<img id="handler' + treeNode.getID() + '" src="' + href + 'images/' + (showLines ? 'lastnode' : 'white') + '.gif" style="width:19px;height:20px;vertical-align:middle;">';
			}
		}
	}
	iconStartImage = treeNode.getIcon();
	if (state != 'closed') {
		if (treeNode.hasChilds()) {
			iconStartImage = treeNode.getOpenIcon();
		}
	}
	
	if (iconStartImage) str += '<img id="iconimage' + treeNode.getID() + '" src="' + iconStartImage + '" style="vertical-align:middle;" OnClick="selectNode(\'' + treeNode.getID() + '\')">';
	str += '&nbsp;<span unselectable="ON" style="vertical-align:middle;" class="treetitle" ID="title' + treeNode.getID() + '" OnDblClick="handleNode(\'' + treeNode.getID() + '\')" OnClick="selectNode(\'' + treeNode.getID() + '\')" onMouseOver="mouseOverNode(\'' + treeNode.getID() + '\')" onMouseOut="mouseOutNode(\'' + treeNode.getID() + '\')">';
	str += treeNode.getName();
	str += '</span>';
	str += '</nobr>';
	str += '</div>';

	if (treeNode.hasChilds()) {
		if (state == 'open') {
			str += '<div id="node' + treeNode.getID() + 'sub" style="display:block;">';
			fireOpenEvent(treeNode);
			// alert('openevent: ' + treeNode.getName());
		}
		else {
			str += '<div id="node' + treeNode.getID() + 'sub" style="display:' + (showAllNodesOnStartup == true ? 'block;' : 'none;') + ';">';
		}
		var subgroupstr = '';
		var newChar = '';

		if (!lastNode) {
			newChar = 'I';
		}
		else {
			newChar = 'B';
		}
		for(var z=0;z<treeNode.getChildCount();z++) {
			treeNode.childs[z].setLineString(linestring + newChar);
		}
		for(var z=0;z<treeNode.getChildCount();z++) {
			subgroupstr += showNode(treeNode.childs[z],(z == (treeNode.getChildCount() -1)));
		}
		str += subgroupstr;
		str += '</div>';
	}
	else {
		str += '<div id="node' + treeNode.getID() + 'sub" style="display:none;">';
		str += '</div>';
	}
	return str;
}
/*
function mouseMove() {
	if (dragging) {
		alert('bob');
	}
}
function mouseUp() {
	if (dragging) {
		alert('dropped on something!');
	}
}
*/
function startDrag(nodeID) {
	if (!dragable) {
		return;
	}
	draggedNodeID = nodeID;
	
	var srcObj = window.event.srcElement;
	while(srcObj.tagName != 'DIV') {
		srcObj = srcObj.parentElement;
	}
	floatDragElement = document.createElement('DIV');

	floatDragElement.innerHTML = srcObj.innerHTML;
	floatDragElement.childNodes[0].removeChild(floatDragElement.childNodes[0].childNodes[0]);
	
	document.body.appendChild(floatDragElement);
	floatDragElement.style.zIndex = 100;
	floatDragElement.style.position = 'absolute';
	floatDragElement.style.filter='progid:DXImageTransform.Microsoft.Alpha(1,opacity=60);';
}
function findSpanChild(element) {
	if (element.tagName == 'SPAN') {
		return element;
	}
	else {
		if (element.childNodes) {
			for(var i=0;i<element.childNodes.length;i++) {
				var value = findSpanChild(element.childNodes[i]);
				if (value != false) {
					return value;
				}
			}
			return false;
		}
	}
}
function dragEnter(nodeID) {
	if (!dragable) {
		return;
	}
	lastDraggedOnNodeID = nodeID;
	
	if (colouredElement) {
		findSpanChild(colouredElement).className = 'treetitle';
	}
	colouredElement = window.event.srcElement;
	while(colouredElement.tagName != 'DIV') {
		colouredElement = colouredElement.parentElement;
		if (colouredElement.tagName == 'BODY') {
			// Something gone seriously wrong.
			alert('Drag failure, reached <BODY>!');
			return;
		}
	}	
	findSpanChild(colouredElement).className = 'treetitleselectedfocused';
}
function dragLeave() {
	if (!dragable) {
		return;
	}
}
function endDrag(nodeID) {
	if (!dragable) {
		return;
	}
	if (lastDraggedOnNodeID != null) {
		fireMoveEvent(getTreeNode(lastDraggedOnNodeID),draggedNodeID,lastDraggedOnNodeID);
	}
}
function dragProceed() {
	if (!dragable) {
		return;
	}
	var dragged = getTreeNode(draggedNodeID);
	var newparent = getTreeNode(lastDraggedOnNodeID);

	var oldparent = dragged.getParent();
	
	oldparent.removeChild(dragged);
	newparent.addChild(dragged);
	
	refreshNode(oldparent);
	refreshNode(newparent);
	
	_dragClean()
}
function dragCancel() {
	if (!dragable) {
		return;
	}
	_dragClean()
}
/**
* Don't call this yourself.
*/
function _dragClean() {
	if (!dragable) {
		return;
	}
	if (colouredElement) {
		findSpanChild(colouredElement).className = 'treetitle';
	}
	
	floatDragElement.parentElement.removeChild(floatDragElement);
	floatDragElement = null;
	colouredElement = null;
	draggedNodeID = null;
	lastDraggedOnNodeID = null;
}
function dragMove() {
	if (!dragable) {
		return;
	}
	floatDragElement.style.top = window.event.clientY;
	floatDragElement.style.left = window.event.clientX;
}
function editEnded() {
	if (treeNodeEdited != null) {
		// treeNodeEdited.getID();
		var editTitle = document.getElementById('title' + treeNodeEdited.getID());
		var input = editTitle.childNodes[0];
	
		var newValue = input.value;
		
		if (newValue == treeNodeEdited.getName()) {
			editTitle.innerHTML = newValue;
			treeNodeEdited = null;
			return;
		}
	
		fireEditEvent(treeNodeEdited,newValue);
		
		if (!editaborted) {
			treeNodeEdited.setName(newValue);
			editTitle.innerHTML = newValue;
		}
	
		treeNodeEdited = null;
	}
}
function mouseOverNode(nodeID) {
	var treeNode = getTreeNode(nodeID);	
	if (showHover) document.getElementById('title' + nodeID).className = "treetitlehover"; 
	fireHoverEvent(treeNode,true);
}
function mouseOutNode(nodeID)
{
	var treeNode = getTreeNode(nodeID);	
	if (showHover) document.getElementById('title' + nodeID).className = (nodeID == selectedNode ? "treetitleselectedfocused" : "treetitle");
	fireHoverEvent(treeNode,false);
}
function selectNode(nodeID) {
	var treeNode = getTreeNode(nodeID);

	if (selectedNode != null) {
		if (selectedNode == nodeID) {
			if (treeNode.isEditable()) {
				if (treeNodeEdited == treeNode) {
					return;
				}
				treeNodeEdited = treeNode;
				var editTitle = document.getElementById('title' + treeNode.getID());
				editTitle.className = 'editednode';
				

				editTitle.innerHTML = '<input type="text" onKeypress="if (event.keyCode == 13) { this.onblur = null; editEnded(); }" name="editednode" class="editednodeinput">';
				var input = editTitle.childNodes[0];
				input.value = treeNode.getName();
				input.focus();
				input.select();
				input.onblur = editEnded;
			}
			return;
		}
		if (treeNodeEdited != null) {
			editEnded();
		}
		var oldNodeTitle = document.getElementById('title' + selectedNode);
		oldNodeTitle.className = 'treetitle';
	}
	selectedNode = nodeID;
	var nodetitle = document.getElementById('title' + selectedNode);
	nodetitle.className = 'treetitleselectedfocused';
	
	if (treeNode.gotHandler()) {
		treeNode.getHandler()(treeNode);
	}
	else {
		standardClick(treeNode);
	}
}
function refreshNode(treeNode) {
	var submenu = document.getElementById('node' + treeNode.getID() + 'sub');
	var str = '';
	for(var i=0;i<treeNode.getChildCount();i++) {
		var parent = treeNode.getParent();
		if (!parent) {
			treeNode.childs[i].setLineString(treeNode.getLineString() + 'B');
		}
		else {
			if (parent.childs[parent.childs.length - 1] == treeNode) {
				treeNode.childs[i].setLineString(treeNode.getLineString() + 'B');
			}
			else {
				treeNode.childs[i].setLineString(treeNode.getLineString() + 'I');
			}
		}
		str += showNode(treeNode.childs[i],i == (treeNode.getChildCount() - 1));
	}
	var actionimage = document.getElementById('handler' + treeNode.getID());
	if (treeNode.getChildCount() == 0) {
		// TreeNode haven't got any children, make sure the right image is displayed.
		if (actionimage.src.indexOf('last') == -1) {
			actionimage.src = href + 'images/' + (showLines ? 't' : 'white') + '.gif';
		}
		else {
			actionimage.src = href + 'images/' + (showLines ? 'lastnode' : 'white') + '.gif';
		}
		actionimage.onclick = null;
		
		// Close the submenu
		if (submenu) {
			submenu.style.display = 'none';
		}
	}
	else {
		// We have children, make sure to display the + and - icon.
		if (actionimage.src.indexOf('plus') != -1) {
			// The TreeNode have already got children, and displays them.
		}
		else if (actionimage.src.indexOf('minus') != -1) {
			// The TreeNode have already got children, and displays them.
		}
		else {
			if (actionimage.src.indexOf('last') == -1) {
				actionimage.outerHTML = '<img id="handler' + treeNode.getID() + '" src="' + href + 'images/' + (showLines ? 'plus' : 'plus_nolines') + '.gif" style="width:19px;height:20px;vertical-align:middle;" OnClick="handleNode(\'' + treeNode.getID() + '\');">';
			}
			else {
				actionimage.outerHTML = '<img id="handler' + treeNode.getID() + '" src="' + href + 'images/plus_last.gif" style="width:19px;height:20px;vertical-align:middle;" OnClick="handleNode(\'' + treeNode.getID() + '\');">';
			}
		}
	}
	submenu.innerHTML = str;
}
function handleNode(nodeID) {
	var treeNode = getTreeNode(nodeID);	
	if (!treeNode.hasChilds()) { // No reason to handle a node without childs.
		return;
	}
	
	var submenu = document.getElementById('node' + nodeID + 'sub');
	
	var iconimageholder = document.getElementById('iconimage' + nodeID);
	var actionimage = document.getElementById('handler' + nodeID);

	// This will be used if showRootNode is set to false.
	var firstChildOfRoot = false;
	if (actionimage.src.indexOf('_no_root') != -1) {
		firstChildOfRoot = true;
	}
	
	if (submenu.style.display == 'none') {
		writeStates(nodeID,'open');
		fireOpenEvent(treeNode);
		submenu.style.display = 'block';

		if (iconimageholder) iconimageholder.src = treeNode.getOpenIcon();
	
		if (actionimage.src.indexOf('last') == -1) {
			actionimage.src = href + 'images/' + ((firstChildOfRoot) ? 'minus_no_root' : (showLines ? 'minus' : 'minus_nolines')) + '.gif';
		}
		else {
			actionimage.src = href + 'images/' + ((firstChildOfRoot) ? 'minus_last_no_root' : (showLines ? 'minus_last' : 'minus_nolines')) + '.gif';
		}
	}
	else {
		writeStates(nodeID,'closed');
		submenu.style.display = 'none';
		
		if (iconimageholder) iconimageholder.src = treeNode.getIcon();
		
		if (actionimage.src.indexOf('last') == -1) {
			actionimage.src = href + 'images/' + ((firstChildOfRoot) ? 'plus_no_root' : (showLines ? 'plus' : 'plus_nolines')) + '.gif';
		}
		else {
			actionimage.src = href + 'images/' + ((firstChildOfRoot) ? 'plus_last_no_root' : (showLines ? 'plus_last' : 'plus_nolines')) + '.gif';
		}
	}
}
function fireHoverEvent(treeNode,hover) {
	if (treeNode.gotHoverEventListeners()) {
		for(var i=0;i<treeNode.hovereventlisteners.length;i++) {
			eval(treeNode.hovereventlisteners[i] + '(\'' + treeNode.getID() +'\',' + hover + ');');
		}
	}
	else standardHover(treeNode,hover);
}
function fireOpenEvent(treeNode) {
	if (treeNode.gotOpenEventListeners()) {
		for(var i=0;i<treeNode.openeventlisteners.length;i++) {
			eval(treeNode.openeventlisteners[i] + '(\'' + treeNode.getID() + '\');');
		}
	}
}
function fireEditEvent(treeNode,newVal) {
	if (treeNode.gotEditEventListeners()) {
		for(var i=0;i<treeNode.editeventlisteners.length;i++) {
			eval(treeNode.editeventlisteners[i] + '(\'' + treeNode.getID() + '\',\'' + escape(newVal) + '\');');
		}
	}
}
function fireMoveEvent(treeNode,draggedNodeID,droppedOnNodeID) {
	if (treeNode.gotMoveEventListeners()) {
		for(var i=0;i<treeNode.moveeventlisteners.length;i++) {
			eval(treeNode.moveeventlisteners[i] + '(' + draggedNodeID + ',' + droppedOnNodeID + ');');
		}
	}
}
function blurSelection() {
	if (selectedNode != null) {
		var oldNodeTitle = document.getElementById('title' + selectedNode);
		oldNodeTitle.className = 'treetitleselectedblured';
	}
}
function focusSelection() {
	if (selectedNode != null) {
		var oldNodeTitle = document.getElementById('title' + selectedNode);
		oldNodeTitle.className = 'treetitleselectedfocused';
	}
}
function getCookieVal (offset) {  
	var endstr = document.cookie.indexOf (";",offset);  
	if (endstr == -1) {
		endstr = document.cookie.length;
	}
	return unescape(document.cookie.substring(offset,endstr));
}
function getCookie (name) {  
	var arg = name + "=";
	var alen = arg.length;
	var clen = document.cookie.length;
	var i = 0;
	while (i < clen) {
		var j = i + alen;
		if (document.cookie.substring(i, j) == arg) {
			return getCookieVal(j);
		}
		i = document.cookie.indexOf(" ", i) + 1;
		if (i == 0) {
			break;
		}
	}
	return null;
}
function setCookie (name, value) {  
	var argv = setCookie.arguments;  
	var argc = setCookie.arguments.length;  
	var expires = (argc > 2) ? argv[2] : null;  
	var path = (argc > 3) ? argv[3] : null;  
	var domain = (argc > 4) ? argv[4] : null;  
	var secure = (argc > 5) ? argv[5] : false;  
	document.cookie = name + "=" + escape (value) + ((expires == null) ? "" : ("; expires=" + expires.toGMTString())) + ((path == null) ? "" : ("; path=" + path)) + ((domain == null) ? "" : ("; domain=" + domain)) + ((secure == true) ? "; secure" : "");
}
function expandNode() {
	var state = getState(selectedNode);
	if (state == 'open') {
		var currentTreeNode = getTreeNode(selectedNode);
		if (currentTreeNode.hasChilds()) {
			selectNode(currentTreeNode.childs[0].getID());
		}
	}
	else {
		handleNode(selectedNode);
	}
}
function subtractNode() {
	var state = getState(selectedNode);
	if (state == 'closed') {
		var currentTreeNode = getTreeNode(selectedNode);
		var parent = currentTreeNode.getParent();
		if (parent != null && parent != rootNode) {
			selectNode(parent.getID());
		}
	}
	else {
		handleNode(selectedNode);
	}
}
function selectPrevNode() {
	var currentTreeNode = getTreeNode(selectedNode);
	if (currentTreeNode.prevSibling != null) {

		var state = getState(currentTreeNode.prevSibling.getID());

		if (state == 'open' && currentTreeNode.prevSibling.hasChilds()) {
			// We have to find the last open child of the previoussiblings childs.
			var current = currentTreeNode.prevSibling.childs[currentTreeNode.prevSibling.childs.length - 1];
			var currentstate = 'open';
			while (current.hasChilds() && (getState(current.getID()) == 'open')) {
				current = current.childs[current.childs.length - 1];
			}
			selectNode(current.getID());
		}
		else {
			selectNode(currentTreeNode.prevSibling.getID());
		}
	}
	else {
		if (currentTreeNode.getParent() != null && currentTreeNode.getParent() != rootNode) {
			selectNode(currentTreeNode.getParent().getID());
		}
	}
}
function selectNextNode() {
	var currentTreeNode = getTreeNode(selectedNode);

	var state = getState(selectedNode);
	if (state == 'open' && currentTreeNode.hasChilds()) {
		selectNode(currentTreeNode.childs[0].getID());
	}	
	else {
		if (currentTreeNode.nextSibling != null) {
			selectNode(currentTreeNode.nextSibling.getID());
		}
		else {
			// Continue up the tree until we either hit null, or a parent which have a child.
			var parent = currentTreeNode;
			while ((parent = parent.getParent()) != rootNode) {
				if (parent.nextSibling != null) {
					selectNode(parent.nextSibling.getID());
					break;
				}
			}
			/*
			if (currentTreeNode.getParent().nextSibling != null) {
				selectNode(currentTreeNode.getParent().nextSibling.getID());
			}
			*/
		}
	}
}
function keyDown(event) {
	if (window.event) {
		event = window.event;
	}
	if (event.keyCode == 38) { // Up
		selectPrevNode();
		return false;
	}
	else if (event.keyCode == 40) { // Down
		selectNextNode();
		return false;
	}
	else if (event.keyCode == 37) { // left
		subtractNode();
		return false;
	}
	else if (event.keyCode == 39) { // right
		expandNode();
		return false;
	}
}
document.onkeydown = keyDown;
