﻿// Fusion Javascript Library 
// (c) Webfuel

if (typeof (Fsn) == 'undefined') Fsn = {};

Fsn.Tree = function(settings, my) {
	my = my || {};
	settings = settings || {};
	var ITree = Fsn.Control(settings, my);

	$.extend(my, {
		dataSource: settings.dataSource || null,
		nodes: Fsn.List(),
		selectedNode: null,
		nodeMap: {}
	});
	my.addGetters("nodes;dataSource;selectedNode");
	my.addEvents("selectedNode");

	$.extend(ITree, {
		collapseAll: function() {

		},

		selectNode: function(node) {
			if (my.selectedNode) {
				my.selectedNode.set('isSelected', false);
				my.selectedNode.refresh();
			}
			if (node) {
				node.set('isSelected', true);
				node.refresh();
			}
			my.selectedNode = node;
			ITree.raiseEvent('selectedNode', { node: node });
		},

		findNodes: function(id) {
			if (!id || id == "" || !my.nodeMap[id]) return [];
			return my.nodeMap[id].slice();
		},

		reloadNodes: function(id) {
			var selectedId;
			if (my.selectedNode) {
				selectedId = my.selectedNode.get('id');
			}
			var nodes = ITree.findNodes(id);
			for (var i = 0; i < nodes.length; i++)
				nodes[i].reload(undefined, function() {
					// Try to reselect the previous selected node
					if (!my.selectedNode && selectedId) {
						var found = ITree.findNodes(selectedId);
						if (found && found.length > 0)
							ITree.selectNode(found[0]);
					}
				});
		},

		removeNodes: function(id) {
			var nodes = ITree.findNodes(id);
			for (var i = 0; i < nodes.length; i++)
				nodes[i].remove();
		},

		registerNode: function(node) {
			var id = node.get('id');
			if (!id || id == "") return;
			if (!my.nodeMap[id]) my.nodeMap[id] = [];
			my.nodeMap[id].push(node);
		},

		unregisterNode: function(node) {
			if (node === my.selectedNode) ITree.selectNode(null);
			var id = node.get('id');
			if (!id || id == "" || !my.nodeMap[id]) return;
			var index = $.inArray(node, my.nodeMap[id]);
			if (index == -1) return;
			my.nodeMap[id].splice(index, 1);
		}
	});

	my.element.addClass("fui-tree");

	var styleLines = function() {
		$("table .fui-treenode-expander > span", my.element).removeClass("ui-icon-treeline-l").addClass("ui-icon-treeline-t");
		$("table:last-child > tbody > tr > .fui-treenode-expander > span", my.element).removeClass("ui-icon-treeline-t").addClass("ui-icon-treeline-l");
		$("table > tbody > tr > .fui-treenode-line", my.element).removeClass("last-child");
		$("table:last-child > tbody > tr > .fui-treenode-line", my.element).addClass("last-child");
	};

	// Bind to TreeNodeCollection event handlers
	my.nodes.addEventHandler('insertedItem', function(sender, event) {
		event.item.set('parentNode', ITree).set('parentTree', ITree);
		event.item.get('element').appendTo(my.element);
		styleLines();
	});
	my.nodes.addEventHandler('removedItem', function(sender, event) {
		event.item.set('parentNode', null).set('parentTree', null);
		event.item.get('element').remove();
		styleLines();
	});

	return ITree;
};

Fsn.TreeNode = function(settings, my) {
	my = my || {};
	settings = settings || {};
	var ITreeNode = Fsn.Control(settings, my);

	$.extend(my, {
		item: settings.item || null,
		context: settings.context || null,
		nodes: Fsn.List(),

		// icon/title are used by the default node body template
		icon: settings.icon || "folder-collapsed",
		iconExpanded: settings.iconExpanded || settings.icon || "folder-open",
		text: settings.text || "(tree node)",

		isExpanded: settings.isExpanded || false,
		isPopulated: settings.isPopulated || false,
		isSelected: false,

		parentNode: null,
		parentTree: null,

		dragEnabled: settings.dragEnabled || false,
		dropEnabled: settings.dropEnabled || false
	});

	my.accessors.get_depth = function() {
		var depth = 0;
		var node = my.parentNode;
		while (node != null) {
			node = node.get('parentNode');
			depth++;
		}
		return depth;
	};

	my.accessors.set_parentNode = function(value) {
		my.parentNode = value;
	};
	my.accessors.set_parentTree = function(value) {
		if (my.parentTree === value) return;
		if (my.parentTree) my.parentTree.unregisterNode(ITreeNode);
		my.parentTree = value;
		if (my.parentTree) my.parentTree.registerNode(ITreeNode);
		for (var i = 0; i < my.nodes.length(); i++) {
			my.nodes.itemAt(i).set('parentTree', value);
		}
	};

	my.addSetters("parentNode;parentTree;isSelected;");
	my.addGetters("depth;nodes;item;context;");

	$.extend(ITreeNode, {

		refresh: function() {
			// Refresh body content
			if (my.isExpanded) {
				$(".ui-icon", my.$content).removeClass().addClass("ui-icon").addClass("ui-icon-" + my.iconExpanded);
			} else {
				$(".ui-icon", my.$content).removeClass().addClass("ui-icon").addClass("ui-icon-" + my.icon);
			}
			$(".text", my.$content).html("&nbsp;" + my.text);

			if (my.isExpanded) {
				if (my.nodes.length() > 0) {
					my.$row2.show()
					$("span", my.$expander).addClass("ui-icon-collapsesmall").removeClass("ui-icon-expandsmall");
				} else {
					my.$row2.hide()
					$("span", my.$expander).removeClass("ui-icon-collapsesmall").removeClass("ui-icon-expandsmall");
				}
			} else if (my.isPopulated) {
				my.$row2.hide();
				if (my.nodes.length() > 0) {
					$("span", my.$expander).addClass("ui-icon-expandsmall").removeClass("ui-icon-collapsesmall");
				} else {
					$("span", my.$expander).removeClass("ui-icon-collapsesmall").removeClass("ui-icon-expandsmall");
				}
			} else {
				my.$row2.hide();
				$("span", my.$expander).addClass("ui-icon-expandsmall").removeClass("ui-icon-collapsesmall");
			}
			my.$body[my.isSelected ? 'addClass' : 'removeClass']("sel");
		},

		reload: function(expand, callback) {
			if (my.parentTree && my.parentTree.get('dataSource')) {
				$PageManager.getDataSource(my.parentTree.get('dataSource')).selectNode(my.id, function(caller, eventArgs) {
					if (my.nodes.length() > 0 || my.isPopulated) my.nodes.clear();
					var nodes = eventArgs.nodes;
					for (var i = 0; i < nodes.length; i++) {
						my.nodes.insert(new Fsn.TreeNode({ id: nodes[i].Id, text: nodes[i].Text, icon: nodes[i].Icon, iconExpanded: nodes[i].IconExpanded, isPopulated: nodes[i].IsPopulated, item: nodes[i].Item, context: nodes[i].Context }), -1);
					}
					my.isPopulated = true;
					if (expand !== undefined) my.isExpanded = expand;
					ITreeNode.refresh();
					if (callback)
						callback();
				});
			} else {
				if (my.nodes.length() > 0 || my.isPopulated) my.nodes.clear();
				my.isPopulated = true;
				if (expand !== undefined) my.isExpanded = expand;
				ITreeNode.refresh();
			}
		},

		expand: function() {
			if (my.nodes.length() == 0 && !my.isPopulated) {
				ITreeNode.reload(true);
			} else if (my.nodes.length() > 0) {
				my.isExpanded = true;
				ITreeNode.refresh();
			}
		},

		collapse: function() {
			my.isExpanded = false;
			ITreeNode.refresh();
		},

		toggle: function() {
			ITreeNode[my.isExpanded ? "collapse" : "expand"]();
		},

		click: function() {
			if (my.parentTree)
				my.parentTree.selectNode(this);
		},

		removeChild: function(node) {
			my.nodes.remove(my.nodes.find(node));
		},

		remove: function() {
			if (my.parentNode)
				my.parentNode.removeChild(ITreeNode);
		}

	});

	// Create the outline html for this node
	my.element = $("<table class='fui-treenode'></table>");

	my.$row1 = $("<tr></tr>").appendTo(my.element);
	my.$row2 = $("<tr></tr>").appendTo(my.element);

	// TODO: Replace this with a default template, that can be overridden
	my.$expander = $("<td class='fui-treenode-expander'><span class='ui-icon'></span></td>").appendTo(my.$row1);
	my.$body = $("<td class='fui-treenode-body' nowrap='nowrap'></td>").appendTo(my.$row1);

	// Put default content into the body
	my.$content = $("<table><tr><td width='18px'><span style='display:block' class='ui-icon'></span></td><td class='text' nowrap='nowrap'></td></tr></table>").appendTo(my.$body);

	my.$line = $("<td class='fui-treenode-line'><span></span></td>").appendTo(my.$row2);
	my.$nodes = $("<td class='fui-treenode-nodes'></td>").appendTo(my.$row2);

	var styleLines = function() {
		$("table .fui-treenode-expander > span", my.element).removeClass("ui-icon-treeline-l").addClass("ui-icon-treeline-t");
		$("table:last-child > tbody > tr > .fui-treenode-expander > span", my.element).removeClass("ui-icon-treeline-t").addClass("ui-icon-treeline-l");
		$("table > tbody > tr > .fui-treenode-line", my.element).removeClass("last-child");
		$("table:last-child > tbody > tr > .fui-treenode-line", my.element).addClass("last-child");
	}

	// Attach event handlers
	my.$expander.click($.delegateEvent(ITreeNode.toggle, ITreeNode));
	my.$body.click($.delegateEvent(ITreeNode.click, ITreeNode));
	my.nodes.addEventHandler('insertedItem', function(sender, event) {
		event.item.set('parentNode', ITreeNode).set('parentTree', my.parentTree);
		event.item.get('element').appendTo(my.$nodes);
		styleLines();
	});
	my.nodes.addEventHandler('removedItem', function(sender, event) {
		event.item.set('parentNode', null).set('parentTree', null);
		event.item.get('element').remove();
		styleLines();
	});

	// refresh the node (also renders initial content)
	ITreeNode.refresh(); // DO WE NEED TO DO THIS HERE?
	return ITreeNode;
};

