/**
 * NODE CLASS
 */
function NtNode(id,
				childrenCount,
				depth,
				html,
				parentNodeId) {
	this.id = id;
	this.parentNodeId = parentNodeId;
	this.childrenCount = childrenCount;
	this.depth = depth;
	this.html = html;
	this.hasFetchedChildren = false;
	
	this.toString = function() {
		return "Node(\nid="+this.id+
							"\n parentNodeId="+this.parentNodeId +
							"\n childrenCount="+this.childrenCount+
							"\n path="+this.path+
							"\n html="+this.html+
							"\n hasFetchedChildren="+this.hasFetchedChildren +
							"\n)\n";
	}
}

/* --------------------------------------------------------------------------------------------- */

/**
 * NODE TREE JAVASCRIPT
 */

// Constants
var NT_PREFIX = "node_";
var NT_HTML = "_html";
var NT_CHILDREN = "_children";
var NT_EXPANDER = "_expander";

// Global variables
var ntRootNodeId = null;
var ntDocRoot = "";
var ntSessionId = "";
var ntExpandedNodeArray = new NxcPersistentArray();

// Resources
var ntExpander = new Object();
ntExpander.expand = new Image();
ntExpander.collapse = new Image();
ntExpander.noexpand = new Image();
ntExpander.tooltip = '';

// Containers
var ntBusyMessageContainerId = "";

// Node collection
var ntNodes = new Object();

/**
 * Gets node from the node collection
 * @param id (int)
 * @return NtNode object
 */
function ntGetNode(id) {
	if(ntNodes[id]) return ntNodes[id];
	return null;
}

/**
 * Gets depth of a node based on its path
 * @param node (NtNode)
 * @return depth (int)
 */
function ntGetDepth(node) {
	if(node == null) return 0;

	// Is this the rootnode or trashnode?
	if(node.id == ntRootNodeId) return 0;

    rootNode = ntGetNode(ntRootNodeId);
    return (node.depth - rootNode.depth);
}

/**
 * Sets up a XMLHttpRequest object
 * @return XMLHttpRequest object
 */
function ntGetHttpRequest() {
	var httpRequest = null;
	if(window.XMLHttpRequest) httpRequest = new XMLHttpRequest();
	else if(window.ActiveXObject) httpRequest = new ActiveXObject("Microsoft.XMLHTTP");		
	return httpRequest;
}

/**
 * Sends a GET request to specified URL
 * @param url (String)
 * @return Response text (string)
 */
function ntSendHttpRequest(url) {
	var httpRequest = ntGetHttpRequest();
	if(httpRequest != null) {
		httpRequest.open("GET", url, false);
		httpRequest.send(null);
		if(httpRequest.responseText) return httpRequest.responseText;
	}
	return null;
}

/**
 * Parses a CSV list to an array of nodes
 * @param csv (String)
 * @param parentNodeId (integer)
 * @return Array of NtNode objects (Array)
 */
function ntParseCsv(csv, parentNodeId) {
	// Parse csv list and create nodes
	var nodeList = new Array();
	
	if(csv == null) return nodeList;

	var lines = csv.split("\n");

	if(lines.length == 1 && lines[0] == null) return false;
	
	for(i=0; i<lines.length; i++) {
		if(lines[i] == null || lines[i].length == 0) break;
		
		var lineArray = unescape( decodeURIComponent( lines[i] ) );
		var line = lineArray.split("|");
		
		if(line.length < 4) break; // invalid line
		
		var node = new NtNode(line[0],
							  parseInt(line[1]),
							  parseInt(line[2]),
							  line[3],
							  parentNodeId)
							
		nodeList[ nodeList.length ] = node;
		ntNodes[ node.id ] = node;
	}
	return nodeList;
}

/**
 * Fetches a single node from the server
 * @param nodeId (int)
 * @param parentNodeId (int)
 * @return NtNode object
 */
function ntFetchNode(nodeId, parentNodeId) {
	var httpRequest = ntGetHttpRequest();
	if(httpRequest == null ) return false;
	
	// Perform request
	var url = ntDocRoot + "/nodetree/getnode_csv?node_id="+nodeId+"&PHPSESSID="+ntSessionId;
	if(parentNodeId == null) url += "&root=1";
	var csv = ntSendHttpRequest(url);
	
	// Parse csv list
	var nodeList = ntParseCsv(csv, parentNodeId);
	
	if(!nodeList) return false;
	return nodeList[0];
}

/**
 * Fetces the children of a node from the server
 * @param parentNodeId
 * @return Array of NtNode objects
 */
function ntFetchChildren(parentNodeId) {
	var httpRequest = ntGetHttpRequest();
	if(httpRequest == null) return false;
	
	// Perform request
	var url = ntDocRoot + "/nodetree/getchildren_csv?parent_node_id="+parentNodeId+"&PHPSESSID="+ntSessionId;
	var csv = ntSendHttpRequest(url);

	// Parse csv list
	var nodeList = ntParseCsv(csv, parentNodeId);
	
	// Update parent node
	parentNode = ntGetNode( parentNodeId );
	if(parentNode) parentNode.hasFetchedChildren = true;

	return nodeList;
}

/**
 * Creates an HTML representation of a node
 * @param node (NtNode)
 * @return HTML text (string)
 */
function ntNodeToHTML(node) {
	var html = "";
	
	if(!node) return html;
	
	// Define variables
	var marginLeft = "";
	var onclick = "";
	var src = "";
	var alt = "";
	var nodeId = "";
	var objectId = "";
	
	// Title container
	html += '<span class="nt_title_container">';
	
	// Expander
	id = 'id="' + NT_PREFIX + node.id + NT_EXPANDER + '"';
	marginLeft = (ntGetDepth( node )) * 22;
	style = 'style="margin-left: '+marginLeft+'px;"';
	onclick = "";
	src = 'src="'+ntExpander.noexpand.src+'"';
	alt = 'alt="'+ntExpander.tooltip+'" title="'+ntExpander.tooltip+'"';
	if(node.childrenCount > 0) {
		onclick = 'onclick="ntToggleNode(\'' + node.id + '\')"';
		src = 'src="'+ntExpander.expand.src+'"';
	}
	html += '<img '+id+' '+style+' '+onclick+' '+src+' class="nt_expander" '+alt+'/>';
	
	// Icon and Title
	html += '<span class="nt_iconandtitle">';
	html += node.html;

	html += '</span>';
	
	// Title container END
	html += '</span>';
	
    return html;
}

/**
 * Creates an HTML representation of a list of nodes
 * @param nodeList Array of NtNode objects
 * @return HTML text (string)
 */
function ntNodeListToHTML(nodeList) {
	var html = '';
	
	for(i=0; i<nodeList.length; i++) {
		if(nodeList[i] == null) break;

		// Main div
		var id = 'id="' + NT_PREFIX + nodeList[i].id + '"';
		var clazz = 'class="nt_node"';
		html += '<div '+id+' '+clazz+'>';
		
		// Get html for node
		html += ntNodeToHTML(nodeList[i]);
		html += '</div>';

		// Children
		id = 'id="' + NT_PREFIX + nodeList[i].id + NT_CHILDREN + '"';
		var style = 'style="display: none;"';
		html += '<div '+id+' '+style+'>Laster...</div>';
	}
	
	return html;
}

/**
 * Fetches node from server and updates HTML representation
 * @param nodeId (int)
 */
function ntRefreshNode(nodeId) {
	if(nodeId != null) {
		var node = ntGetNode(nodeId);
		if(node) {
			var parentNodeId = node.parentNodeId;
			var refreshedNode = ntFetchNode(nodeId, parentNodeId);
			var nodeDiv = document.getElementById( NT_PREFIX + nodeId );
			var childrenDiv = document.getElementById( NT_PREFIX + nodeId + NT_CHILDREN );
			
			if(nodeDiv) nodeDiv.innerHTML = ntNodeToHTML( refreshedNode );
			if(childrenDiv) childrenDiv.innerHTML = ntNodeListToHTML( ntFetchChildren(nodeId) );
			if(refreshedNode.childrenCount > 0) ntExpandNode(nodeId);
		}
	}
}

/**
 * Displays children of a node (if any)
 * @param nodeId (int)
 */
function ntExpandNode(nodeId) {
	var node = ntGetNode(nodeId);

	if(node) {
		var expander = document.getElementById( NT_PREFIX + nodeId + NT_EXPANDER );
		var children = document.getElementById( NT_PREFIX + nodeId + NT_CHILDREN );
		
		if(!node.hasFetchedChildren) {
			var nodeList = ntFetchChildren(nodeId);
			var html = ntNodeListToHTML(nodeList);
			if(children) children.innerHTML = html;
		}
		
		if(children) children.style.display = "block";
		if(expander) expander.src = ntExpander.collapse.src;
		
		var longId = node.parentNodeId == null ? "/"+nodeId : ""+node.parentNodeId+"/"+nodeId;
		ntExpandedNodeArray.nxcAddId(longId);
		ntExpandedNodeArray.nxcWriteCookie();
	}
}

/**
 * Hides children of a node (if any)
 * @paran nodeId (int)
 */
function ntCollapseNode(nodeId) {
	var expander = document.getElementById( NT_PREFIX + nodeId + NT_EXPANDER );
	var children = document.getElementById( NT_PREFIX + nodeId + NT_CHILDREN );
	
	if(children) children.style.display = "none";
	if(expander) expander.src = ntExpander.expand.src;
	
	var node = ntGetNode(nodeId);
	if(node) {
		var longId = node.parentNodeId == null ? "/"+nodeId : ""+node.parentNodeId+"/"+nodeId;
		ntExpandedNodeArray.nxcRemoveId(longId);
		ntExpandedNodeArray.nxcWriteCookie();
	}
}

/**
 * Shows or hides children of a node
 * @param nodeId (int)
 */
function ntToggleNode(nodeId) {
	var node = ntGetNode(nodeId);
	if(node && node.childrenCount > 0) {
		var children = document.getElementById( NT_PREFIX + nodeId + NT_CHILDREN );
		
		if(children && children.style.display != "block") ntExpandNode(nodeId);
		else ntCollapseNode(nodeId);
	}
}

function ntDisplayBusyMessage(message) {
	var msgDiv = document.getElementById(ntBusyMessageContainerId);
	if(msgDiv) {
		if(message) msgDiv.innerHTML = message;
		msgDiv.style.display = "block";
	}
}

function ntHideBusyMessage() {
	var msgDiv = document.getElementById(ntBusyMessageContainerId);
	if(msgDiv) {
		msgDiv.style.display = "none";
	}
}


/**
 * Initialises and displays node tree
 * @param targetDivId (String) The HTML tag where the node tree should be output
 */
function ntInitTree(targetDivId) {
	var rootNode = ntFetchNode( ntRootNodeId, null );
	var div = document.getElementById( targetDivId )
	var nodeList = ntFetchChildren( ntRootNodeId );
	
	//if(rootNode) nodeList.push(rootNode);
	
	if(div) div.innerHTML = ntNodeListToHTML( nodeList );
	
	// Expand nodetree
	ntExpandedNodeArray.cookieName = "nxcnodetree";
	ntExpandedNodeArray.nxcReadCookie();
	var ar = ntExpandedNodeArray.nxcGetArray();
	for(var i=0; i<ar.length; i++) {
	    var val = ar[i];
	    var tmp = val.split('/');
	    var parentId = tmp[0];
	    var id = tmp[1];
	    var node = ntGetNode( id );
	    if( !node ) node = ntFetchNode(id, parentId);
	    if( node ) ntExpandNode(id);
	}
	//ntExpandNode(ntRootNodeId);
	
	ntHideBusyMessage();
}
