6 using System.Collections;
7 using System.Collections.Generic;
15 class Node : IComparable<Node>, IComparable
17 readonly Tree parentTree;
18 string caption, element, pubUrl;
19 public bool Documented;
24 ArrayList legacyNodes;
26 Dictionary<string, Node> childrenLookup;
28 /* Address has three types of value,
29 * _ 0 is for no on-disk representation
30 * _ >0 is a valid address that is loaded immediately
31 * _ <0 is a valid negated address to indicate lazy loading
36 [Obsolete ("Tree inheriting Node is being phased out. Use the `Tree.RootNode' property instead")]
37 public Node (string caption, string element)
39 this.parentTree = (Tree) this;
40 this.caption = caption;
41 this.element = element;
46 public Node (Node parent, string caption, string element) : this (parent.Tree, caption, element)
51 internal Node (Tree tree, string caption, string element)
53 this.parentTree = tree;
54 this.caption = caption;
55 this.element = element;
56 this.elementSort = parentTree.HelpSource != null && parentTree.HelpSource.SortType == SortType.Element;
60 /// Creates a node from an on-disk representation
62 internal Node (Node parent, int address) : this (parent.parentTree, address)
67 internal Node (Tree tree, int address)
69 this.address = address;
70 this.parentTree = tree;
71 this.elementSort = parentTree.HelpSource != null && parentTree.HelpSource.SortType == SortType.Element;
76 /* This is solely used for MatchNode to check for equality */
83 parentTree.InflateNode (this);
85 parent.RegisterFullNode (this);
88 public void AddNode (Node n)
96 public void DeleteNode (Node n)
99 if (!string.IsNullOrEmpty (n.element))
100 childrenLookup.Remove (n.element);
103 // When a child node is inflated, it calls this method
104 // so that we can add it to our lookup for quick search
105 void RegisterFullNode (Node child)
107 if (childrenLookup == null)
108 childrenLookup = new Dictionary<string, Node> ();
109 if (!string.IsNullOrEmpty (child.element))
110 childrenLookup[child.element] = child;
113 [Obsolete ("Use ChildNodes")]
114 public ArrayList Nodes {
116 if (legacyNodes == null)
117 legacyNodes = new ArrayList (ChildNodes as ICollection);
122 public IList<Node> ChildNodes {
125 return nodes != null ? nodes : new List<Node> ();
129 public string Element {
139 public string Caption {
161 internal int Address {
173 /// Creates a new node, in the locator entry point, and with
174 /// a user visible caption of @caption
176 public Node CreateNode (string c_caption, string c_element)
179 if (string.IsNullOrEmpty (c_caption))
180 throw new ArgumentNullException ("c_caption");
181 if (string.IsNullOrEmpty (c_element))
182 throw new ArgumentNullException ("c_element");
184 Node t = new Node (this, c_caption, c_element);
186 childrenLookup[c_element] = t;
191 public Node GetOrCreateNode (string c_caption, string c_element)
194 return CreateNode (c_caption, c_element);
195 if (childrenLookup.Count != nodes.Count || (nodes.Count == 0 && childrenLookup.Count != nodes.Capacity))
199 if (!childrenLookup.TryGetValue (c_element, out result))
200 result = CreateNode (c_caption, c_element);
204 public void EnsureNodes ()
207 nodes = new List<Node> ();
208 childrenLookup = new Dictionary<string, Node> ();
212 public void EnsureLoaded ()
214 if (address < 0 && !loaded) {
222 foreach (var node in nodes)
223 childrenLookup[node.Element] = node;
228 return nodes == null || nodes.Count == 0;
232 void EncodeInt (BinaryWriter writer, int value)
235 int high = (value >> 7) & 0x01ffffff;
236 byte b = (byte)(value & 0x7f);
239 b = (byte)(b | 0x80);
247 int DecodeInt (BinaryReader reader)
254 b = reader.ReadByte();
256 ret = ret | ((b & 0x7f) << shift);
258 } while ((b & 0x80) == 0x80);
263 internal void Deserialize (BinaryReader reader)
265 int count = DecodeInt (reader);
266 element = reader.ReadString ();
267 caption = reader.ReadString ();
272 nodes = new List<Node> (count);
273 for (int i = 0; i < count; i++) {
274 int child_address = DecodeInt (reader);
276 Node t = new Node (this, -child_address);
280 if (parentTree.ForceResort)
284 internal void Serialize (FileStream output, BinaryWriter writer)
287 foreach (Node child in nodes)
288 child.Serialize (output, writer);
290 address = (int) output.Position;
291 EncodeInt (writer, nodes == null ? 0 : (int) nodes.Count);
292 writer.Write (element);
293 writer.Write (caption);
296 foreach (Node child in nodes)
297 EncodeInt (writer, child.address);
306 internal string GetInternalUrl ()
309 if (element.IndexOf (":") != -1 || parent == null)
312 var parentUrl = parent.GetInternalUrl ();
313 return parentUrl.EndsWith ("/") ? parentUrl + element : parentUrl + "/" + element;
316 public string PublicUrl {
320 return pubUrl = parentTree.HelpSource != null ? parentTree.HelpSource.GetPublicUrl (this) : GetInternalUrl ();
324 int IComparable.CompareTo (object obj)
326 Node other = obj as Node;
329 return CompareToInternal (other);
332 int IComparable<Node>.CompareTo (Node obj)
334 return CompareToInternal (obj);
337 int CompareToInternal (Node other)
340 other.EnsureLoaded ();
342 var cap1 = elementSort ? element : caption;
343 var cap2 = elementSort ? other.element : other.caption;
345 /* Some node (notably from ecmaspec) have number prepended to them
346 * which we need to sort better by padding them to the same number
349 if (char.IsDigit (cap1[0]) && char.IsDigit (cap2[0])) {
350 int c1 = cap1.TakeWhile (char.IsDigit).Count ();
351 int c2 = cap2.TakeWhile (char.IsDigit).Count ();
354 cap1 = cap1.PadLeft (cap1.Length + Math.Max (0, c2 - c1), '0');
355 cap2 = cap2.PadLeft (cap2.Length + Math.Max (0, c1 - c2), '0');
359 return string.Compare (cap1, cap2, StringComparison.Ordinal);
363 internal static class IListExtensions
365 // TODO: if the backing store ever change from List<T>, we need to tune these methods to have a fallback mechanism
366 public static int BinarySearch<T> (this IList<T> ilist, T item)
368 var list = ilist as List<T>;
370 throw new NotSupportedException ();
371 return list.BinarySearch (item);
374 public static int BinarySearch<T> (this IList<T> ilist, T item, IComparer<T> comparer)
376 var list = ilist as List<T>;
378 throw new NotSupportedException ();
379 return list.BinarySearch (item, comparer);