﻿window.WebTree = window.WebTree || function(aspTree, tree, settings)
{
	var hasChildsLevel = tree.Element.parentNode.getAttribute("DataSourceLevel1") != null;

	this.OnNodeChecked = function(node, isChecked, isChechboxClicked)
	{
		if (tree.DisableEvents)
			return;

		var nodeLevel = node.getLevel();

		if (nodeLevel == 0)	// if node's level is 0, then check/uncheck all its children
		{
			if (isChechboxClicked)
			{
				if (hasChildsLevel)
				{
					//Disable the checkbox clicked
					node.setEnabled && node.setEnabled(false);

					//Get the original text and change the node to Loading...
					var tmpLoading = node.getText();
					node.setText(tree.LoadOnDemandPrompt, false);
				}
			}

			setTimeout(function()
			{
				if (!hasChildsLevel)
				{
					//Change the class if not have childs. No need to be bold
					node.setClass(isChecked ? settings.Css.NodeCheckedCss : settings.Css.NodeCss);

					// call a custom user event after the childs are loaded
					settings.onNodeChecked && settings.onNodeChecked(node, tree, hasChildsLevel);
				}
				else
				{
					//Show downloading
					var subnodes;
					subnodes = igtree_getElementById("M_" + node.element.id);
					subnodes.style.display = "";

					if (isChechboxClicked)
					{
						var isPopulated = node.getPopulated();

						//Load all childs and check them
						WebTree.EnsureChildNodesLoaded(tree, node, function(node)
						{
							if (isPopulated)
							{
								$(node.getChildNodes()).each(function(index, node)
								{
									node.hasCheckbox() && node.setChecked(isChecked, null, false);
								});
							}

							//Enable the node
							node.setEnabled && node.setEnabled(true);

							//Returns the original text to the node
							node.setText(tmpLoading, false);

							//Change the font of the node
							node.setClass(isChecked ? settings.Css.NodeParentCheckedCss : settings.Css.NodeCss);

							// call a custom user event after the childs are loaded
							settings.onNodeChecked && settings.onNodeChecked(node, tree, hasChildsLevel);
						});
					}
				}
			}, 100);
		}
		else if (nodeLevel == 1) // update parent node's state
		{
			//Change the class
			node.setClass(isChecked ? settings.Css.NodeCheckedCss : settings.Css.NodeCss);

			if (isChechboxClicked)
			{
				var isCheckedChildren = isChecked ? true : this.GetCheckedChildNodes(node.getParent()).length > 0;

				node.getParent().setClass(isCheckedChildren ? settings.Css.NodeParentCheckedCss : settings.Css.NodeCss);

				if (!isChecked && node.getParent().getChecked())
				{
					node.getParent().setChecked(false);
					var tagId = node.getTag();
					$(node.getParent().getChildNodes()).each(function(index, node)
					{
						if (tagId != node.getTag())
						{
							igtree_updateNodeCheck(node, null, true);
						}
					});
				}

				// call a custom user event
				settings.onNodeChecked && settings.onNodeChecked(node, tree, hasChildsLevel);
			}
		}
	}

	this.OnNodeClick = function(node, isChecked)
	{
		if (node.getLevel() == 1)
		{
			// call a custom user event
			settings.onNodeClick && settings.onNodeClick(tree, node);
		}
	}

	this.OnNodeExpand = function(node)
	{
		//Not implemented
		return;
	}

	// Methods

	// the dropdownlist owns this tree, if any
	this.DropDownList = function()
	{
		return aspTree[0].DropDownList;
	}

	this.FindNode = function(levelIds, onNodeFound)
	{
		WebTree.FindNode(tree, levelIds, onNodeFound)
	}

	this.GetCheckedChildNodes = function(node)
	{
		node = node || tree;

		var foundNodes = [];
		var nodes = node.getNodes ? node.getNodes() : node.getChildNodes();

		for (var n = 0, length = nodes.length; n < length; n++)
		{
			var childNode = nodes[n];

			try
			{
				if (childNode.hasCheckbox())
				{
					if (childNode.getChecked())
					{
						// if the node's level is 0 and it's checked, test its child node.
						if (childNode.getLevel() == 0)
							foundNodes = foundNodes.concat(this.GetCheckedChildNodes(childNode));
						else
							foundNodes.push(childNode);
					}
				}
				else
				{
					foundNodes = foundNodes.concat(this.GetCheckedChildNodes(childNode));
				}
			}
			catch (ex) { } // so don't let it crush the whole script
		}

		return foundNodes;
	}

	this.GetAllCheckedNodes = function(node, hasChildsLevel)
	{
		node = node || tree;

		var countNodes = 0;
		var foundNodes = [];
		var nodes = node.getNodes ? node.getNodes() : node.getChildNodes();

		for (var n = 0, length = nodes.length; n < length; n++)
		{
			var childNode = nodes[n];

			try
			{
				if (childNode.hasCheckbox())
				{
					if (childNode.getLevel() == 0)
					{
						if (childNode.getChecked())
						{
							foundNodes.push(childNode);

							if (!hasChildsLevel)
								countNodes += 1;
							else
								countNodes += childNode.getChildNodes().length;
						}
						else if (childNode.getPopulated())
						{
							var tmpAllNodes = this.GetAllCheckedNodes(childNode);
							foundNodes = foundNodes.concat(tmpAllNodes[0]);
							countNodes += tmpAllNodes[1];
						}
					}
					else if (childNode.getChecked())
					{
						foundNodes.push(childNode);
						countNodes += 1;
					}
				}
				else
				{
					foundNodes = foundNodes.concat(this.GetAllCheckedNodes(childNode)[0]);
					countNodes += 1;
				}
			}
			catch (ex) { } // so don't let it crush the whole script
		}

		//It'll return [OBJECT, COUNT]
		return [foundNodes, countNodes];
	}

	this.LoadTreeFromServer = function(onReady)
	{
		WebTree.EnsureChildNodesLoaded(tree, tree, onReady);
	}

	this.ClearAll = function(node)
	{
		var nodes = (node = node || tree).getNodes ? node.getNodes() : node.getChildNodes();

		for (var n = 0, length = nodes.length; n < length; n++)
		{
			var node = nodes[n];

			if (node.hasCheckbox() && node.getChecked())
			{
				node.setChecked(false, null, false, true);
			}
			else
			{
				this.ClearAll(node);
			}
		}
	}

	this.RemoveSelected = function(nodeId)
	{
		var node = igtree_getNodeById(nodeId);

		var nodeLevel = node.getLevel();

		if (nodeLevel == 0)
		{
			node.setChecked(false, null, false, true);
		}
		else
		{
			node.setChecked(false, null, false, true);
		}
	}

	this.OnLoadManipulateJSON = function(node, data)
	{
		return (settings.OnLoadManipulateJSON && settings.OnLoadManipulateJSON(tree, node, data));
	}
}

WebTree.OnInitializeTree = function(treeId)
{
	var tree = igtree_getTreeById(treeId);
	var aspTree = $(tree.Element.parentNode);

	tree.EventData = null;
	tree.Element.style.outline = "none"; // hide focus rectange for this tree (FF)
	tree.Element.hideFocus = true; 		// hide focus rectange for this tree (IE)

	tree.WebTree = aspTree[0].WebTree = new WebTree(aspTree, tree,
	{
		url: aspTree.attr("DataSourceUrl"),
		eventsData: $("#" + aspTree.attr("DataId")),
		onNodeChecked: window[aspTree.attr("OnNodeChecked")],
		onNodeClick: window[aspTree.attr("OnNodeClick")],
		OnLoadManipulateJSON: window[aspTree.attr("OnLoadManipulateJSON")],
		Css:
		{
			NodeCss: aspTree.attr("CssNode"),
			NodeHoveredCss: aspTree.attr("CssNodeHovered"),
			NodeCheckedCss: aspTree.attr("CssNodeChecked"),
			NodeParentCheckedCss: aspTree.attr("CssNodeParentChecked")
		}
	});
}

WebTree.OnNodeExpand = function(treeId, nodeId)
{
	var tree = igtree_getTreeById(treeId);
	var node = igtree_getNodeById(nodeId);

	if (tree.DisableEvents == true) return true;

	if (node.getPopulated() == false)
	{
		WebTree.LoadNodeFromServer(tree, node, false, function()
		{
			WebTree.OnEvent("onexpand", tree, node, true, { status: "expanded" });
		});
	}
	else
	{
		WebTree.OnEvent("onexpand", tree, node, true, { status: "expanded" });
	}

	tree.WebTree.OnNodeExpand(node);
}

WebTree.OnNodeChecked = function(treeId, nodeId, isChecked, isChechboxClicked)
{
	var tree = igtree_getTreeById(treeId);
	var node = igtree_getNodeById(nodeId);

	WebTree.OnEvent("onchecked", tree, node, true, { status: isChecked ? "checked" : "unchecked" });

	tree.WebTree.OnNodeChecked(node, isChecked, isChechboxClicked);
}

WebTree.OnNodeClick = function(treeId, nodeId, isChecked)
{
	var tree = igtree_getTreeById(treeId);
	var node = igtree_getNodeById(nodeId);

	tree.WebTree.OnNodeClick(node, isChecked);
}

WebTree.LoadNodeFromServer = function(tree, node, isRoot, onNodeLoaded)
{
	$.getJSON(WebTree.GetDataSourceUrl(tree, !isRoot && node), function(data, textStatus)
	{
		var dataManipulated = tree.WebTree.OnLoadManipulateJSON(!isRoot && node, data);

		if (dataManipulated)
			data = dataManipulated;

		WebTree.PopulateNode(tree, node, data, isRoot);

		onNodeLoaded(node);
	});
}

WebTree.GetDataSourceUrl = function(tree, node)
{
	var nodeId = (node ? node.getTag() : -1).toString();

	if (isFinite(nodeId))
	{
		var level = (!node ? 0 : node.getLevel() + 1);
		var datasourcepath = tree.Element.parentNode.getAttribute("DataSourcePath");
		var datasourcelevel = tree.Element.parentNode.getAttribute("DataSourceLevel" + level.toString());
		var langid = tree.Element.parentNode.getAttribute("LangId");

		return datasourcepath + '/JSON_' + datasourcelevel + (level == 1 ? '_' + nodeId : '') + '_' + langid + '.js';
	}
	else
	{
		return 'c.asp?action=' + nodeId + ajaxComplementURL
	}
}

WebTree.PopulateNode = function(tree, parentNode, data, isRoot)
{
	// There is bug, which make the parent node of just added nodes to be expanded.
	// So after this method the parentNode will be expanded, if there are tricks to prevent this.

	var disableCheckboxesForRootNodes = tree.Element.parentNode.getAttribute("DisableCheckboxesForRootNodes") == "true";
	var hasChildsLevel = tree.Element.parentNode.getAttribute("DataSourceLevel1") != null;
	var clientState = eval("igtree_" + tree.Id + "_cs");

	parentNode.removeChild && parentNode.removeChild(0);

	if (isRoot == true)
	{
		for (var key in data)
		{
			var cssNodeparentChecked = tree.Element.parentNode.getAttribute("cssNodeparentChecked");

			var node = parentNode.addRoot(data[key].text, !isFinite(data[key].id.toString()) && cssNodeparentChecked ? "TreeNodeParentChecked" : null, hasChildsLevel);

			node.setTag(data[key].id.toString());

			if (hasChildsLevel)
				node.addChild(tree.LoadOnDemandPrompt);

			node.setPopulated(false);
			
			node.setExpanded(!isFinite(data[key].id.toString()) || (clientState[2] && typeof (clientState[2][data[key].id]) != 'undefined') ? true : false);

			if (node.hasCheckbox() && clientState[0] && typeof (clientState[0][data[key].id]) != 'undefined')
			{
				node.setChecked(true, null, true, true);
			}
		}
	}
	else
	{
		for (var key in data)
		{
			var node = parentNode.addChild(data[key].text);
			node.setTag(data[key].id.toString());

			if (clientState[1] && typeof (clientState[1][data[key].id]) != 'undefined')
			{
				if (node.hasCheckbox())
				{
					node.setChecked(true, null, true, true);
				}
				else
				{
					var src = $('#' + node.Id + ' .TreeNode')[0];

					var className = igtree_getResolvedHoverClass(node.WebTree, src);

					src.HovClass = src.className;
					if (tree.MergeStyles)
						src.className += " " + className;

					node.setSelected(true);
				}
			}
			else if (node.getParent && node.hasCheckbox && node.hasCheckbox() && node.getParent().getChecked && node.getParent().getChecked())
			{
				node.setChecked(true, null, false);
			}
		}
	}
}

WebTree.FindNode = function(tree, levelIds, onNodeFound)
{
	function FindNodeInLevel(id, nodes)
	{
		var foundNode = null;

		$(nodes).each(function(index, node)
		{
			if (+node.getTag() == id) { foundNode = node; return false; }
		});

		return foundNode;
	}

	WebTree.EnsureChildNodesLoaded(tree, tree, function()
	{
		var node = FindNodeInLevel(levelIds[0], tree.getNodes());

		WebTree.EnsureChildNodesLoaded(tree, node, function(node)
		{
			onNodeFound(FindNodeInLevel(levelIds[1], node.getChildNodes()));
		});
	});
}

WebTree.EnsureChildNodesLoaded = function(tree, node, onReady)
{
	var isRoot = node.getNodes != null;

	if (isRoot)
	{
		if ($('#' + tree.UniqueId + '[IsCreateNodes = 1]').length == 1)
		{
			node.clearNodes();

			$('#' + tree.UniqueId).attr('IsCreateNodes', '0');
		}
	}

	if (!isRoot && !node.getPopulated() || isRoot && node.getNodes() == 0)
	{
		WebTree.LoadNodeFromServer(tree, node, isRoot, function(node)
		{
			onReady && onReady(node);
		});
	}
	else
	{
		onReady && onReady(node);
	}
}

WebTree.OnEvent = function(eventType, tree, node, isInverse, customData)
{
	var treeEventData = tree.EventData = tree.EventData || {};
	var nodeEventData = treeEventData[node.Id] = treeEventData[node.Id] || {};

	if (isInverse == true)
	{
		nodeEventData[eventType] ? delete nodeEventData[eventType] : nodeEventData[eventType] = { id: +node.getTag(), text: node.getText(), level: node.getLevel() };
	}
	else
	{
		// not implemented
	}

	// adding custom data to the default event infromation
	if (nodeEventData[eventType] != null)
	{
		for (var key in customData)
		{
			nodeEventData[eventType][key] = customData[key];
		}
	}
}