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
);