/*********************************************************************************
Copyright (C) 2007  Ryan Bowman

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

For any questions or comments contact ryan at fiddlerelf dot com
**********************************************************************************/

treeViewId = 0;
uniqueId = 0;

function WXTreeView()
{
	this.TREESTATETYPE = "treestate";
	this.TREENODEICONTYPE = "treenodeicon";
	this.TREENODESPANTYPE = "treenodespan";
	this.DIRECTORY = "directory";
	this.FILE = "file";
	this.TVPREFIX = "tv";

	this.xmlDoc;
	this.htmlRoot;
	//this.createUniqueIds;
	this.uniqueIdName = "id";
	this.useFileImages = true;
	this.collapsedFolderImage = "folder_closed.png";
	this.expandedFolderImage = "folder_open.png";
	this.leafImage = "unknown.png";
	this.expandedImage = "expanded_icon.png";
	this.collapsedImage = "collapsed_icon.png";
	this.blankImage = "blank.png";
	this.treeViewId = treeViewId++;
	this.overFlow = "auto";
	this.currentNodeId;
	this.openNodeId;
	this.rootNodeIsRegularNode = false;
	this.rootNodeId = null;
	this.lookAndFeel = MODERN;
	this.history;
	
	this.buildTree = TVbuildTree;
	this.treeNodeClicked = TVtreeNodeClicked;
	this.appendNode = TVappendNode;
	this.isRootNode = TVisRootNode;
	//this.createUniqueIds = TVcreateUniqueIds;
	//this.setUniqueId = TVsetUniqueId;
	this.nodeHasChildElements = TVnodeHasChildElements;
	this.setHtmlTreeRoot = TVsetHtmlTreeRoot;
	this.setXmlDocument = TVsetXmlDocument;
	this.createTree = TVcreateTree;
	this.useFileImages = TVuseFileImages;
	this.setCollapsedFolderImage = TVsetCollapsedFolderImage;
	this.setExpandedFolderImage = TVsetExpandedFolderImage;
	this.setLeafImage = TVsetLeafImage;
	this.setLookAndFeel = FCsetLookAndFeel;
	this.getCollapsedImage = TVgetCollapsedImage;
	this.getExpandedImage = TVgetExpandedImage;
	this.getCollapsedFolderImage = TVgetCollapsedFolderImage;
	this.getExpandedFolderImage = TVgetExpandedFolderImage;
	this.getDefaultLeafImage = TVgetDefaultLeafImage;
	this.getBlankImage = TVgetBlankImage;
	this.getNodeValueHtml = TVgetNodeValueHtml;
	this.setOverFlow = TVsetOverFlow;
	this.getTreeViewId = TVgetTreeViewId;
	this.setTreeViewId = TVsetTreeViewId;
	this.createTreeNode = TVcreateTreeNode;
	this.getImageStateFile = TVgetImageStateFile;
	this.getImageIconFile = TVgetImageIconFile;
	this.nodeHasSubdirectories = TVnodeHasSubdirectories;
	this.buildTreeLevel = TVbuildTreeLevel;
	this.treeNodeIsHidden = TVtreeNodeIsHidden;
	this.expandTreeNode = TVexpandTreeNode;
	this.collapseTreeNode = TVcollapseTreeNode;
	this.hideChildNodes = TVhideChildNodes;
	this.getCurrentNodeId = TVgetCurrentNodeId;
	this.setCurrentNodeId = TVsetCurrentNodeId;
	this.getOpenNodeId = TVgetOpenNodeId;
	this.setOpenNodeId = TVsetOpenNodeId;
	this.openTreeNode = TVopenTreeNode;
	this.nodeIsSubNode = TVnodeIsSubNode;
	this.treeNodeClickedExt = TVtreeNodeClickedExt;
	this.openTreeNodeExt = TVopenTreeNodeExt;
	this.getNormalizedNodeId = TVgetNormalizedNodeId;
	this.convertIdToTreeViewId = TVconvertIdToTreeViewId;
	this.buildRootNode = TVbuildRootNode;
	this.getXmlElementById = TVgetXmlElementById;
	this.getHtmlElementById = TVgetHtmlElementById;
	this.getImmediateSubdirectories = TVgetImmediateSubdirectories;
	this.getNodeSpan = TVgetNodeSpan;
	this.setNodeCurrent = TVsetNodeCurrent;
	this.moveUpOneNode = TVmoveUpOneNode;
	this.getImageDirectory = FCgetImageDirectory;
	this.getCurrentNodeClass = TVgetCurrentNodeClass;
	this.addToHistory = TVaddToHistory;
	this.addToHistoryExt = TVaddToHistoryExt;
	this.gotoNode = TVgotoNode;
	this.getNodePath = TVgetNodePath;
}

function TVcreateTree()
{
	if (this.xmlDoc && this.htmlRoot)
	{
		/*
		if (this.createUniqueIds)
		{
			this.createUniqueIds(this.xmlDoc, this.uniqueIdName);
		}
		*/
		
		this.htmlRoot.style.overflow = this.overFlow;
		
		if (this.rootNodeIsRegularNode)
		{
			this.buildTreeLevel(this.htmlRoot, this.xmlDoc.documentElement);
		}
		else
		{
			this.buildRootNode(this.htmlRoot, this.xmlDoc.documentElement);
			var nodeId = this.xmlDoc.documentElement.getAttribute("id");
			this.rootNodeId = nodeId;
			this.addToHistory(nodeId);
			var htmlNode = this.getHtmlElementById(nodeId);
			this.buildTreeLevel(htmlNode, this.xmlDoc.documentElement);
			this.openTreeNode(this.xmlDoc.documentElement);
		}
	}
	
}

/*
function TVsetLookAndFeel(lookAndFeel)
{
	this.lookAndFeel = lookAndFeel;
}
*/

function TVgetCurrentNodeClass()
{
	if (this.lookAndFeel == MODERN)
		return "treenodecurrentmodern";
	else
		return "treenodecurrentoldschool";
}

function TVgetCollapsedFolderImage()
{
	return this.getImageDirectory() + this.collapsedFolderImage;
}

function TVgetExpandedFolderImage()
{
	return this.getImageDirectory() + this.expandedFolderImage;
}

function TVgetCollapsedImage()
{
	return this.getImageDirectory() + this.collapsedImage;
}

function TVgetExpandedImage()
{
	return this.getImageDirectory() + this.expandedImage;
}

function TVgetDefaultLeafImage()
{
	return this.getImageDirectory() + this.leafImage;
}

function TVgetBlankImage()
{
	return this.getImageDirectory() + this.blankImage;
}

/*
function TVgetImageDirectory()
{
	if (this.lookAndFeel == MODERN)
		return MODERNLOOKANDFEELDIRECTORY;
	else
		return OLDSCHOOLLOOKANDFEELDIRECTORY;
}
*/

function TVsetHtmlTreeRoot(htmlNode)
{
	this.htmlRoot = htmlNode;
}

function TVsetXmlDocument(XmlDoc, createUniqueId, uniqueIdName)
{
	this.xmlDoc = XmlDoc;
	this.createUniqueId = (!createUniqueId ? true : createUniqueId);
	this.uniqueIdName = (!uniqueIdName ? "id" : uniqueIdName);
}

function TVsetCollapsedFolderImage(collapsedFolderImage)
{
	this.collapsedFolderImage = collapsedFolderImage;
}

function TVsetExpandedFolderImage(expandedFolderImage)
{
	this.expandedFolderImage = expandedFolderImage;
}

function TVsetLeafImage(leafImage)
{
	this.leafImage = leafImage;
}

function TVuseFileImages(useFileImages)
{
	this.useFileImages = ((useFileImages == null) ? true : useFileImages);
}

function TVgetTreeViewId()
{
	return this.treeViewId;
}

function TVsetTreeViewId(id)
{
	this.treeViewId = id;
}

function TVsetOverFlow(overFlow)
{
	this.overFlow = ((overFlow == null) ? "auto" : overFlow);;
}

function TVgetCurrentNodeId()
{
	return this.currentNodeId;
}

function TVsetCurrentNodeId(nodeId)
{
	this.currentNodeId = nodeId;
}

function TVgetOpenNodeId()
{
	return this.openNodeId;
}

function TVsetOpenNodeId(nodeId)
{
	this.openNodeId = nodeId;
}

function TVgetXmlElementById(nodeId)
{
	//var nodes = this.xmlDoc.selectNodes("//*[@id = '" + nodeId + "']");
	//return nodes[0];
	return this.xmlDoc.selectSingleNode("//*[@id = '" + nodeId + "']");
}

function TVgetHtmlElementById(nodeId)
{
	return document.getElementById(this.convertIdToTreeViewId(nodeId));
}

/*
function TVcreateUniqueIds(XmlEl, idName)
{
	var xmlChildren = xmlEl.childNodes;

	for (var i = 0; i < xmlChildren.length; i++)
	{
		if (xmlChildren[i].nodeType == 1)
		{
			this.setUniqueId(xmlChildren[i], idName);
			if (this.nodeHasChildElements(xmlChildren[i]))	
				this.createUniqueIds(xmlChildren[i], idName);
		}
	}
}

function TVsetUniqueId(XmlEl, idName)
{
	XmlEl.setAttribute(idName, uniqueId++);
}
*/

function TVgetNormalizedNodeId(htmlNode)
{
	var id = htmlNode.getAttribute("id");
	var prefix = this.treeViewId + "_" + this.TVPREFIX;
	return id.substring(prefix.length, id.length);
}

function TVconvertIdToTreeViewId(id)
{
	return this.treeViewId + "_" + this.TVPREFIX + id;
}

function TVbuildRootNode(htmlRoot, xmlDoc)
{
	this.appendNode(htmlRoot, xmlDoc, true);
}

function TVbuildTreeLevel(parenthtmlElement, currentXmlElement)
{
	var xmlChildren = currentXmlElement.childNodes;
	var htmlElement;

	for (var i = 0; i < xmlChildren.length; i++)
	{
		if (xmlChildren[i].nodeName == "directory")
		{
			htmlElement = this.appendNode(parenthtmlElement, xmlChildren[i]);
		}
	}	
}

function TVbuildTree(htmlEl, xmlEl)
{
	var xmlChildren = xmlEl.childNodes;
	var htmlElement;
	
	for (var i = 0; i < xmlChildren.length; i++)
	{
		if (xmlChildren[i].nodeName == "directory")
		{
			htmlElement = this.appendNode(htmlEl, xmlChildren[i]);
			if (this.nodeHasChildElements(xmlChildren[i]))	
				this.buildTree(htmlElement, xmlChildren[i]);
		}		
	}	
}

function TVnodeHasSubdirectories(xmlNode)
{
	var nodeId = xmlNode.getAttribute(this.uniqueIdName);
	//var xmlNode = this.getXmlElementById(nodeId);
	nodeList = xmlNode.getElementsByTagName("directory");
	if (nodeList.length > 0 )
		return true;
	else
		return false;
}


function TVtreeNodeClicked(xmlNode, clickedType)
{
	var nodeId = xmlNode.getAttribute(this.uniqueIdName);
	var clickedHtmlNode = this.getHtmlElementById(nodeId);
	//var clickedXmlNode = this.getXmlElementById(nodeId);

	//clickedXmlNode = nodes[0];
	switch (clickedType)
	{
		case this.TREESTATETYPE:
		{
			if (this.nodeHasSubdirectories(xmlNode))
			{
				//var subNodes = clickedXmlNode.getElementsByTagName("directory");
				var subNodes = this.getImmediateSubdirectories(xmlNode);
				if (subNodes.length > 0)
				{
					var htmlSubNode = this.getHtmlElementById(subNodes[0].getAttribute(this.uniqueIdName));
					if (!htmlSubNode || this.treeNodeIsHidden(this.getNormalizedNodeId(htmlSubNode)))
					{
						this.expandTreeNode(xmlNode);
					}
					else
					{
						this.collapseTreeNode(xmlNode);
					}
				}
			}
		}
		break;
		case this.TREENODEICONTYPE: case this.TREENODESPANTYPE:
		{
			this.openTreeNode(xmlNode);
			if (this.nodeHasSubdirectories(xmlNode))
			{
				this.expandTreeNode(xmlNode);
			}
			this.addToHistory(nodeId);
		}
		break;
		/*
		case this.TREENODESPANTYPE:
		{
			this.openTreeNode(nodeId);
		}
		break;
		*/
		default:
		return;
		break;
	}
	
	this.setCurrentNodeId(nodeId);
	
	this.treeNodeClickedExt(nodeId, clickedType)
}

function TVtreeNodeClickedExt(nodeId, clickedType)
{

}

function TVgetNodeSpan(xmlNode)
{
	var nodeId = xmlNode.getAttribute(this.uniqueIdName);
	var htmlNode = this.getHtmlElementById(nodeId);
	var children = htmlNode.childNodes;
	children = children[0].childNodes;
	for (var i = 0; i < children.length; i++)
	{
		if (children[i].nodeName.toLowerCase() == "span")
			return children[i];
	}
	
	return null;
}

function TVmoveUpOneNode()
{
	if (this.currentNodeId)
	{
		var xmlNode = this.getXmlElementById(this.currentNodeId);
		var nodeId = xmlNode.getAttribute(this.uniqueIdName);
		if (xmlNode.parentNode && !this.isRootNode(nodeId))
		{
			var xmlParent = xmlNode.parentNode
			var nodeId = xmlParent.getAttribute(this.uniqueIdName);
			this.openTreeNode(xmlParent);
			this.setCurrentNodeId(nodeId);
			this.addToHistory(nodeId);
		}
	}		
}

function TVaddToHistory(nodeId)
{
	this.history.push(nodeId);
	this.addToHistoryExt();
}

function TVaddToHistoryExt(nodeId)
{
	//
}


function TVsetNodeCurrent(xmlNode, set)
{
	var spanEl = this.getNodeSpan(xmlNode);

	if (spanEl)
	{
		if (set)
		{
			// set the class
			spanEl.className = this.getCurrentNodeClass();
		}
		else
		{
			// set the class
			spanEl.className = "treenode";
		}
	}
}

function TVgotoNode(nodeId)
{
	this.openTreeNode(this.getXmlElementById(nodeId));
	this.setCurrentNodeId(nodeId);
}

function TVopenTreeNode(xmlNode)
{
	var nodeId = xmlNode.getAttribute(this.uniqueIdName);
	var htmlNode = this.getHtmlElementById(nodeId);
	var imgNodes = htmlNode.getElementsByTagName("img");
	var openNodeId;
	var openXmlNode;
	
	if (htmlNode.style.display == "none")
		this.expandTreeNode(xmlNode.parentNode);
	
	if (imgNodes.length > 1)
	{
		if (!this.isRootNode(nodeId))
			imgNodes[1].setAttribute("src", this.getExpandedFolderImage());
		this.setNodeCurrent(xmlNode, true);
	}
	var openNodeId = this.getOpenNodeId()
	if (openNodeId != null && nodeId != openNodeId)
	{
		htmlCurrentNode = this.getHtmlElementById(openNodeId);
		imgNodes = htmlCurrentNode.getElementsByTagName("img");
		if (imgNodes.length > 1)
		{
			if (!this.isRootNode(openNodeId))
				imgNodes[1].setAttribute("src", this.getCollapsedFolderImage());
			openXmlNode = this.getXmlElementById(openNodeId);
			this.setNodeCurrent(openXmlNode, false);
		}
	}
	this.setOpenNodeId(nodeId);
	//htmlNode.scrollIntoView(false);
	
	this.openTreeNodeExt(xmlNode);
}

function TVgetNodePath(xmlNode)
{
	if (xmlNode != this.xmlDoc.documentElement)
		return this.getNodePath(xmlNode.parentNode) + "/" + xmlNode.getAttribute("name");
	else
		return "//" + xmlNode.getAttribute("name");
}

function TVopenTreeNodeExt(nodeId)
{
	// for extending
}

function TVnodeCanBeExpanded(nodeId)
{

}

function TVnodeIsExpanded(nodeId)
{

}

function TVgetImmediateSubdirectories(xmlNode)
{
	var nodeId = xmlNode.getAttribute(this.uniqueIdName);
	var children;
	var directories = new Array();
	
	children = xmlNode.childNodes;
	for (var i = 0; i < children.length; i++)
	{
		if (children[i].nodeName == this.DIRECTORY)
			directories.push(children[i]);
	} 
	
	return directories;
}

function TVexpandTreeNode(xmlNode)
{
	var nodeId = xmlNode.getAttribute(this.uniqueIdName);
	var htmlNode = this.getHtmlElementById(nodeId);
	var currentXmlNode = xmlNode;
	
	if (htmlNode.style.display == "none")
		this.expandTreeNode(xmlNode.parentNode);
	
	if (this.nodeHasSubdirectories(xmlNode))
	{
		//var subNodes = currentXmlNode.getElementsByTagName("directory");
		var subNodes = this.getImmediateSubdirectories(xmlNode);
		if (subNodes.length > 0)
		{
			var htmlSubNode = this.getHtmlElementById(subNodes[0].getAttribute(this.uniqueIdName));
			if (!htmlSubNode)
			{
				this.buildTreeLevel(htmlNode, currentXmlNode);
			}
			else
			{
				this.hideChildNodes(nodeId, false);
			}
		}
	}
	var imgNodes = htmlNode.getElementsByTagName("img");
	if (imgNodes.length > 0)
	{
		if (!this.isRootNode(nodeId))
			imgNodes[0].setAttribute("src", this.getExpandedImage());
	}
}

function TVhideChildNodes(nodeId, hide)
{
	var htmlNode = this.getHtmlElementById(nodeId);
	var children = htmlNode.childNodes;
	var display;
	
	if (hide)
		display = "none";
	else
		display = "block";
	
	for (var i = 0; i < children.length; i++)
	{	
		if (children[i].nodeName.toLowerCase() == "div")
		{
			children[i].style.display = display;
		}
	}	

}

function TVnodeIsSubNode(childNodeId, parentNodeId)
{
	var nodes = this.xmlDoc.selectNodes("//*[@id = '" + parentNodeId + "']//*[@id = '" + childNodeId + "']");
	if (nodes.length > 0)
		return true;
	else
		return false;
}

function TVcollapseTreeNode(xmlNode)
{
	var nodeId = xmlNode.getAttribute(this.uniqueIdName);
	htmlNode = this.getHtmlElementById(nodeId);
	var openNewNode = false;
	this.hideChildNodes(nodeId, true);
	var imgNodes = htmlNode.getElementsByTagName("img");
	if (imgNodes.length > 0)
	{
		imgNodes[0].setAttribute("src", this.getCollapsedImage());
	}
	var openNodeId = this.getOpenNodeId();
	if (this.nodeIsSubNode(openNodeId,nodeId))
	{
		this.openTreeNode(xmlNode);
		openNewNode = true;
	}
	return openNewNode;
}

function TVtreeNodeIsHidden(nodeId)
{
	htmlNode = this.getHtmlElementById(nodeId);
	display = htmlNode.style.display;
	if ((!display) || display == '' || display == "block")
	{
		return false;
	}
	else
	{
		return true;
	}
}

function TVgetNodeValueHtml(xmlNode)
{
	var nodeId = xmlNode.getAttribute(this.uniqueIdName);
	return xmlNode.getAttribute("name");
}

function TVgetImageStateFile(nodeId, isRoot)
{
	var rootNode = (!isRoot ? false : isRoot);
	if (this.nodeHasSubdirectories(nodeId) && !(rootNode && !this.rootNodeIsRegularNode))
		return this.getCollapsedImage();
	else
		return this.getBlankImage();
}

function TVgetImageIconFile(nodeId, isRoot)
{
	var rootNode = (!isRoot ? false : isRoot);
	if (rootNode && !this.rootNodeIsRegularNode)
		return this.getExpandedFolderImage();
	else
		return this.getCollapsedFolderImage();
}

function TVcreateTreeNode(xmlNode, isRoot)
{
	/*
	REWRITE THIS DAMN THING INTO FUNCTIONS PLEASE.
	*/
	
	var nodeId = xmlNode.getAttribute(this.uniqueIdName);
	var currrentXmlElement = xmlNode;
	var rootNode = (!isRoot ? false : isRoot);
	var clickedType;
	var divEl = document.createElement("div");
	divEl.setAttribute("id", this.convertIdToTreeViewId(nodeId));
	if (!(rootNode && !this.rootNodeIsRegularNode))
		divEl.className = "treenode";
	else
		divEl.className = "roottreenode";
	
	var stopPropFx = clickedStopPropogation;
	var addClickedFxBody;
	var addClickedFx;
	
	var noBREl = document.createElement("nobr");
	
	var imgStateEl = document.createElement("img");
	var imgStateFile = this.getImageStateFile(xmlNode, rootNode);
	imgStateEl.className = "treenodestate";
	imgStateEl.setAttribute("src", imgStateFile);
	if (!(rootNode && !this.rootNodeIsRegularNode))
	{
		clickedType = "treestate";
		addClickedFxBody = "treeNodeClicked(" + nodeId + ", " + this.treeViewId + ", '" + clickedType + "');";
		addClickedFx = new Function(addClickedFxBody);
		normAddEvent(imgStateEl, "click", stopPropFx);
		normAddEvent(imgStateEl, "click", addClickedFx);
	}
	
	var imgIconEl = document.createElement("img");
	var imgIconFile = this.getImageIconFile(xmlNode, rootNode);
	imgIconEl.className = "treenodeicon";
	imgIconEl.setAttribute("src", imgIconFile);
	clickedType = "treenodeicon";
	addClickedFxBody = "treeNodeClicked(" + nodeId + ", " + this.treeViewId + ", '" + clickedType + "');";
	addClickedFx = new Function(addClickedFxBody);
	normAddEvent(imgIconEl, "click", stopPropFx);
	normAddEvent(imgIconEl, "click", addClickedFx);
	
	var spanEl = document.createElement("span");
	spanEl.className = "treenode";
	var innerHtmlValue = this.getNodeValueHtml(xmlNode);
	spanEl.innerHTML = innerHtmlValue;
	clickedType = "treenodespan";
	addClickedFxBody = "treeNodeClicked(" + nodeId + ", " + this.treeViewId + ", '" + clickedType + "');";
	addClickedFx = new Function(addClickedFxBody);
	normAddEvent(spanEl, "click", stopPropFx);
	normAddEvent(spanEl, "click", addClickedFx);	

	noBREl.appendChild(imgStateEl);
	noBREl.appendChild(imgIconEl);
	noBREl.appendChild(spanEl);
	divEl.appendChild(noBREl);
	
	return divEl;
	
}

function TVcreateTreeDiv()
{

}

function TVcreateTreeImgState()
{

}

function TVcreateTreeImgIcon()
{

}

function TVcreateTreeSpan()
{

}

function TVappendNode(parenthtmlElement, currentXmlElement, isRoot)
{	
	var rootNode = (!isRoot ? false : isRoot);
	var nodeId = currentXmlElement.getAttribute(this.uniqueIdName);
	treeNodeEl = this.createTreeNode(currentXmlElement, rootNode);
	treeNodeEl.style.display = "block";
	parenthtmlElement.appendChild(treeNodeEl);
	return treeNodeEl;
}

function TVnodeHasChildElements(node)
{
	var children = node.childNodes;
	for (var i = 0; i < children.length; i++)
	{
		if (children[i].nodeType == 1)
			return true;
	}
	return false;
}

function TVisRootNode (nodeId)
{
	if (nodeId == this.rootNodeId) 
		return true;
	else
		return false;
}

	