<%@ Page Language="C#" EnableViewState="False" %>

<script runat="server">
//===============================================================================================================
// System  : Sandcastle Help File Builder
// File    : FillNode.aspx
// Author  : Eric Woodruff  (Eric@EWoodruff.us)
// Updated : 04/09/2014
// Note    : Copyright 2007-2014, Eric Woodruff, All rights reserved
// Compiler: Microsoft C#
//
// This file contains the code used to dynamically load a parent node with its child table of content nodes when
// first expanded.
//
// This code is published under the Microsoft Public License (Ms-PL).  A copy of the license should be
// distributed with the code.  It can also be found at the project website: https://GitHub.com/EWSoftware/SHFB.  This
// notice, the author's name, and all copyright notices must remain intact in all applications, documentation,
// and source files.
//
//    Date     Who  Comments
// ==============================================================================================================
// 06/21/2007  EFW  Created the code
// 07/17/2013  EFW  Merged code contributed by Procomp Solutions Oy that improves performance for large TOCs by
//								  using XML serialization and caching.
//===============================================================================================================

private static readonly TocNode[] NoChildNodes = new TocNode[0];
private static readonly object TocLoadSyncObject = new object();

// This is used to contain the serialized table of contents
[XmlRoot("HelpTOC")]
public sealed class TableOfContents
{
	[XmlElement("HelpTOCNode")]
	public TocNode[] ChildNodes;

	[XmlIgnore]
	public IDictionary<string, TocNode> NodesById;

	internal void IndexNodes()
	{
		this.NodesById = new Dictionary<string, TocNode>();
		AddToIndex(this.NodesById, this.ChildNodes);
	}

	private static void AddToIndex(IDictionary<string, TocNode> nodesById, TocNode[] nodes)
	{
		foreach(TocNode node in nodes)
			if(!String.IsNullOrEmpty(node.Id))
			{
				nodesById.Add(node.Id, node);
				AddToIndex(nodesById, node.ChildNodes);
			}
	}
}

// This represents a single node in the table of contents
public sealed class TocNode
{
	[XmlAttribute("Id")]
	public string Id;

	[XmlAttribute("Title")]
	public string Title;

	[XmlAttribute("Url")]
	public string Url;

	[XmlElement("HelpTOCNode")]
	public TocNode[] ChildNodes;
}

// Load the TOC info and store it in the cache on first use
private TableOfContents GetToc()
{
	string tocPath = Server.MapPath("WebTOC.xml");
	string tocCacheKey = tocPath;

	lock(TocLoadSyncObject)
	{
		TableOfContents toc = this.Cache[tocCacheKey] as TableOfContents;

		if(toc == null)
		{
			CacheDependency cacheDependency = new CacheDependency(tocPath);

			using(XmlReader reader = XmlReader.Create(tocPath))
			{
				toc = (TableOfContents)new XmlSerializer(typeof(TableOfContents)).Deserialize(reader);
				toc.IndexNodes();
			}

			this.Cache.Insert(tocCacheKey, toc, cacheDependency);
		}

		return toc;
	}
}

// Load the requested node with its children
protected override void Render(HtmlTextWriter writer)
{
	StringBuilder sb = new StringBuilder(10240);
	TableOfContents toc = this.GetToc();

	// The ID to use should be passed in the query string
	string expandedId = this.Request.QueryString["Id"];
	TocNode expandedNode;

	if(toc.NodesById.TryGetValue(expandedId, out expandedNode))
	{
		foreach(TocNode childNode in expandedNode.ChildNodes ?? NoChildNodes)
		{
			if(childNode.ChildNodes != null && childNode.ChildNodes.Length != 0)
			{
				// Write out a parent TOC entry
				string childUrl = childNode.Url;
				string childTarget;

				if(!String.IsNullOrEmpty(childUrl))
					childTarget = " target=\"TopicContent\"";
				else
				{
					childUrl = "#";
					childTarget = String.Empty;
				}

				sb.AppendFormat("<div class=\"TreeNode\">\r\n" +
					"<img class=\"TreeNodeImg\" onclick=\"javascript: Toggle(this);\" src=\"Collapsed.gif\"/>" +
					"<a class=\"UnselectedNode\" onclick=\"javascript: return Expand(this);\" " +
					"href=\"{0}\"{1}>{2}</a>\r\n" +
					"<div id=\"{3}\" class=\"Hidden\"></div>\r\n" +
					"</div>\r\n", HttpUtility.HtmlEncode(childUrl), childTarget, HttpUtility.HtmlEncode(childNode.Title),
					childNode.Id);
			}
			else
			{
				string childUrl = childNode.Url;

				if(String.IsNullOrEmpty(childUrl))
					childUrl = "about:blank";

				// Write out a TOC entry that has no children
				sb.AppendFormat("<div class=\"TreeItem\">\r\n" +
					"<img src=\"Item.gif\"/><a class=\"UnselectedNode\" " +
					"onclick=\"javascript: return SelectNode(this);\" href=\"{0}\" " +
					"target=\"TopicContent\">{1}</a>\r\n" +
					"</div>\r\n", HttpUtility.HtmlEncode(childUrl), HttpUtility.HtmlEncode(childNode.Title));
			}
		}

		writer.Write(sb.ToString());
	}
	else
		writer.Write("<b>TOC node not found!</b>");
}
</script>
