
/**
 * Tree is a helper class for a universal way of handling tree structures. It 
 * can be used for example with menus, site maps, tree view controls, etc. 
 */
 
mrj.helpers.Tree = mrj.createClass(
{
	init: function ()
	{
		this.indexMap = ["id", "title", { string: "url", object: "nodes" }];
		this.data = null;
		this.parent = null;
	},

	/**
	 * To set the tree structure with an array / object. Useful when dealing
	 * with on the fly changes via AJAX.
	 * 
	 * @param	data	The object for conversion
	 */	 
	setData: function (data)
	{
		this.data = this.objectToTree(data);
	},
	
	/**
	 * Convert an index to a named ID
	 * 
	 * @param	index
	 * @param	obj			 	 	 
	 */	 
	getMapId: function (index, obj)
	{
		var id = this.indexMap[index];
		var type = typeof(id);
		
		if (type == "string" || (type == "object" && id.func != undefined))
		{
			return id;
		}
		else if (type == "object") 
		{
			return id[typeof(obj)];
		}
		
		return null;
	},

	iterate: function (nodes, func, recursive, level)
	{
		if (nodes == null) nodes = this.data;
		if (level == undefined) level = 0;
		if (recursive == undefined || recursive == false) recursive = 0;
		
		for (var i=0; i<nodes.length; i++)
		{
			var n = nodes[i];
			func(this.parent, n, level);
			if (n.nodes != undefined && (level < recursive || recursive == true))
				this.iterate(n.nodes, func, recursive, level + 1);
		}
	},
	
	/**
	 * Generates the tree structure from an object.
	 * NOTE: This function is required for internal use only, use setData()
	 * for this operation.	  
	 * 	 
	 * @param	obj		Object to convert into a tree structure
	 * @see				setData	 
	 * @return			Converted object as a tree structure
	 */
 	objectToTree: function (obj, parent, path, level)
	{
		var branch = new Array();
		if (path == undefined) path = "";
		if (level == undefined) level = 0;
		if (parent == undefined) parent = null;
		
		for (var i in obj)
		{
			var n = obj[i];
			var newNode = new this.Node(parent);
			newNode.level = level;
			
			var useIndexMap = (n.length == undefined ? false : true);
			var childNodes = null;
			
			for (var pid in n)
			{
				var id = (useIndexMap ? this.getMapId(pid, n[pid]) : pid);
				if (id == null) continue;
				
				if (typeof(id) == "object")
				{
					n[pid] = id.func(n[pid]);
					id = id.id; 
				}
				
				if (id == "id")
				{
					newNode.id = (n[pid] == -1 ? i : n[pid]);
				}
				else if (id == "nodes")
				{
					childNodes = n[pid];
				}
				else
				{
					newNode[id] = n[pid];
				}
			}

			newNode.path = path + newNode.id;
			
			if (childNodes != null)
			{
				newNode.nodes = this.objectToTree(childNodes, newNode, newNode.path + "/", level + 1);
			}

			branch[i] = newNode;
		}
		
		return branch;
	},
	
	
	Node: mrj.createClass(
	{
		init: function (parent)
		{
			this.id = null;
			this.title = null;
			this.nodes = null;
			this.parent = parent;
		},
		
		isParent: function ()
		{
			return (this.nodes == null ? false : true);
		},
		
		isRoot: function ()
		{
			return (this.parent == null ? true : false);
		}
	})

});


