/*

XTree - JavaScript-Tree-Navigation; (c) C.Amann 2005, all rights reserved
	
	c.amann@ac.online.de
	www.ac-online.de

*/

updateProgress();

function Tree(treeId) {

	var treeNodes = new Array();
	var nodesToShowOrHide = new Array();
	var nodesToMove = new Array();
	var nodesIndex = 0;
	var tasks = new Array();
	var taskIndex = 0;
	var inMotion = false;
	var currentParentLayer = null;
	var tree = this;
	var animated = true;
	var model = null;
	var currentSelectedId = "";
	
	var numberOfIconsToPreload = 3;
	var iconPreloadIndex = 0;
	
	var currentTaskNode = null;
	var initialized = false;
	
	var callStructureOnSelect = true;

	this.draw = draw;
	this.toggle = toggle;
	this.update = update;
	
	this.makeModel = makeModel;
	this.isLeaf = isLeaf;
	
	this.mouseOver = mouseOver;
	this.mouseOut = mouseOut;
	
	this.doNextTask = doNextTask;
	
	this.expandCurrent = expandCurrent;
	this.collapseCurrent = collapseCurrent;
	this.selectCurrent = selectCurrent;
	this.setProperties = setProperties;
	
	this.expandId = expandId;
	this.selectId = selectId;
	this.expandRootNode = expandRootNode;
	
	this.id = treeId;

	this.motionShow = motionShow;
	this.motionHide = motionHide;
	this.showNextNode = showNextNode;
	this.hideNextNode = hideNextNode;
	
	this.insertStructure = insertStructure;
	
	var model = null;
	//makeModel(model);
	
	engine.registerComponent(treeId, this);
	
	//makeModel(treeNodes);
	
	var SHOW_STEPS = true;
	var ANIMATION_DELAY = 1;
	var ANIMATION_STEP_WIDTH = 10;
	var SHOW_ROOT_NODE = false;
	var SHOW_ONE_BRANCH = true;
	var SELECT_LEAF_ON_TOGGLE = true;
	var DRAW_FROM_LEVEL = 0;

	function setProperties(properties) {
		SHOW_STEPS = properties['SHOW_STEPS'] == "true";
		ANIMATION_DELAY = parseInt(properties['ANIMATION_DELAY']);
		ANIMATION_STEP_WIDTH = parseInt(properties['ANIMATION_STEP_WIDTH']);
		SHOW_ROOT_NODE = properties['SHOW_ROOT_NODE'] == "true";
		SHOW_ONE_BRANCH = properties['SHOW_ONE_BRANCH'] == "true";
		SELECT_LEAF_ON_TOGGLE = properties['SELECT_LEAF_ON_TOGGLE'] == "true";
		DRAW_FROM_LEVEL = parseInt(properties['DRAW_FROM_LEVEL']);		
		model = new TreeModel(SHOW_STEPS);
	}
	
	function insertStructure(structure, parentStructure) {
		var parentNode = model.getNode(parentStructure);
		var treeNode = model.addStructureTreeNode(structure, parentNode);
		treeNode.setLevel(3);
				
		treeNodes.push(treeNode);
		
		var treeNodeAfter = getNodeAfter(treeNode);
		
		var html = treeNode.getInnerHtml();
	
		var treeNodeElement = document.createElement("div");
		
		var idAttrib = document.createAttribute("id");
		idAttrib.nodeValue = treeNode.id;
	
		var styleAttrib = document.createAttribute("class");
		styleAttrib.nodeValue = "XtreeNewTest";
	
		treeNodeElement.setAttributeNode(idAttrib);
		treeNodeElement.setAttributeNode(styleAttrib);
		
		treeNodeElement.innerHTML = html;
		
		//alert(treeNodeAfter.title);
		
		//alert(treeNodeElement.outerHTML);
		
		var elementAfter = null;
		if (treeNodeAfter != null) {
			elementAfter = document.getElementById(treeNodeAfter.id);
		}
		document.getElementById(treeId).insertBefore(treeNodeElement, elementAfter);
		
		
		
	}
	
	function getNodeAfter(treeNode) {
		var nodeAfter = null;
		var parentNode = treeNode.parent;
		var treeNodeSiblings = getSiblings(treeNode);
		for (var i = 0; i < treeNodeSiblings.length; i++) {
			if (treeNodeSiblings[i].position = treeNode.position + 1) {
				nodeAfter = treeNodeSiblings[i];
				break;
			}
		}
		
		if (nodeAfter == null) {
			var nodesToMove = new Array();
			nodesToMove = makeNodesToMove(parentNode, nodesToMove);
			if (nodesToMove.length > 0) {
				nodeAfter = nodesToMove[0];
			}
		}
		
		
		return nodeAfter;
			
		
	}
	
	function addTask(name, treeNode) {
		var task = new Task(name, treeNode);
		tasks.push(task);
	}
	
	function iconLoaded() {
		iconPreloadIndex++;
		if (iconPreloadIndex == numberOfIconsToPreload) {
			initialized = true;
			draw();
		}
		//alert("icon loaded ");
	}
	
	
	function loadIcons() {
		var openIcon = new Image();
		openIcon.onload = iconLoaded;
		openIcon.src = tree_openIcon;
		
		var closedIcon = new Image();
		closedIcon.onload = iconLoaded;
		closedIcon.src = tree_closedIcon;
		
		var leafIcon = new Image();
		leafIcon.onload = iconLoaded;
		leafIcon.src = tree_leafIcon;
	}
	
	function draw() {
		//initialized = true;
		/*
		if (!initialized) {
			loadIcons();
			return;
		}
		*/
		var step = engine.getCurrentStep();
		var structure = database.getStructureById(step.structureId);
		if (step.hidden || structure.hidden) return;
		var ancestors = structure.getAncestors();
		
		var rootId = null;
		
		for (var i = 0; i < ancestors.length; i++) {
			//alert(ancestors[i].title + " " + ancestors[i].level);
			if (ancestors[i].level == DRAW_FROM_LEVEL) {
				rootId = ancestors[i].id;
				break;
			}
		}
		
		var html = new StringBuffer();
		if (rootId != null) {
			treeNodes = model.getTreeNodes(this, rootId);
			var length = treeNodes.length;
			
			for (var i = 0; i < length; i++) {
				html.append(treeNodes[i].render());
			}
		}
		 
		return html.toString();
	}
	
	function update(content) {
		//alert(ancestors[ancestors.length - 1].title + " " + ancestors[ancestors.length - 1].parentId);
		var step = engine.getCurrentStep();
		var structure = database.getStructureById(step.structureId);
		if (step.hidden || structure.hidden) return;
		var nodeToSelect = getTreeNodeById(treeId + "_" + structure.id);
		
		
		if (!content.visible) {
			content.divRef.innerHTML = "";
			return;
		}
		
		
		if (nodeToSelect == null) {
			var parentStructure = database.getStructureById(structure.parentId);
			nodeToSelect = getTreeNodeById(treeId + "_" + parentStructure.id);
			if (nodeToSelect == null) {
				var html = "";
				currentSelectedId = "";
				if (content.visible) {
					html = this.draw();
				}
				content.divRef.innerHTML = html;
			}
		}
		
		nodeToSelect = getTreeNodeById(treeId + "_" + structure.id);
		
		if (nodeToSelect) {
			selectId(structure.id);
		}
		else {
			var parentStructure = database.getStructureById(structure.parentId);
			nodeToSelect = getTreeNodeById(treeId + "_" + parentStructure.id);
			if (nodeToSelect) {
				selectId(parentStructure.id);
			}
		}
				
	}
	
	function mouseOver(id) {
		var myTreeNode = getTreeNodeById(id);
		myTreeNode.setHover(true);
		myTreeNode.redraw();
	}
	
	function mouseOut(id) {
		var myTreeNode = getTreeNodeById(id);
		myTreeNode.setHover(false);
		myTreeNode.redraw();
	}
	

	function toggle(id) {
		if (inMotion) return;
		tasks = new Array();
		taskIndex = 0;
		var myTreeNode = getTreeNodeById(id);
		
		var myStructure = myTreeNode.getStructure();
		if (myStructure.type == "testunit") {
			if (myStructure.hideNavigationTree) {
				var testunitStructures = myStructure.getStructures();
				var myStep = database.getStepById(testunitStructures[0].id);
				engine.jumpToStep(myStep.id);
				return;
			}
		}
		
		
		
		if (myTreeNode.isLeaf()) {
			addTask("select", myTreeNode);
		}
		else {
			if (myTreeNode.isExpanded()) {
				if (!SHOW_ONE_BRANCH) {
					addTask("collapse", myTreeNode);
				}
				
				if (!SHOW_STEPS) {
					var id = myTreeNode.id;
					id = id.substring(id.indexOf("_") + 1);
					var structure = database.getStructureById(id);
					var mySteps = structure.getSteps();
					if (mySteps.length > 0) {
						engine.jumpToStep(mySteps[0].id);
					}
				}
			}
			else {
				if (SHOW_ONE_BRANCH) {
					var expandedNode = getExpandedSiblingNode(myTreeNode);
					if (expandedNode != null) {
						addTask("collapse", expandedNode);
					}
				}
				if (SELECT_LEAF_ON_TOGGLE) {
									
					var leafNode = getDeepestLeaf(myTreeNode);
					if (!leafNode) {
						
						addTask("select", myTreeNode);
						addTask("expand", myTreeNode);
						
						
						
						
						
					}
					else {
						addRequiredExpandTasks(leafNode);
						addTask("select", leafNode);
					}
				}
				else {
					addTask("expand", myTreeNode);
				}
			}
		}
		
		//alert(printTaskArray(tasks));
		callStructureOnSelect = true;
		
		doNextTask();
		
	}
	
	function unselectSelected() {
		for (var i = 0; i < treeNodes.length; i++) {
			if (treeNodes[i].isSelected()) {
				treeNodes[i].setSelected(false);
				//break;
			}
		}
	}
	
	function getDeepestLeaf(treeNode) {
		var myLeaf = null;
		
		if (!SHOW_STEPS) {
			var id = treeNode.id;
			id = id.substring(id.indexOf("_") + 1);
			var structure = database.getStructureById(id);
			if (structure.getSteps().length > 0) {
				return null;
			}
		}
		
		var children = getChildren(treeNode);
		for (var i = 0; i < children.length; i++) {
			//alert("node: " + children[i].id);
			if (!children[i].isLeaf()) {
				myLeaf = getDeepestLeaf(children[i]);
				if (myLeaf != null) break;
			}
			else {
				myLeaf = children[i];
				break;
			}
		}
		return myLeaf;
	
	
	}
	
	
	
	function doNextTask() {
		if (!inMotion) {
			var nextTask = tasks[taskIndex];
			if (nextTask == null) return;
			currentTaskNode = nextTask.treeNode;
			var taskString = "component['" + treeId + "']." + nextTask.name + "Current()";
			if (nextTask.name == "collapseExpanded") {
				taskString = nextTask.name + "()";
			}
			//alert("do Task: " + taskString);
			window.setTimeout(taskString, ANIMATION_DELAY);
			taskIndex++;
			if (taskIndex < tasks.length) {
				window.setTimeout("component['" + treeId + "'].doNextTask()", 100);
			}
		}
		else {
			window.setTimeout("component['" + treeId + "'].doNextTask()", 100);
		}
	}
	
	function getExpandedSiblingNode(treeNode) {
		var siblings = getSiblings(treeNode);
		var myNode = null;
		for (var i = 0; i < siblings.length; i++) {
			if (siblings[i].isExpanded()) {
				myNode = siblings[i];
				break;
			}
		}
		return myNode;
	}
	
	function addTreeNode(treeNode) {
		treeNodes.push(treeNode);
		treeNode.setTree(tree);
	}
	
	function debugTreeNodes() {
		var out = "";
		for (var i = 0; i < treeNodes.length; i++) {
			var parentId = "null";
			if (!treeNodes[i].isRootNode) {
				parentId = treeNodes[i].parent.id;
			}
			
			out += treeNodes[i].id + " " + parentId + "\n";
		}
		alert(out);
	}

	function makeModel() {
		
		model = treeModel;
		if (treeModel) {
			treeNodes = treeModel.getTreeNodes();
			//debugTreeNodes();
			return;
		}
		
		treeNodes = new Array();
		nodesToShowOrHide = new Array();
		nodesToMove = new Array();
		nodesIndex = 0;
		tasks = new Array();
		taskIndex = 0;
		inMotion = false;
		currentParentLayer = null;
		iconPreloadIndex = 0;
		currentTaskNode = null;
		initialized = false;

		var zindex = 1000;

		// root node
		var rootNode = new TreeNode("rootnode", "Root", 0, 0, zindex--, null);
		addTreeNode(rootNode);

		// 1st level
		for (var i = 0; i < 2; i++) {
			var treeNodeLevel1 = new TreeNode("node" + i, "Chapter " + i, 1, i, zindex--, rootNode);
			addTreeNode(treeNodeLevel1);

			// 2nd level
			for (var ii = 0; ii < 2; ii++) {
				var treeNodeLevel2 = new TreeNode("node" + i + "." + ii, "Chapter " + i + "." + ii, 2, ii, zindex--, treeNodeLevel1);
				addTreeNode(treeNodeLevel2);

				// 3rd level
				for (var iii = 0; iii < 3; iii++) {
					var treeNodeLevel3 = new TreeNode("node" + i + "." + ii + "." + iii, "Chapter " + i + "." + ii + "." + iii, 3, iii, zindex--, treeNodeLevel2);
					addTreeNode(treeNodeLevel3);
				}
			}
		}
	}


	// MODEL HELPERS
	
	function isLeaf(treeNode) {
		var isLeaf = true;
		for (var i = 0; i < treeNodes.length; i++) {
			if (!treeNodes[i].isRootNode) {
				if (treeNodes[i].parent.id == treeNode.id) {
					isLeaf = false;
					break;
				}
			}
		}
		return isLeaf;
	}

	function getTreeNodeById(id) {
		var myTreeNode = null;
		for (var i = 0; i < treeNodes.length; i++) {
			if (treeNodes[i].id == id) {
				myTreeNode = treeNodes[i];
				break;
			}
		}
		return myTreeNode;
	}

	function getChildren(treeNode) {
		var children = new Array();
		for (var i = 0; i < treeNodes.length; i++) {
			if (!treeNodes[i].isRootNode && treeNodes[i].parent.id == treeNode.id) {
				children.push(treeNodes[i]);
			}
		}
		return children;
	}
	
	function getSiblings(treeNode) {
			var siblings = new Array();
			if (treeNode.isRootNode) return siblings;
			for (var i = 0; i < treeNodes.length; i++) {
				if (!treeNodes[i].isRootNode && treeNodes[i] != treeNode && treeNodes[i].parent.id == treeNode.parent.id) {
					siblings.push(treeNodes[i]);
				}
			}
			return siblings;
	}

	function addVisibleChildren(treeNode, nodes) {
		var children = getChildren(treeNode);
		for (var i = 0; i < children.length; i++) {
			if (children[i].isVisible()) {
				nodes.push(children[i]);
				nodes = addVisibleChildren(children[i], nodes);
			}
		}
		return nodes;
	}

	function makeNodesToMove(nodeToExpand, nodesToMove) {
		if (nodeToExpand.isRootNode) return nodesToMove;

		for (var i = 0; i < treeNodes.length; i++) {
			if (treeNodes[i] != nodeToExpand && treeNodes[i].parent != null &&
				treeNodes[i].parent.id == nodeToExpand.parent.id &&
				treeNodes[i].position > nodeToExpand.position) {

				nodesToMove.push(treeNodes[i]);
				nodesToMove = addVisibleChildren(treeNodes[i], nodesToMove);
			}
		}

		nodesToMove = makeNodesToMove(nodeToExpand.parent, nodesToMove);
		return nodesToMove;
	}
	
	function expandCurrent() {
		expand(currentTaskNode);
	}
	
	function collapseCurrent() {
		collapse(currentTaskNode);
	}
	
	function selectCurrent() {
		select(currentTaskNode);
	}
	
	function addRequiredExpandTasks(nodeToExpand) {
		if (nodeToExpand.isRootNode) return;
		var parentNode = nodeToExpand.parent;
		addRequiredExpandTasks(parentNode);
		if (!parentNode.isExpanded()) {
			addTask("expand", parentNode);
		}
		
	}
	
	function isAnchestor(treeNode, anchestorOf) {
		//alert("is " + treeNode.title + " ancestor of " + anchestorOf.title);
		var isAnchestor = false;
		while (true) {
			var parent = anchestorOf.parent;
			if (parent == null) break;
			if (treeNode == parent) {
				isAnchestor = true;
				break;
			}
			anchestorOf = parent;
		}
		//alert(isAnchestor);
		return isAnchestor;
		
	}
	
	function addRequiredCollapseTasks(nodeToExpand) {
		for (var i = treeNodes.length - 1; i > -1; i--) {
			if (treeNodes[i].isExpanded() && !isAnchestor(treeNodes[i], nodeToExpand)) {
				addTask("collapse", treeNodes[i]);
			}
		
		
		}
	}
	
	function expandRootNode() {
		var rootNode = null;
		for (var i = 0; i < treeNodes.length; i++) {
			if (treeNodes[i].isRootNode) {
				rootNode = treeNodes[i];
				break;
			}
		}
		if (rootNode != null) {
			expandId(rootNode.id);
		}
		
	}
	
	function collapseFirstLevel() {
		var rootNode = null;
		for (var i = 0; i < treeNodes.length; i++) {
			if (treeNodes[i].isRootNode) {
				rootNode = treeNodes[i];
				break;
			}
		}
		if (rootNode != null) {
			var children = getChildren(rootNode);
			for (var i = 0; i < children.length; i++) {
				addTask("collapse", children[i]);
			}
		}
	
	}
		
	
	
	function expandId(id) {
		tasks = new Array();
		taskIndex = 0;
		var nodeToExpand = getTreeNodeById(id);
		if (!nodeToExpand) return;
		
		if (SHOW_ONE_BRANCH) {
			addRequiredCollapseTasks(nodeToExpand);
			
		}
		
		if (!nodeToExpand.isRootNode) {
			addRequiredExpandTasks(nodeToExpand);
		}
		
		addTask("expand", nodeToExpand);
		//alert("tasks: " + printTaskArray(tasks));
		
		doNextTask();
	}
	
	function selectId(id) {
		var id2 = id;
		if ((id + "").indexOf(treeId + "_") == -1) {
			id = treeId + "_" + id;
		}
		
		if (id == currentSelectedId) {
			return;
		}
		
		callStructureOnSelect = false;
		
		var nodeToSelect = getTreeNodeById(id);
		
		if (!nodeToSelect) {
			if (!SHOW_STEPS) {
				var step = database.getStepById(id2);
				if (step) {
					var structure = database.getStructureById(step.structureId);
					nodeToSelect = getTreeNodeById(treeId + "_" + structure.id);
				}
				//treeNodeToSelect.selected = true;
				//treeNodeToSelect.redraw();
			}
			//return;
		}
		
		// hack to make tests selectable in the tree
		/*
		if (nodeToSelect == null) {
			
			id = id.substring(id.indexOf("_") + 1);
			var structure = database.getStructureById(id);
			
			var parentStructure = database.getStructureById(structure.parentId);
			if (parentStructure != null) {
				//alert(treeId + "_" + parentStructure.id);
				nodeToSelect = getTreeNodeById(treeId + "_" + parentStructure.id);
			}
			if (nodeToSelect == null || nodeToSelect.parent == null) return;
			//alert("***nodeToSelect " + nodeToSelect.title);
			
		}
		*/
		
		//alert("select " + nodeToSelect.title);
		
		tasks = new Array();
		taskIndex = 0;
		
		if (nodeToSelect != null) {
			if (SHOW_ONE_BRANCH) {
				addRequiredCollapseTasks(nodeToSelect);
			}

			if (!nodeToSelect.isRootNode) {
				addRequiredExpandTasks(nodeToSelect);
			}

			addTask("select", nodeToSelect);
		}
		else {
			collapseFirstLevel();
		}
		currentSelectedId = id;
		
		
		doNextTask();
	}

	function isFirstLevelExpanded() {
		var rootNode = null;
		for (var i = 0; i < treeNodes.length; i++) {
			if (treeNodes[i].isRootNode) {
				rootNode = treeNodes[i];
				break;
			}
		}
		//alert(rootNode.isExpanded());
			
		return rootNode.isExpanded();


	}
	
	
	
	function makeNodesToShow(nodeToExpand, nodesToShowOrHide) {
		for (var i = 0; i < treeNodes.length; i++) {
			if (!treeNodes[i].isRootNode && treeNodes[i].parent.id == nodeToExpand.id) {
				nodesToShowOrHide.push(treeNodes[i]);
				
			}
		}
		return nodesToShowOrHide;
	}
	
	function printNodeArray(array) {
		var out = "";
		for (var i = 0; i < array.length; i++) {
			out += array[i].id;
			if (i < array.length - 1) out += ",";
		}
		return out;
	}
	
	function printTaskArray(array) {
			var out = "";
			for (var i = 0; i < array.length; i++) {
				out += array[i].name + " " + array[i].treeNode.getStructure().title;
				if (i < array.length - 1) out += ",";
			}
			return out;
	}
	
	function select(nodeToSelect) {
		//alert(nodeToSelect.title);
		if (!nodeToSelect.isSelected()) {
			unselectSelected();
			nodeToSelect.setSelected(true);
			nodeToSelect.setVisited(true);
			//alert("###1 " + nodeToSelect.title);
		
			var object = nodeToSelect.getStructure();
			if (object instanceof Structure) {
				var structure = nodeToSelect.getStructure();
				var steps = structure.getSteps();
				if (steps.length > 0) {
			    	callStep(steps[0].id);
				}
			}
			if (object instanceof CTStep) {
				callStep(object.id);
			}
			//callStructure(structure.id + "");
		}
		
	}
	
	function callStep(id) {
	    if (callStructureOnSelect) {
	        engine.jumpToStep(id);
	    }
	}
	
	function callStructure(id) {
		
	}
	



	function expand(nodeToExpand) {
		if (inMotion) return;
		if (nodeToExpand == null) return;
		
		//alert("expand " + nodeToExpand.title);
		
		nodesToShowOrHide = new Array();
		nodesToMove = new Array();
		
		nodesToShowOrHide = makeNodesToShow(nodeToExpand, nodesToShowOrHide);
		
		/*
		for (var i = 0; i < nodesToShowOrHide.length; i++) {
			alert(nodesToShowOrHide[i].title);
		}
		*/
		
		nodesToMove = makeNodesToMove(nodeToExpand, nodesToMove);
		currentParentLayer = nodeToExpand.getLayer();

		nodesIndex = 0;
		inMotion = true;
		nodeToExpand.setExpanded(true);
		
		showNextNode();
		
	}

	function collapse(nodeToCollapse) {
		if (inMotion) return;
		if (nodeToCollapse == null) return;

		nodesToShowOrHide = new Array();
		nodesToMove = new Array();

		if (nodeToCollapse == null) return;

		
		for (var i = 0; i < treeNodes.length; i++) {
			if (!treeNodes[i].isRootNode && treeNodes[i].parent.id == nodeToCollapse.id) {
				nodesToShowOrHide.push(treeNodes[i]);
				nodesToShowOrHide = addVisibleChildren(treeNodes[i], nodesToShowOrHide);
			}
		}

		nodesToMove = makeNodesToMove(nodeToCollapse, nodesToMove);

		currentParentLayer = nodeToCollapse.getLayer();

		nodesIndex = nodesToShowOrHide.length - 1;
		inMotion = true;
		nodeToCollapse.setExpanded(false);
		hideNextNode();
		
		
	}

	// ANIMATION

	function showNextNode() {
		//alert("nextNode");
		if (nodesIndex >= nodesToShowOrHide.length) {
			nodesIndex = 0;
			nodesToShowOrHide = new Array();
			inMotion = false;
			return;
		}

		var layer = nodesToShowOrHide[nodesIndex].getLayer();
		
		//var innerLayer = document.getElementById(nodesToShowOrHide[nodesIndex].id + "_node");
		//alert(innerLayer.style.borderBottomWidth);
		
		var top = 0;
		var layerHeight = parseInt(layer.scrollHeight) + parseInt(layer.style.borderBottomWidth) + parseInt(layer.style.borderTopWidth);
		var maxTop = layerHeight;
		if (currentParentLayer != null) {
			var currentParentLayerHeight = parseInt(currentParentLayer.scrollHeight) + parseInt(currentParentLayer.style.borderBottomWidth) + parseInt(currentParentLayer.style.borderTopWidth);
			top = parseInt(currentParentLayer.style.top) + currentParentLayerHeight - layerHeight;
			maxTop = currentParentLayerHeight + parseInt(currentParentLayer.style.top);
		}

		if (nodesIndex > 0) {
			var previousLayer = nodesToShowOrHide[nodesIndex - 1].getLayer();
			var previousLayerTop = parseInt(previousLayer.style.top);
			var previousLayerHeight = parseInt(previousLayer.scrollHeight) + parseInt(previousLayer.style.borderBottomWidth) + parseInt(previousLayer.style.borderTopWidth);
			top = previousLayerHeight + previousLayerTop - layerHeight;
			maxTop = previousLayerTop + previousLayerHeight;
		}
		layer.style.top = top;
		layer.style.visibility = "visible";
		
		//alert(top);
		
		motionShow(maxTop);
	}

	function hideNextNode() {
		if (nodesIndex < 0) {
			nodesIndex = 0;
			nodesToShowOrHide = new Array();
			inMotion = false;
			return;
		}
		
		nodesToShowOrHide[nodesIndex].setExpanded(false);
		nodesToShowOrHide[nodesIndex].setSelected(false);
		
		var layer = nodesToShowOrHide[nodesIndex].getLayer();
		var layerHeight = parseInt(layer.scrollHeight);
		
		var bottomBorderWidth = parseInt(layer.style.borderBottomWidth);
		var topBorderWidth = parseInt(layer.style.borderTopWidth);
		
		layerHeight = layerHeight + topBorderWidth + bottomBorderWidth;
		minTop = 0;

		if (currentParentLayer != null) {
			minTop = parseInt(currentParentLayer.style.top) + (parseInt(currentParentLayer.scrollHeight) - layerHeight);
		}

		if (nodesIndex > 0) {
			var previousLayer = nodesToShowOrHide[nodesIndex - 1].getLayer();
			var previousLayerTop = parseInt(previousLayer.style.top);
			minTop = previousLayerTop + parseInt(previousLayer.scrollHeight) - layerHeight;
		}
		
		motionHide(minTop);
	}

	function motionShow(maxTop) {
		var layer = nodesToShowOrHide[nodesIndex].getLayer();
		var top = parseInt(layer.style.top);
		var finished = false;
		var tempTop = 0;
		var stepWidthDiff = 0;

		top += ANIMATION_STEP_WIDTH;
		if (top > maxTop) {
			stepWidthDiff = top - maxTop;
			top = maxTop;
			finished = true;
		}
		layer.style.top = top;

		for (var i = 0; i < nodesToMove.length; i++) {
			if (nodesToMove[i].isVisible()) {
				tempTop = parseInt(nodesToMove[i].getLayer().style.top);
				nodesToMove[i].getLayer().style.top = tempTop + ANIMATION_STEP_WIDTH - stepWidthDiff;
			}
		}

		if (!finished) {
			window.setTimeout("component['" + treeId + "'].motionShow(" + maxTop + ")", ANIMATION_DELAY);
		}
		else {
			nodesIndex++;
			window.setTimeout("component['" + treeId + "'].showNextNode()", ANIMATION_DELAY);
		}
	}

	function motionHide(minTop) {
		var layer = nodesToShowOrHide[nodesIndex].getLayer();
		var top = parseInt(layer.style.top);
		var finished = false;
		var tempTop = 0;
		var stepWidthDiff = 0;

		top -= ANIMATION_STEP_WIDTH;
		if (top < minTop) {
			stepWidthDiff = minTop - top;
			top = minTop;
			finished = true;
		}

		layer.style.top = top;

		for (var i = 0; i < nodesToMove.length; i++) {
			if (nodesToMove[i].isVisible()) {
				tempTop = parseInt(nodesToMove[i].getLayer().style.top);
				nodesToMove[i].getLayer().style.top = tempTop - ANIMATION_STEP_WIDTH + stepWidthDiff;
			}
		}

		if (!finished) {
			window.setTimeout("component['" + treeId + "'].motionHide(" + minTop + ")", ANIMATION_DELAY);
		}
		else {
			layer.style.visibility = "hidden";
			layer.style.top = 0;
			nodesIndex--;
			hideNextNode();
		}
	}

	

}

function Task(name, treeNode) {
	this.name = name;
	this.treeNode = treeNode;
}




function TreeNode(id, title, level, position, zindex, parent) {
	this.id = id;
	this.title = title;
	this.level = level;
	this.parent = parent;
	this.zindex = zindex;
	this.position = position;
	this.render = render;
	this.setHover = setHover;
	
	var isRootNode = (parent == null);
	var layer = null;
	var tree = null;
	var expanded = false;
	var selected = false;
	var node = this;
	var structure = null;
	var visited = false;
	var hover = false;
	var section = 0;

	this.isRootNode = isRootNode;
	this.getLayer = getLayer;
	this.getInnerHtml = getInnerHtml;
	this.isVisible = isVisible;
	this.tree = tree;
	this.setTree = setTree;
	this.setSection = setSection;
	this.setExpanded = setExpanded;
	this.setVisited = setVisited;
	this.isVisited = isVisited;
	this.isExpanded = isExpanded;
	this.isLeaf = isLeaf;
	this.setSelected = setSelected;
	this.isSelected = isSelected;
	this.setStructure = setStructure;
	this.getStructure = getStructure;
	this.setLevel = setLevel;
	this.redraw = redraw;
	this.getLevel = getLevel;
	
	function setTree(myTree) {
		tree = myTree;
		
		//id = tree.id + "_" + id;
	}
	
	function setLevel(_level) {
		level = _level;
	}
	
	function getLevel() {
		return level;
	}
	
	function setSection(_section) {
		section = _section;
	}
	
	function setHover(_hover) {
		hover = _hover;
	}
	
	function setStructure(myStructure) {
		structure = myStructure;
	}
	
	function getStructure() {
		return structure;
	}
	
	function setVisited(_visited) {
		visited = _visited;
	}
	
	function isVisited() {
		return visited;
	}
	
	function isLeaf() {
		return tree.isLeaf(node);
	}
	
	function setExpanded(_expanded) {
		expanded = _expanded;
		redraw();
	}
	
	function isExpanded() {
		return expanded;
	}
	
	function setSelected(_selected) {
		selected = _selected;
		redraw();
	}
	function isSelected() {
		return selected;
	}

	function calculateIndent(indent) {
		if (tree.showRootNode) {
			indent = level * indent;
		}
		else {
			indent = (level - 1) * indent;
		}
		return indent;
	}

	function isVisible() {
		if (layer == null) {
			return false;
		}
		return getLayer().style.visibility == "visible";
	}

	function getLayer() {
		if (layer == null) {
			layer = document.getElementById(id);
			//alert("getElement: " + id);
		}
		return layer;
	}

	function render(setVisible) {
		var innerHtml = getInnerHtml();
		var visibility = "hidden";
		if (setVisible) visibility = "visible";
		var rootNodeStyle = "";
		
		if (isRootNode) {
			rootNodeStyle = "top:0px;";
			if (!tree.showRootNode) {
				rootNodeStyle += "display:none;";
			}
			else {
				visibility = "visible";
			}
		}
		if (!isVisible()) {
			visibility = "hidden";
		}
		//alert(id);
		var html = new StringBuffer();
		html.append("<div id=\"");
		html.append(id);
		html.append("\" style=\"position:absolute;border:0px solid red;overflow:visible;visibility:");
		html.append(visibility);
		html.append(";");
		html.append(rootNodeStyle);
		html.append("left:0px;width:100%;z-index:");
		html.append(zindex);
		html.append("\">");
		html.append(innerHtml);
		html.append("</div>\n");
		
		return html.toString();
	}
	
	function redraw() {
		if (getLayer() != null) {
			var styleClass = createStyleClass();
			var layer = document.getElementById(id + "_node");
			layer.className = styleClass;
			var headerlayer = document.getElementById(id + "_nodeheader");
			var headerStyleClass = "XTreeLevel" + level + "HeaderSection" + section;
			if (expanded) {
				headerStyleClass += "Expanded";
			}
			if (selected) {
				headerStyleClass += "Selected";
			}
			if (hover) {
				headerStyleClass += "Hover";
			}
			//alert(headerStyleClass);
			if (headerlayer) headerlayer.className = headerStyleClass;
			//var textlayer = document.getElementById(id + "_nodetext");
			//textlayer.className = styleClass + "Text";
			//getLayer().innerHTML = getInnerHtml();
		}
	}
	
	function createStyleClass() {
		var styleClass = "XTreeLevel" + level;
		var styleExtension = "";
		
		if (selected) {
			styleExtension = "Selected";
		}
		else if (visited) {
			//styleExtension = "Visited";
		}
		else if (expanded) {
			styleExtension = "Expanded";
		}
		
		styleClass += styleExtension;
		
		if (isLeaf()) {
			styleClass += "Leaf";
		}
		
		if (hover) {
			styleClass += "Hover";
		}
		
		
		return styleClass;
	}
	
	function getInnerHtml() {
		var toggleScript = "component['" + tree.id + "'].toggle('" + id + "');";
		var mouseOverScript = "component['" + tree.id + "'].mouseOver('" + id + "');";
		var mouseOutScript = "component['" + tree.id + "'].mouseOut('" + id + "');";
		
		var styleClass = createStyleClass();
		var headerClass = "XTreeLevel" + level + "HeaderSection" + section;//styleClass + "Header";
		//alert(headerClass);
		//if (structure.visited) title = title + "+";
				
		var mousehandler = new StringBuffer();
		if (!engine.isInPreviewMode()) {
			mousehandler.append("onmousedown=\"");
			mousehandler.append(toggleScript);
			mousehandler.append("\" onmouseover=\"");
			mousehandler.append(mouseOverScript);
			mousehandler.append("\" onmouseout=\"");
			mousehandler.append(mouseOutScript);
			mousehandler.append("\"");
		}
		
		
		var titleHTML = "<span id=\"" + id + "_nodetext" + "\" class=\"" + styleClass + "Text\">" + title + "</span>";
		var html = new StringBuffer();
		var ie = document.all;
		
		// firefox renders different from IE
		if (ie) {
			html.append("<table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" style=\"padding:0px;margin:0px;border:0px yellow solid\"><tr><td id=\"" + id + "_nodeheader\" style=\"padding:0px;margin:0px;border:0px yellow solid\" class=\"" + headerClass + "\"></td>");
			html.append("<td style=\"padding:0px;margin:0px;border:none\"><a href=\"#\" class=\"");
			html.append(styleClass);
			html.append("\"  id=\"");
			html.append(id);
			html.append("_node\" ");
			html.append(mousehandler.toString());
			html.append(" HIDEFOCUS>");
			html.append(titleHTML);
			html.append("</a></td></tr></table>");
		}
		else {
			html.append("<table class=\"tree\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\"><tr class=\"tree\"><td id=\"" + id + "_nodeheader\" style=\"padding:0px;margin:0px;border:0px yellow solid\" class=\"" + headerClass + "\"></td><td id=\"");
			html.append(id);
			html.append("_node\" class=\"");
			html.append(styleClass);
			html.append("\" width=\"100%\" ");
			html.append(mousehandler);
			html.append(">");
			html.append(titleHTML);
			html.append("</td></tr></table>");
		}		
		//alert(html.toString());
		return html.toString();
		
	}



}

function MenuBar(id) {

	this.draw = draw;
	this.setProperties = setProperties;
	this.update = update;
	this.mouseOver = mouseOver;
	this.mouseOut = mouseOut;
	this.id = id;
	
	var SHOW_STEPS = false;
	var ANIMATION_DELAY = 1;
	var ANIMATION_STEP_WIDTH = 10;
	var SHOW_ROOT_NODE = false;
	var SHOW_ONE_BRANCH = true;
	var LEVEL = 1;
	
	var items = new Array();

	engine.registerComponent(id, this);
	
	function mouseOver(id) {
		items[id].hover = true;
		items[id].update();
	}
	
	function mouseOut(id) {
		items[id].hover = false;
		items[id].update();
	}
	
	function setProperties(properties) {
		SHOW_STEPS = properties['SHOW_STEPS'] == "true";
		ANIMATION_DELAY = parseInt(properties['ANIMATION_DELAY']);
		ANIMATION_STEP_WIDTH = parseInt(properties['ANIMATION_STEP_WIDTH']);
		SHOW_ROOT_NODE = properties['SHOW_ROOT_NODE'] == "true";
		SHOW_ONE_BRANCH = properties['SHOW_ONE_BRANCH'] == "true";
		LEVEL = parseInt(properties['LEVEL']);		
	}
	
	function update(content) {
		var currentStep = engine.getCurrentStep();
		var structure = database.getStructureById(currentStep.structureId);
		var ancestors = structure.getAncestors();
		
		var itemId = ancestors[ancestors.length - (LEVEL + 2)].id;
		
		if (items.length == 0) {
			var html = this.draw();
			content.divRef.innerHTML = html;
		}
		
		var item = null;
		for (item in items) {
			items[item].selected = (item == itemId); 
			items[item].update();
		}
		
		
		
	}
	
	function draw() {
		var html = "";
		
		var currentStep = engine.getCurrentStep();
		var currentStructure = database.getStructureById(currentStep.structureId);
		var ancestors = currentStructure.getAncestors();
		var rootStructure = ancestors[ancestors.length - (LEVEL + 1)];
		var structures = rootStructure.getStructures();
    	var stepToSelect = null;
    	
    	var stepId = "";
    	//var length = 0;
    	for (var i = 0; i < structures.length; i++) {
    		stepId = "";
    		if (!structures[i].visible) continue;
    		
    		stepToSelect = database.findFirstStepInStructure(structures[i]);
    		if (stepToSelect) stepId = stepToSelect.id;
    		
    		var item = new MenuItem(this, id + "_menuitem" + i, structures[i], stepId);
    		items[structures[i].id] = item;
    		//length++;
    	}
    	
    	//var width = Math.round(100 / length);
    	
    	var html = "<table cellspacing=\"0\" cellpadding=\"0\" class=\"" + id + "\"><tr>";
    	for (var myItem in items) {
    		html += "<td class=\"" + id + "_itemcell\">" + items[myItem].draw() + "</td>";
    	}
    	html += "</tr></table>";
    	
    	//alert(html);
    	return html;
	}

}

function MenuItem(menubar, id, structure, stepId) {
	
	this.draw = draw;
	this.update = update;
	this.stepId = stepId;
	this.selected = false;
	this.hover = false;
	
	var divRef = null;
	
	var mouseOverScript = "component['" + menubar.id + "'].mouseOver('" + structure.id + "');";
	var mouseOutScript = "component['" + menubar.id + "'].mouseOut('" + structure.id + "');";
	var mouseClickScript = "engine.jumpToStep('" + stepId + "')";
		
	function draw() {
		var html = "";
		html += "<div class=\"" + id + "\" id=\"" + id + "\" onclick=\"" + mouseClickScript + "\" onmouseover=\"" + mouseOverScript + "\" onmouseout=\"" + mouseOutScript + "\">" + structure.title + "</div>";
		return html;
	}
	
	function update() {
		var className = id;
		if (!divRef) {
			divRef = document.getElementById(id);
		}
		if (this.selected) {
			className += "Selected";
		}
		if (this.hover) {
			className += "Hover";
		}
		divRef.className = className;
	}
}


