// Licensed Materials - Property of IBM
//
// IBM Cognos Products: pps
//
// (C) Copyright IBM Corp. 2005, 2017
//
// US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
//This file defines an JavaScript class that replicates the attributeTree used in PPES

function ppesAdminATreeSortAscendingByIndex(a,b) {
	//Provides a comparison method for sorting an array of children based on the sortIndex 
	if (a.type == "folder" && b.type == "folder" && a.getChild("sortIndex") && b.getChild("sortIndex")) {
		if (parseInt(a.getChild("sortIndex").value) > parseInt(b.getChild("sortIndex").value))
			return 1;
		else 
			return -1;
	} 
	else 
		return 0;
};

function AttributeTreeNodeFolder(name) {
	var children = new Array();
	var childrenNames = new Array();
	
	this.name = name;
	
	this.addChild = function(name, child) {
		var idx = children.length;
		if (childrenNames[name]) {
			idx = childrenNames[name];
		} else {
			childrenNames[name] = idx;
		}
		
		children[idx] = child;
	}
	
	this.getChild = function(name) {
		return children[childrenNames[name]];
	}
	
	this.getChildren = function() {
		return children;
	}
	
	this.toString = function() {
		return "Folder(" + name + ")";
	}
	
	this.sortChildren = function() {		
		children.sort(ppesAdminATreeSortAscendingByIndex);
		for (var i = 0; i < children.length; i++ ) {
			childrenNames[children[i].name] = i;
		}

	}
}
AttributeTreeNodeFolder.prototype.type = "folder";

function AttributeTreeNodeInt(name, value, subType, specialized) {
	this.name = name;
	this.value = value;
	this.subType = subType;
	this.specialized = (specialized == true);
	
	this.toString = function() {
		return "Int(" + name + ") + value:" + value + " subType:" + subType + " specialized:" + specialized;
	}
}
AttributeTreeNodeInt.prototype.type="int";

function AttributeTreeNodeString(name, value, subType, specialized) {
	this.name = name;
	this.value = value;
	this.subType = subType;
	this.specialized = (specialized == true);
	
	this.toString = function() {
		return "Int(" + name + ") + value:" + value + " subType:" + subType + " specialized:" + specialized;
	}
}
AttributeTreeNodeString.prototype.type="string";

function AttributeTree() {

	var root = new AttributeTreeNodeFolder("TreeRoot");
	
	//public methods
	
	this.getRoot = function() {
		return root;
	}
	
	this.getNode = function(path) {
		return findNode(path);
	}
	
	this.getInt = function(path, defaultValue) {
		var node = findNode(path);
		
		if (node && node.type == "int")
			return parseInt(node.value);
		else
			return defaultValue;
	}
	
	this.getString = function(path, defaultValue) {
		var node = findNode(path);
		
		if (node && node.type == "string")
			return node.value;
		else
			return defaultValue;
	}
	
	this.getNode = function(path) {
		return findNode(path);
	}
	
	this.addInt = function(path, value) {
		var name = path.substr(path.lastIndexOf('.') + 1);
		var node = new AttributeTreeNodeInt(name, value, "", false);
		
		this.insertNode(path,node);
	}
	
	this.addString = function(path, value) {
		var name = path.substr(path.lastIndexOf('.') + 1);
		var node = new AttributeTreeNodeString(name, value, "", false);
		
		this.insertNode(path,node);
	}
	
	this.insertNode = function(path, node) {
		var name = path.substr(path.lastIndexOf('.') + 1);
		var path = path.substr(0,path.lastIndexOf('.'));
		
		var parentNode = createPath(path);

		if (parentNode.type == "folder") {
			parentNode.addChild(node.name,node);
		}
	}
	
	this.mergeIntoTree = function(path, node) {
		var name = path.substr(path.lastIndexOf('.') + 1);
		var path = path.substr(0,path.lastIndexOf('.'));
		
		var parentNode = createPath(path);

		if (parentNode.type == "folder") {
			mergeNode(parentNode, node);
		}
	}
	
	this.getSpecializedTreeCopy = function() {
		var attTree = new AttributeTree();
		
		for (var i = 0; i < root.getChildren().length; i++) {
			copySpecializedNodes(root.getChildren()[i],"",attTree);
		}
		
		return attTree;
	}

	//private methods
	
	function copySpecializedNodes(node,curPath,sTree) {
	
		var path = curPath;
		if (path)
			path += "."
		path += node.name;
	
		if (node.type == "folder") {
	
			var includedChild = false;	
			for (var i = 0; i < node.getChildren().length; i++) {
				copySpecializedNodes(node.getChildren()[i],path,sTree);
			}
	
		} else if (node.specialized) {
			
			var nodeCopy;
			if (node.type == "int")
				nodeCopy = new AttributeTreeNodeInt(node.name, node.value, node.subType, node.specialized);
			else if (node.type == "string")
				nodeCopy = new AttributeTreeNodeString(node.name, node.value, node.subType, node.specialized);
			
			sTree.insertNode(path,nodeCopy); 
		}
	}
	
	function mergeNode(parentNode, node) {
	
		if (parentNode.getChild(node.name)) {
			var twin = parentNode.getChild(node.name);
			if (twin.type == "folder" && node.type == "folder") {
				for (var i = 0; i < node.getChildren().length; i++)
					mergeNode(twin, node.getChildren()[i]);
			} else {
				parentNode.addChild(node.name,node);
			}
		} else {
			parentNode.addChild(node.name,node);
		}
	
	}
	
	function findNode(path) {
		
		var currentNode = root;
		
		if (path.length) {
			var nodes = path.split('.');
			for (var i = 0; i < nodes.length; i++) {
				if (currentNode && (currentNode.type == "folder"))
					currentNode = currentNode.getChild(nodes[i]);
				else
					return currentNode;
			}
		}
		
		return currentNode;
	}
	
	function createPath(path) {
	
		var currentNode = root;
		
		if (path.length) {
			var nodes = path.split('.');
			for (var i = 0; i < nodes.length; i++) {
				if (currentNode && (currentNode.type == "folder")) {
					if (!currentNode.getChild(nodes[i]))
						currentNode.addChild(nodes[i],new AttributeTreeNodeFolder(nodes[i]));
					currentNode = currentNode.getChild(nodes[i]);
				} else
					return currentNode;
			}
		}
		
		return currentNode;
	}
	
	//Debug stuff, can be removed later:
	
	function dumpNode(prefix, folderNode) {
		var str = prefix;
		
		if (folderNode.type == "folder") {
			str += "-" + folderNode.name + "\n";
		
			var children = folderNode.getChildren();
			for (var i = 0; i < children.length; i++) {
				str += dumpNode(prefix + "  ", children[i]);
			}
		} else {
			str += "-" + folderNode.name + "(" + folderNode.value + ")\n";
		}
		
		return str;
	}
	
	this.toString = function() {
		//Debug helper, dumps the whole tree to a string
		return dumpNode("", root);
	}
}