[monodoc] Add missing source-id parameter feeding when XSLT-ing namespaces
[mono.git] / mcs / tools / monodoc / Monodoc / ecma-provider.cs
1 //
2 // The provider for a tree of ECMA documents
3 //
4 // Authors:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Joshua Tauberer (tauberer@for.net)
7 //
8 // (C) 2002, 2003 Ximian, Inc.
9 // (C) 2003 Joshua Tauberer.
10 // Copyright 2003-2011 Novell
11 // Copyright 2011 Xamarin Inc
12 //
13 // TODO:
14 //   Should cluster together constructors
15 //
16 // Easy:
17 //   Should render attributes on the signature.
18 //   Include examples as well.
19 //
20 namespace Monodoc {
21 using System;
22 using System.Diagnostics;
23 using System.Reflection;
24 using System.IO;
25 using System.Xml;
26 using System.Xml.XPath;
27 using System.Xml.Xsl;
28 using System.Text;
29 using System.Collections;
30 using Mono.Lucene.Net.Index;
31 using Mono.Lucene.Net.Documents;
32
33 using Mono.Documentation;
34
35 using BF = System.Reflection.BindingFlags;
36
37 //
38 // Helper routines to extract information from an Ecma XML document
39 //
40 public static class EcmaDoc {
41         public static string GetFullClassName (XmlDocument doc)
42         {
43                 return doc.SelectSingleNode ("/Type").Attributes ["FullName"].InnerText;
44         }
45         
46         public static string GetClassName (XmlDocument doc)
47         {
48                 return GetDisplayName (doc.SelectSingleNode ("/Type")).Replace ("+", ".");
49         }
50
51         public static string GetDisplayName (XmlNode type)
52         {
53                 if (type.Attributes ["DisplayName"] != null) {
54                         return type.Attributes ["DisplayName"].Value;
55                 }
56                 return type.Attributes ["Name"].Value;
57         }
58
59         public static string GetClassAssembly (XmlDocument doc)
60         {
61                 return doc.SelectSingleNode ("/Type/AssemblyInfo/AssemblyName").InnerText;
62         }
63
64         public static string GetClassNamespace (XmlDocument doc)
65         {
66                 string s = doc.SelectSingleNode ("/Type").Attributes ["FullName"].InnerText;
67
68                 return s.Substring (0, s.LastIndexOf ("."));
69         }
70         
71         public static string GetTypeKind (XmlDocument doc)
72         {
73                 XmlNode node = doc.SelectSingleNode ("/Type/Base/BaseTypeName");
74
75                 if (node == null){
76                         if (GetFullClassName (doc) == "System.Object")
77                                 return "Class";
78                         return "Interface";
79                 }
80
81                 switch (node.InnerText){
82
83                 case "System.Delegate":
84                 case "System.MulticastDelegate":
85                         return "Delegate";
86                 case "System.ValueType":
87                         return "Structure";
88                 case "System.Enum":
89                         return "Enumeration";
90                 default:
91                         return "Class";
92                 }
93         }
94
95         //
96         // Utility function: converts a fully .NET qualified type name into a C#-looking one
97         //
98         public static string ConvertCTSName (string type)
99         {
100                 if (!type.StartsWith ("System."))
101                         return type;
102
103                 if (type.EndsWith ("*"))
104                         return ConvertCTSName(type.Substring(0, type.Length - 1)) + "*";
105                 if (type.EndsWith ("&"))
106                         return ConvertCTSName(type.Substring(0, type.Length - 1)) + "&";
107                 if (type.EndsWith ("[]"))
108                         return ConvertCTSName(type.Substring(0, type.Length - 2)) + "[]";
109
110                 switch (type) {
111                 case "System.Byte": return "byte";
112                 case "System.SByte": return "sbyte";
113                 case "System.Int16": return "short";
114                 case "System.Int32": return "int";
115                 case "System.Int64": return "long";
116                         
117                 case "System.UInt16": return "ushort";
118                 case "System.UInt32": return "uint";
119                 case "System.UInt64": return "ulong";
120                         
121                 case "System.Single":  return "float";
122                 case "System.Double":  return "double";
123                 case "System.Decimal": return "decimal";
124                 case "System.Boolean": return "bool";
125                 case "System.Char":    return "char";
126                 case "System.String":  return "string";
127                         
128                 case "System.Object":  return "object";
129                 case "System.Void":  return "void";
130                 }
131
132                 if (type.LastIndexOf(".") == 6)
133                         return type.Substring(7);
134                 
135                 return type;
136         }
137
138         internal static string GetNamespaceFile (string dir, string ns)
139         {
140                 string nsxml = Path.Combine (dir, "ns-" + ns + ".xml");
141                 if (!File.Exists (nsxml))
142                         nsxml = Path.Combine (dir, ns + ".xml");
143                 return nsxml;
144         }
145
146         internal static string GetImageFile (string dir, string img)
147         {
148                 string path = Path.Combine (dir, Path.Combine ("_images", img));
149                 return File.Exists (path) ? path : null;
150         }
151
152         public static string GetCref (XmlElement member)
153         {
154                 string typeName = XmlDocUtils.ToEscapedTypeName (member.SelectSingleNode("/Type/@FullName").InnerText);
155                 if (member.Name == "Type")
156                         return "T:" + typeName;
157                 string memberType = member.SelectSingleNode("MemberType").InnerText;
158                 switch (memberType) {
159                         case "Constructor":
160                                 return "C:" + typeName + MakeArgs(member);
161                         case "Event":
162                                 return "E:" + typeName + "." + XmlDocUtils.ToEscapedMemberName (member.GetAttribute("MemberName"));
163                         case "Field":
164                                 return "F:" + typeName + "." + XmlDocUtils.ToEscapedMemberName (member.GetAttribute("MemberName"));
165                         case "Method": {
166                                 string name = "M:" + typeName + "." + XmlDocUtils.ToEscapedMemberName (member.GetAttribute("MemberName")) + MakeArgs(member);
167                                 if (member.GetAttribute("MemberName") == "op_Implicit" || member.GetAttribute("MemberName") == "op_Explicit")
168                                         name += "~" + XmlDocUtils.ToTypeName (member.SelectSingleNode("ReturnValue/ReturnType").InnerText, member);
169                                 return name;
170                         }
171                         case "Property":
172                                 return "P:" + typeName + "." + XmlDocUtils.ToEscapedMemberName (member.GetAttribute("MemberName")) + MakeArgs(member);
173                         default:
174                                 throw new NotSupportedException ("MemberType '" + memberType + "' is not supported.");
175                 }
176         }
177         
178         private static string MakeArgs (XmlElement member)
179         {
180                 XmlNodeList parameters = member.SelectNodes ("Parameters/Parameter");
181                 if (parameters.Count == 0)
182                         return "";
183                 StringBuilder args = new StringBuilder ();
184                 args.Append ("(");
185                 args.Append (XmlDocUtils.ToTypeName (parameters [0].Attributes ["Type"].Value, member));
186                 for (int i = 1; i < parameters.Count; ++i) {
187                         args.Append (",");
188                         args.Append (XmlDocUtils.ToTypeName (parameters [i].Attributes ["Type"].Value, member));
189                 }
190                 args.Append (")");
191                 return args.ToString ();
192         }
193 }
194
195 //
196 // The Ecma documentation provider:
197 //
198 // It populates a tree with contents during the help assembly
199 //
200 public class EcmaProvider : Provider {
201         ArrayList/*<string>*/ asm_dirs = new ArrayList ();
202
203         public EcmaProvider ()
204         {
205         }
206
207         public EcmaProvider (string base_directory)
208         {
209                 AddDirectory (base_directory);
210         }
211
212         public void AddDirectory (string directory)
213         {
214                 if (!Directory.Exists (directory))
215                         throw new FileNotFoundException (String.Format ("The directory `{0}' does not exist", directory));
216                 asm_dirs.Add (directory);
217         }
218         
219         public override void PopulateTree (Tree tree)
220         {
221                 ArrayList ns_dirs = new ArrayList ();
222                 foreach (string asm in asm_dirs) {
223                         ns_dirs.AddRange (Directory.GetDirectories (asm));
224                 }
225
226                 foreach (string ns in ns_dirs){
227                         string basedir = Directory.GetParent (ns).FullName;
228                         string [] files = Directory.GetFiles (ns);
229                         Node ns_node = null;
230                         string tn = null;
231                         
232                         Hashtable nsnodes = new Hashtable();
233
234                         foreach (string file in files){
235                                 if (!file.EndsWith (".xml"))
236                                         continue;
237
238                                 if (ns_node == null) {
239                                         tn = Path.GetFileName (ns);
240                                         tree.HelpSource.Message (TraceLevel.Info, "Processing namespace {0}", tn);
241                                         ns_node = tree.LookupNode (tn, "N:" + tn);
242                                         string ns_summary_file = EcmaDoc.GetNamespaceFile (basedir, tn);
243                                         
244                                         nsnodes[ns_node] = nsnodes;
245                                         
246                                         if (File.Exists (ns_summary_file)) {
247                                                 XmlDocument nsSummaryFile = new XmlDocument ();
248                                                 nsSummaryFile.Load (ns_summary_file);
249                                                 namespace_realpath [tn] = ns_summary_file;
250                                                 
251                                                 XmlNode ns_summary = nsSummaryFile.SelectSingleNode ("Namespace/Docs/summary");
252                                                 if (ns_summary != null && ns_summary.InnerText.Trim () != "To be added." && ns_summary.InnerText != "") {
253                                                         namespace_summaries [tn]  = detached.ImportNode (ns_summary, true);
254                                                         namespace_remarks [tn]    = detached.ImportNode (nsSummaryFile.SelectSingleNode ("Namespace/Docs/remarks"), true);
255                                                 }
256                                                 
257                                         } else if (!namespace_summaries.ContainsKey (tn)) {
258                                                 namespace_summaries [tn] = null;
259                                                 namespace_remarks [tn] = null;
260                                         }
261                                 }
262                                 tree.HelpSource.Message (TraceLevel.Verbose, "    Processing input file {0}", Path.GetFileName (file));
263
264                                 PopulateClass (tree, tn, ns_node, file);
265                         }
266                         
267                         // Sort the list of types in each namespace
268                         foreach (Node ns_node2 in nsnodes.Keys)
269                                 ns_node2.Sort();
270                 }
271
272         }
273                 
274         class TypeInfo : IComparable {
275                 public string type_assembly;
276                 public string type_name;
277                 public string type_full;
278                 public string type_kind;
279                 public XmlNode type_doc;
280
281                 public TypeInfo (string k, string a, string f, string s, XmlNode n)
282                 {
283                         type_assembly = a;
284                         type_name = s;
285                         type_doc = n;
286                         type_kind = k;
287                         type_full = f;
288                 }
289
290                 public int CompareTo (object b)
291                 {
292                         TypeInfo na = this;
293                         TypeInfo nb = (TypeInfo) b;
294
295                         return String.Compare (na.type_full, nb.type_full);
296                 }
297         }
298         
299         //
300         // Packs a file with the summary data
301         //
302         public override void CloseTree (HelpSource hs, Tree tree)
303         {
304                 foreach (DictionaryEntry de in class_summaries){
305                         XmlDocument doc = new XmlDocument ();
306                         string ns = (string) de.Key;
307                         
308                         ArrayList list = (ArrayList) de.Value;
309                         list.Sort();
310
311                         XmlElement elements = doc.CreateElement ("elements");
312                         doc.AppendChild (elements);
313                         
314                         if (namespace_summaries [ns] != null)
315                                 elements.AppendChild (doc.ImportNode ((XmlNode)namespace_summaries [ns],true));
316                         else
317                                 elements.AppendChild (doc.CreateElement("summary"));
318                         
319                         if (namespace_remarks [ns] != null)
320                                 elements.AppendChild (doc.ImportNode ((XmlNode)namespace_remarks [ns],true));
321                         else
322                                 elements.AppendChild (doc.CreateElement("remarks"));
323                         
324                         hs.Message (TraceLevel.Info, "Have {0} elements in the {1}", list.Count, ns);
325                         foreach (TypeInfo p in list){
326                                 XmlElement e = null;
327                                 
328                                 switch (p.type_kind){
329                                 case "Class":
330                                         e = doc.CreateElement ("class"); 
331                                         break;
332                                         
333                                 case "Enumeration":
334                                         e = doc.CreateElement ("enum");
335                                         break;
336                                         
337                                 case "Structure":
338                                         e = doc.CreateElement ("struct");
339                                         break;
340                                         
341                                 case "Delegate":
342                                         e = doc.CreateElement ("delegate");
343                                         break;
344                                         
345                                 case "Interface":
346                                         e = doc.CreateElement ("interface");
347                                         break;
348                                 }
349                                 
350                                 e.SetAttribute ("name", p.type_name);
351                                 e.SetAttribute ("fullname", p.type_full);
352                                 e.SetAttribute ("assembly", p.type_assembly);
353                                 XmlNode copy = doc.ImportNode (p.type_doc, true);
354                                 e.AppendChild (copy);
355                                 elements.AppendChild (e);
356                         }
357                         hs.PackXml ("xml.summary." + ns, doc,(string) namespace_realpath[ns]);
358                 }
359                 
360                 
361                 XmlDocument nsSummary = new XmlDocument ();
362                 XmlElement root = nsSummary.CreateElement ("elements");
363                 nsSummary.AppendChild (root);
364                 
365                 foreach (DictionaryEntry de in namespace_summaries) {
366                         XmlNode n = (XmlNode)de.Value;
367                         XmlElement summary = nsSummary.CreateElement ("namespace");
368                         summary.SetAttribute ("ns", (string)de.Key);
369                         root.AppendChild (summary);
370                         if (n != null)
371                                 summary.AppendChild (nsSummary.ImportNode (n,true));
372                         else
373                                 summary.AppendChild (nsSummary.CreateElement("summary"));
374                 }
375                 tree.HelpSource.PackXml ("mastersummary.xml", nsSummary, null);
376                 AddExtensionMethods (tree);
377                 AddImageFiles (hs, tree);
378         }
379
380         void AddExtensionMethods (Tree tree)
381         {
382                 XmlDocument extensions = null;
383                 XmlNode root = null;
384                 int numMethods = 0;
385                 foreach (string asm in asm_dirs) {
386                         string overview_file = Path.Combine (asm, "index.xml");
387                         if (File.Exists (overview_file)) {
388                                 XmlDocument overview = new XmlDocument ();
389                                 overview.Load (overview_file);
390                                 XmlNodeList e = overview.SelectNodes ("/Overview/ExtensionMethods/*");
391                                 if (e.Count > 0) {
392                                         if (extensions == null) {
393                                                 extensions = new XmlDocument ();
394                                                 root = extensions.CreateElement ("ExtensionMethods");
395                                                 extensions.AppendChild (root);
396                                         }
397                                         foreach (XmlNode n in e) {
398                                                 ++numMethods;
399                                                 root.AppendChild (extensions.ImportNode (n, true));
400                                         }
401                                 }
402                         }
403                 }
404                 if (extensions != null) {
405                         tree.HelpSource.Message (TraceLevel.Info, "Have {0} extension methods", numMethods);
406                         tree.HelpSource.PackXml ("ExtensionMethods.xml", extensions, "ExtensionMethods.xml");
407                 }
408         }
409
410         void AddImageFiles (HelpSource hs, Tree tree)
411         {
412                 foreach (string asm in asm_dirs) {
413                         string path = Path.Combine (asm, "_images");
414                         if (!Directory.Exists (path))
415                                 return;
416
417 #if NET_2_0
418                         foreach (var img in Directory.GetFiles (path))
419 #else
420                         foreach (var img in Directory.EnumerateFiles (path))
421 #endif
422                                 hs.PackFile (img, Path.GetFileName (img));
423                 }
424         }
425       
426         Hashtable/*<string, List<TypeInfo>>*/ class_summaries = new Hashtable ();
427         Hashtable/*<string, XmlNode>*/ namespace_summaries = new Hashtable ();
428         Hashtable/*<string, XmlNode>*/ namespace_remarks = new Hashtable ();
429         Hashtable/*<string, string -- path>*/ namespace_realpath = new Hashtable ();
430
431         XmlDocument detached = new XmlDocument ();
432         
433         void PopulateClass (Tree tree, string ns, Node ns_node, string file)
434         {
435                 XmlDocument doc = new XmlDocument ();
436                 doc.Load (file);
437                 
438                 string name = EcmaDoc.GetClassName (doc);
439                 string assembly = EcmaDoc.GetClassAssembly (doc);
440                 string kind = EcmaDoc.GetTypeKind (doc);
441                 string full = EcmaDoc.GetFullClassName (doc);
442
443                 Node class_node;
444                 string file_code = ns_node.tree.HelpSource.PackFile (file);
445
446                 XmlNode class_summary = detached.ImportNode (doc.SelectSingleNode ("/Type/Docs/summary"), true);
447                 ArrayList l = (ArrayList) class_summaries [ns];
448                 if (l == null){
449                         l = new ArrayList ();
450                         class_summaries [ns] = (object) l;
451                 }
452                 l.Add (new TypeInfo (kind, assembly, full, name, class_summary));
453                
454                 class_node = ns_node.LookupNode (String.Format ("{0} {1}", name, kind), "ecma:" + file_code + "#" + name + "/");
455                 
456                 if (kind == "Delegate") {
457                         if (doc.SelectSingleNode("/Type/ReturnValue") == null)
458                                 tree.HelpSource.Message (TraceLevel.Error, "Delegate " + name + " does not have a ReturnValue node.  See the ECMA-style updates.");
459                 }
460
461                 if (kind == "Enumeration")
462                         return;
463
464                 if (kind == "Delegate")
465                         return;
466                 
467                 //
468                 // Always add the Members node
469                 //
470                 class_node.CreateNode ("Members", "*");
471
472                 PopulateMember (doc, name, class_node, "Constructor", "Constructors");
473                 PopulateMember (doc, name, class_node, "Method", "Methods");
474                 PopulateMember (doc, name, class_node, "Property", "Properties");
475                 PopulateMember (doc, name, class_node, "Field", "Fields");
476                 PopulateMember (doc, name, class_node, "Event", "Events");
477                 PopulateMember (doc, name, class_node, "Operator", "Operators");
478         }
479
480         class NodeIndex {
481                 public XmlNode node;
482                 public int     index;
483
484                 public NodeIndex (XmlNode node, int index)
485                 {
486                         this.node = node;
487                         this.index = index;
488                 }
489         }
490
491         struct NodeCompare : IComparer {
492                 public int Compare (object a, object b)
493                 {
494                         NodeIndex na = (NodeIndex) a;
495                         NodeIndex nb = (NodeIndex) b;
496
497                         return String.Compare (na.node.Attributes ["MemberName"].InnerText,
498                                                nb.node.Attributes ["MemberName"].InnerText);
499                 }
500         }
501
502         string GetMemberName (XmlNode node)
503         {
504                 return node.Attributes ["MemberName"].InnerText;
505         }
506         
507         //
508         // Performs an XPath query on the document to extract the nodes for the various members
509         // we also use some extra text to pluralize the caption
510         //
511         void PopulateMember (XmlDocument doc, string typename, Node node, string type, string caption)
512         {
513                 string select = type;
514                 if (select == "Operator") select = "Method";
515                 
516                 XmlNodeList list1 = doc.SelectNodes (String.Format ("/Type/Members/Member[MemberType=\"{0}\"]", select));
517                 ArrayList list = new ArrayList();
518                 int i = 0;
519                 foreach (XmlElement n in list1) {
520                         n.SetAttribute("assembler_index", (i++).ToString());
521                         if (type == "Method" && GetMemberName(n).StartsWith("op_")) continue;
522                         if (type == "Operator" && !GetMemberName(n).StartsWith("op_")) continue;
523                         list.Add(n);
524                 }
525                 
526                 int count = list.Count;
527                 
528                 if (count == 0)
529                         return;
530
531                 Node nodes_node;
532                 string key = type.Substring (0, 1);
533                 nodes_node = node.CreateNode (caption, key);
534                 
535                 switch (type) {
536                         case "Event":
537                         case "Field":
538                                 foreach (XmlElement n in list)
539                                         nodes_node.CreateNode (GetMemberName (n), n.GetAttribute("assembler_index"));
540                                 break;
541
542                         case "Constructor":
543                                 foreach (XmlElement n in list)
544                                         nodes_node.CreateNode (EcmaHelpSource.MakeSignature(n, typename), n.GetAttribute("assembler_index"));
545                                 break;
546
547                         case "Property": // properties with indexers can be overloaded too
548                         case "Method":
549                         case "Operator":
550                                 foreach (XmlElement n in list) {
551                                         bool multiple = false;
552                                         foreach (XmlNode nn in list) {
553                                                 if (n != nn && GetMemberName(n) == nn.Attributes ["MemberName"].InnerText) {
554                                                         multiple = true;
555                                                         break;
556                                                 }
557                                         }
558                                         
559                                         string group, name, sig;
560                                         if (type != "Operator") {
561                                                 name = GetMemberName(n);
562                                                 sig = EcmaHelpSource.MakeSignature(n, null);
563                                                 group = name;
564                                         } else {
565                                                 EcmaHelpSource.MakeOperatorSignature(n, out name, out sig);
566                                                 group = name;
567                                         }
568                                         
569                                         if (multiple) {
570                                                 nodes_node.LookupNode (group, group)
571                                                         .CreateNode (sig, n.GetAttribute("assembler_index"));
572                                         } else {
573                                                 nodes_node.CreateNode (name, n.GetAttribute("assembler_index"));
574                                         }
575                                 }
576                                 
577                                 foreach (Node n in nodes_node.Nodes) {
578                                         if (!n.IsLeaf)
579                                                 n.Sort ();
580                                 }
581                                 
582                                 break;
583                                 
584                         default:
585                                 throw new InvalidOperationException();
586                 }
587                 
588                 nodes_node.Sort ();
589         }
590
591 }
592
593 //
594 // The Ecma HelpSource provider
595 //
596 public class EcmaHelpSource : HelpSource {
597
598         public EcmaHelpSource (string base_file, bool create) : base (base_file, create)
599         {
600                 ExtObject = new ExtensionObject (this);
601         }
602
603         public EcmaHelpSource ()
604         {
605                 ExtObject = new ExtensionObject (this);
606         }
607
608         static string css_ecma;
609         public static string css_ecma_code {
610                 get {
611                         if (css_ecma != null)
612                                 return css_ecma;
613                         if (use_css) {
614                                 System.Reflection.Assembly assembly = typeof(EcmaHelpSource).Assembly;
615                                 Stream str_css = assembly.GetManifestResourceStream ("mono-ecma.css");
616                                 css_ecma = (new StreamReader (str_css)).ReadToEnd();
617                         } else {
618                                 css_ecma = String.Empty;
619                         }
620                         return css_ecma;
621                 }
622         }
623
624         public override string InlineCss {
625                 get {return base.InlineCss + css_ecma_code;}
626         }
627
628         static string js;
629         public static string js_code {
630                 get {
631                         if (js != null)
632                                 return js;
633                         if (use_css) {
634                                 System.Reflection.Assembly assembly = typeof(EcmaHelpSource).Assembly;
635                                 Stream str_js = assembly.GetManifestResourceStream ("helper.js");
636                                 js = (new StreamReader (str_js)).ReadToEnd();
637                         } else {
638                                 js = String.Empty;
639                         }
640                         return js;
641                 }
642         }
643
644         public override string InlineJavaScript {
645                 get {return js_code + base.InlineJavaScript;}
646         }
647
648         public override string GetPublicUrl (string url)
649         {
650                 if (url == null || url.Length == 0)
651                         return url;
652                 try {
653                         string rest;
654                         XmlDocument d = GetXmlFromUrl (url, out rest);
655                         if (rest == "")
656                                 return EcmaDoc.GetCref (d.DocumentElement);
657                         XmlElement e = GetDocElement (d, rest);
658                         if (e == null)
659                                 return EcmaDoc.GetCref (d.DocumentElement) + "/" + rest;
660                         return EcmaDoc.GetCref (e);
661                 }
662                 catch (Exception e) {
663                         return url;
664                 }
665         }
666
667         private static XmlElement GetDocElement (XmlDocument d, string rest)
668         {
669                 string memberType = null;
670                 string memberIndex = null;
671
672                 string [] nodes = rest.Split (new char [] {'/'});
673                 
674                 switch (nodes.Length) {
675                         // e.g. C; not supported.
676                         case 1:
677                                 return null;
678                         // e.g. C/0 or M/MethodName; the latter isn't supported.
679                         case 2:
680                                 try {
681                                         // XPath wants 1-based indexes, while the url uses 0-based values.
682                                         memberIndex = (int.Parse (nodes [1]) + 1).ToString ();
683                                         memberType  = GetMemberType (nodes [0]);
684                                 } catch {
685                                         return null;
686                                 }
687                                 break;
688                         // e.g. M/MethodName/0
689                         case 3:
690                                 memberIndex = (int.Parse (nodes [2]) + 1).ToString ();
691                                 memberType  = GetMemberType (nodes [0]);
692                                 break;
693                         // not supported
694                         default:
695                                 return null;
696                 }
697                 string xpath = "/Type/Members/Member[MemberType=\"" + memberType + "\"]" + 
698                                 "[position()=" + memberIndex + "]";
699                 return (XmlElement) d.SelectSingleNode (xpath);
700         }
701
702         private static string GetMemberType (string type)
703         {
704                 switch (type) {
705                         case "C": return "Constructor";
706                         case "E": return "Event";
707                         case "F": return "Field";
708                         case "M": return "Method";
709                         case "P": return "Property";
710                         default:
711                                 throw new NotSupportedException ("Member Type: '" + type + "'.");
712                 }
713         }
714
715         public override string GetText (string url, out Node match_node)
716         {
717                 match_node = null;
718
719                 string cached = GetCachedText (url);
720                 if (cached != null)
721                         return cached;
722                 
723                 if (url == "root:")
724                 {
725                         XmlReader summary = GetHelpXml ("mastersummary.xml");
726                         if (summary == null)
727                                 return null;
728
729                         XsltArgumentList args = new XsltArgumentList();
730                         args.AddExtensionObject("monodoc:///extensions", ExtObject);
731                         args.AddParam("show", "", "masteroverview");
732                         string s = Htmlize(summary, args);
733                         return BuildHtml (css_ecma_code, js_code, s); 
734                 }
735                 
736                 if (url.StartsWith ("ecma:")) {
737                         string s = GetTextFromUrl (url);
738                         return BuildHtml (css_ecma_code, js_code, s); 
739                 }
740
741                 return null;
742         }
743
744
745         string RenderMemberLookup (string typename, string member, ref Node type_node)
746         {
747                 if (type_node.Nodes == null)
748                         return null;
749
750                 string membername = member;
751                 string[] argtypes = null;
752                 if (member.IndexOf("(") > 0) {
753                         membername = membername.Substring(0, member.IndexOf("("));
754                         member = member.Replace("@", "&");
755                         
756                         // reform the member signature with CTS names
757
758                         string x = member.Substring(member.IndexOf("(")+1);
759                         argtypes = x.Substring(0, x.Length-1).Split(',', ':'); // operator signatures have colons
760
761                         if (membername == ".ctor")
762                                 membername = typename;
763
764                         member = membername + "(";
765                         for (int i = 0; i < argtypes.Length; i++) {
766                                 argtypes[i] = EcmaDoc.ConvertCTSName(argtypes[i]);
767                                 if (i > 0) member += ",";
768                                 member += argtypes[i];
769                         }
770                         member += ")";
771                 }
772                 
773                 // Check if a node caption matches exactly
774                 
775                 bool isoperator = false;
776                 
777                 if ((membername == "op_Implicit" || membername == "op_Explicit") && argtypes.Length == 2) {
778                         isoperator = true;
779                         membername = "Conversion";
780                         member = argtypes[0] + " to " + argtypes[1];
781                 } else if (membername.StartsWith("op_")) {
782                         isoperator = true;
783                         membername = membername.Substring(3);
784                 }
785
786                 foreach (Node x in type_node.Nodes){
787                         if (x.Nodes == null)
788                                 continue;
789                         if (isoperator && x.Caption != "Operators")
790                                 continue;
791                         
792                         foreach (Node m in x.Nodes) {
793                                 string caption = m.Caption;
794                                 string ecaption = ToEscapedMemberName (caption);
795                                 if (m.IsLeaf) {
796                                         // No overloading (usually), is just the member name.  The whole thing for constructors.
797                                         if (caption == membername || caption == member ||
798                                                         ecaption == membername || ecaption == member) {
799                                                 type_node = m;
800                                                 return GetTextFromUrl (m.URL);
801                                         }
802                                 } else if (caption == member || ecaption == member) {
803                                         // Though there are overloads, no arguments are in the url, so use this base node
804                                         type_node = m;
805                                         return GetTextFromUrl (m.URL);
806                                 } else {
807                                         // Check subnodes which are the overloads -- must match signature
808                                         foreach (Node mm in m.Nodes) {
809                                                 ecaption = ToEscapedTypeName (mm.Caption);
810                                                 if (mm.Caption == member || ecaption == member) {
811                                                         type_node = mm;
812                                                         return GetTextFromUrl (mm.URL);
813                                                 }
814                                         }
815                                 }
816                         }
817                 }
818                 
819                 return null;
820         }
821
822         public static string MakeSignature (XmlNode n, string cstyleclass)
823         {
824                 string sig;
825
826                 if (cstyleclass == null)
827                         sig = n.Attributes["MemberName"].InnerText;
828                 else {
829                         // constructor style
830                         sig = cstyleclass;
831                 }
832         
833                 /*if (n.SelectSingleNode("MemberType").InnerText == "Method" || n.SelectSingleNode("MemberType").InnerText == "Constructor") {*/ // properties with indexers too
834                         XmlNodeList paramnodes = n.SelectNodes("Parameters/Parameter");
835                         sig += "(";
836                         bool first = true;
837                         foreach (XmlNode p in paramnodes) {
838                                 if (!first) sig += ",";
839                                 string type = p.Attributes["Type"].InnerText;
840                                 type = EcmaDoc.ConvertCTSName(type);
841                                 sig += type;
842                                 first = false;
843                         }
844                         sig += ")";
845                 //}
846
847                 return sig;
848         }
849         
850         public static void MakeOperatorSignature (XmlNode n, out string nicename, out string sig)
851         {
852                 string name;
853
854                 name = n.Attributes["MemberName"].InnerText;
855                 nicename = name.Substring(3);
856                 
857                 switch (name) {
858                         // unary operators: no overloading possible     [ECMA-335 Â§10.3.1]
859                         case "op_UnaryPlus":                    // static     R operator+       (T)
860                         case "op_UnaryNegation":                // static     R operator-       (T)
861                         case "op_LogicalNot":                   // static     R operator!       (T)
862                         case "op_OnesComplement":               // static     R operator~       (T)
863                         case "op_Increment":                    // static     R operator++      (T)
864                         case "op_Decrement":                    // static     R operator--      (T)
865                         case "op_True":                         // static  bool operator true   (T)
866                         case "op_False":                        // static  bool operator false  (T)
867                         case "op_AddressOf":                    // static     R operator&       (T)
868                         case "op_PointerDereference":           // static     R operator*       (T)
869                                 sig = nicename;
870                                 break;
871                         
872                         // binary operators: overloading is possible [ECMA-335 Â§10.3.2]
873                         case "op_Addition":                     // static    R operator+    (T1, T2)
874                         case "op_Subtraction":                  // static    R operator-    (T1, T2)
875                         case "op_Multiply":                     // static    R operator*    (T1, T2)
876                         case "op_Division":                     // static    R operator/    (T1, T2)
877                         case "op_Modulus":                      // static    R operator%    (T1, T2)
878                         case "op_ExclusiveOr":                  // static    R operator^    (T1, T2)
879                         case "op_BitwiseAnd":                   // static    R operator&    (T1, T2)
880                         case "op_BitwiseOr":                    // static    R operator|    (T1, T2)
881                         case "op_LogicalAnd":                   // static    R operator&&   (T1, T2)
882                         case "op_LogicalOr":                    // static    R operator||   (T1, T2)
883                         case "op_Assign":                       // static    R operator=    (T1, T2)
884                         case "op_LeftShift":                    // static    R operator<<   (T1, T2)
885                         case "op_RightShift":                   // static    R operator>>   (T1, T2)
886                         case "op_SignedRightShift":             // static    R operator>>   (T1, T2)
887                         case "op_UnsignedRightShift":           // static    R operator>>>  (T1, T2)
888                         case "op_Equality":                     // static bool operator==   (T1, T2)
889                         case "op_GreaterThan":                  // static bool operator>    (T1, T2)
890                         case "op_LessThan":                     // static bool operator<    (T1, T2)
891                         case "op_Inequality":                   // static bool operator!=   (T1, T2)
892                         case "op_GreaterThanOrEqual":           // static bool operator>=   (T1, T2)
893                         case "op_LessThanOrEqual":              // static bool operator<=   (T1, T2)
894                         case "op_UnsignedRightShiftAssignment": // static    R operator>>>= (T1, T2)
895                         case "op_MemberSelection":              // static    R operator->   (T1, T2)
896                         case "op_RightShiftAssignment":         // static    R operator>>=  (T1, T2)
897                         case "op_MultiplicationAssignment":     // static    R operator*=   (T1, T2)
898                         case "op_PointerToMemberSelection":     // static    R operator->*  (T1, T2)
899                         case "op_SubtractionAssignment":        // static    R operator-=   (T1, T2)
900                         case "op_ExclusiveOrAssignment":        // static    R operator^=   (T1, T2)
901                         case "op_LeftShiftAssignment":          // static    R operator<<=  (T1, T2)
902                         case "op_ModulusAssignment":            // static    R operator%=   (T1, T2)
903                         case "op_AdditionAssignment":           // static    R operator+=   (T1, T2)
904                         case "op_BitwiseAndAssignment":         // static    R operator&=   (T1, T2)
905                         case "op_BitwiseOrAssignment":          // static    R operator|=   (T1, T2)
906                         case "op_Comma":                        // static    R operator,    (T1, T2)
907                         case "op_DivisionAssignment":           // static    R operator/=   (T1, T2)
908                         default:                                // If all else fails, assume it can be overridden...whatever it is.
909                                 XmlNodeList paramnodes = n.SelectNodes("Parameters/Parameter");
910                                 sig = nicename + "(";
911                                 bool first = true;
912                                 foreach (XmlNode p in paramnodes) {
913                                         if (!first) sig += ",";
914                                         string type = p.Attributes["Type"].InnerText;
915                                         type = EcmaDoc.ConvertCTSName(type);
916                                         sig += type;
917                                         first = false;
918                                 }
919                                 sig += ")";
920                                 break;
921                         
922                         // conversion operators: overloading based on parameter and return type [ECMA-335 Â§10.3.3]
923                         case "op_Implicit":                    // static implicit operator R (T)
924                         case "op_Explicit":                    // static explicit operator R (T)
925                                 nicename = "Conversion";
926                                 string arg = n.SelectSingleNode("Parameters/Parameter/@Type").InnerText;
927                                 string ret = n.SelectSingleNode("ReturnValue/ReturnType").InnerText;
928                                 sig = EcmaDoc.ConvertCTSName(arg) + " to " + EcmaDoc.ConvertCTSName(ret);
929                                 break;
930                 }       
931         }
932
933         //
934         // This routine has to perform a lookup on a type.
935         //
936         // Example: T:System.Text.StringBuilder
937         //
938         // The prefix is the kind of opereation being requested (T:, E:, M: etc)
939         // ns is the namespace being looked up
940         // type is the type being requested
941         //
942         // This has to walk our toplevel (which is always a namespace)
943         // And then the type space, and then walk further down depending on the request
944         //
945         public override string RenderTypeLookup (string prefix, string ns, string type, string member, out Node match_node)
946         {
947                 string url = GetUrlForType (prefix, ns, type, member, out match_node);
948                 if (url == null) return null;
949                 return GetTextFromUrl (url);
950         }
951
952         public virtual string GetIdFromUrl (string prefix, string ns, string type)
953         {
954                 Node tmp_node = new Node (Tree, "", "");
955                 string url = GetUrlForType (prefix, ns, type, null, out tmp_node);
956                 if (url == null) return null;
957                 return GetFile (url.Substring (5), out url);
958         }
959         
960         public string GetUrlForType (string prefix, string ns, string type, string member, out Node match_node)
961         {
962                 if (!prefix.EndsWith(":"))
963                         throw new ArgumentException("prefix");
964
965                 if (member != null)
966                         member = member.Replace ("#", ".").Replace ("{", "<").Replace ("}", ">");
967                         
968                 // If a nested type, compare only inner type name to node list.
969                 // This should be removed when the node list doesn't lose the containing type name.
970                 type = ToEscapedTypeName (type.Replace("+", "."));
971                 MatchAttempt[] attempts = GetAttempts (ns, type);
972
973                 foreach (Node ns_node in Tree.Nodes){
974                         string ns_node_namespace = ns_node.Element.Substring (2);
975
976                         if (!MatchesNamespace (attempts, ns_node_namespace, out type))
977                                 continue;
978                         
979                         foreach (Node type_node in ns_node.Nodes){
980                                 string element = type_node.Element;
981                                 
982                                 string cname;
983                                 if (element.StartsWith("T:")) {
984                                         cname = element.Substring(2);
985                                         string _ns;
986                                         RootTree.GetNamespaceAndType (cname, out _ns, out cname);
987                                         cname = ToEscapedTypeName (cname);
988                                         int pidx = cname.LastIndexOf (".");
989                                         cname = cname.Substring(pidx+1);
990                                         pidx = cname.LastIndexOf ("/");
991                                         if (pidx != -1)
992                                                 cname = cname.Substring(0, pidx);
993                                         cname = cname.Replace("+", ".");
994                                 } else {                                
995                                         int pidx = element.IndexOf ("#");
996                                         int sidx = element.IndexOf ("/");
997                                         cname = element.Substring (pidx + 1, sidx-pidx-1);
998                                         cname = ToEscapedTypeName (cname);
999                                 }
1000                                 
1001                                 //Console.WriteLine ("t:{0} cn:{1} p:{2}", type, cname, prefix);
1002
1003                                 if (type == cname && prefix == "T:") {
1004                                         match_node = type_node;
1005                                         return type_node.URL;
1006                                 } else if (type.StartsWith (cname)){
1007                                         int p = cname.Length;
1008
1009                                         match_node = type_node;
1010                                         if (type == cname){
1011                                                 string ret = RenderMemberLookup (type, member, ref match_node);
1012                                                 if (ret == null)
1013                                                         return type_node.URL;
1014                                                 return match_node.URL;
1015
1016                                         } else if (type [p] == '/'){
1017                                                 //
1018                                                 // This handles summaries
1019                                                 //
1020                                                 match_node = null;
1021                                                 foreach (Node nd in type_node.Nodes) {
1022                                                         if (nd.Element [nd.Element.Length - 1] == type [p + 1]) {
1023                                                                 match_node = nd;
1024                                                                 break;
1025                                                         }
1026                                                 }
1027                                                 
1028                                                 string ret = type_node.URL;
1029                                                 if (!ret.EndsWith("/")) ret += "/";
1030                                                 return ret + type.Substring (p + 1);
1031                                         }
1032                                 }
1033                         }
1034                 }
1035
1036                 match_node = null;
1037                 return null;
1038         }
1039
1040         struct MatchAttempt {
1041                 public string Namespace;
1042                 public string Type;
1043
1044                 public MatchAttempt (string ns, string t)
1045                 {
1046                         Namespace = ns;
1047                         Type = t;
1048                 }
1049         }
1050
1051         private static MatchAttempt[] GetAttempts (string ns, string type)
1052         {
1053                 MatchAttempt[] attempts = new MatchAttempt [Count (ns, '.') + 1];
1054                 int wns = 0;
1055                 for (int i = 0; i < ns.Length; ++i) {
1056                         if (ns [i] == '.')
1057                                 attempts [wns++] = new MatchAttempt (ns.Substring (0, i), 
1058                                                 ns.Substring (i+1) + "." + type);
1059                 }
1060                 attempts [wns++] = new MatchAttempt (ns, type);
1061                 return attempts;
1062         }
1063
1064         private static int Count (string s, char c)
1065         {
1066                 int n = 0;
1067                 for (int i = 0; i < s.Length; ++i)
1068                         if (s [i] == c)
1069                                 ++n;
1070                 return n;
1071         }
1072
1073         private static bool MatchesNamespace (MatchAttempt[] attempts, string ns, out string type)
1074         {
1075                 for (int i = 0; i < attempts.Length; ++i)
1076                         if (ns == attempts [i].Namespace) {
1077                                 type = attempts [i].Type;
1078                                 return true;
1079                         }
1080                 type = null;
1081                 return false;
1082         }
1083         
1084         public static string ToEscapedTypeName (string typename)
1085         {
1086                 return ToEscapedName (typename, "`");
1087         }
1088
1089         static string ToEscapedName (string name, string escape)
1090         {
1091                 StringBuilder filename = new StringBuilder (name.Length);
1092                 int numArgs = 0;
1093                 int numLt = 0;
1094                 bool copy = true;
1095
1096                 for (int i = 0; i < name.Length; ++i) {
1097                         char c = name [i];
1098                         switch (c) {
1099                                 case '{':
1100                                 case '<':
1101                                         copy = false;
1102                                         ++numLt;
1103                                         break;
1104                                 case '}':
1105                                 case '>':
1106                                         --numLt;
1107                                         if (numLt == 0) {
1108                                                 filename.Append (escape).Append ((numArgs+1).ToString());
1109                                                 numArgs = 0;
1110                                                 copy = true;
1111                                         }
1112                                         break;
1113                                 case ',':
1114                                         if (numLt == 1)
1115                                                 ++numArgs;
1116                                         break;
1117                                 default:
1118                                         if (copy)
1119                                                 filename.Append (c);
1120                                         break;
1121                         }
1122                 }
1123                 return filename.ToString ();
1124         }
1125
1126         static string ToEscapedMemberName (string membername)
1127         {
1128                 return ToEscapedName (membername, "``");
1129         }
1130         
1131         public override string GetNodeXPath (XPathNavigator n)
1132         {
1133                 if (n.Matches ("/Type/Docs/param")) {
1134                         string type_name = (string) n.Evaluate ("string (ancestor::Type/@FullName)");
1135                         string param_name = (string) n.Evaluate ("string (@name)");
1136                         
1137                         return String.Format ("/Type [@FullName = '{0}']/Docs/param[@name='{1}']", type_name, param_name);
1138                 }
1139
1140                 if (n.Matches ("/Type/Docs/*")) {
1141                         string type_name = (string) n.Evaluate ("string (ancestor::Type/@FullName)");
1142                         
1143                         return String.Format ("/Type [@FullName = '{0}']/Docs/{1}", type_name, n.Name);
1144                 }
1145                 
1146                 if (n.Matches ("/Type/Members/Member/Docs/*")) {
1147                         string type_name = (string) n.Evaluate ("string (ancestor::Type/@FullName)");
1148                         string member_name = (string) n.Evaluate ("string (ancestor::Member/@MemberName)");
1149                         string member_sig = (string) n.Evaluate ("string (ancestor::Member/MemberSignature [@Language='C#']/@Value)");
1150                         string param_name = (string) n.Evaluate ("string (@name)");
1151                         
1152                         if (param_name == null || param_name == "") {
1153                                 return String.Format (
1154                                 "/Type [@FullName = '{0}']/Members/Member [@MemberName = '{1}'][MemberSignature [@Language='C#']/@Value = '{2}']/Docs/{3}",
1155                                 type_name, member_name, member_sig, n.Name);
1156                         } else {
1157                                 return String.Format (
1158                                 "/Type [@FullName = '{0}']/Members/Member [@MemberName = '{1}'][MemberSignature [@Language='C#']/@Value = '{2}']/Docs/param [@name = '{3}']",
1159                                 type_name, member_name, member_sig, param_name);
1160                         }
1161                 }
1162                 
1163                 Message (TraceLevel.Warning, "WARNING: Was not able to get clean XPath expression for node {0}", EditingUtils.GetXPath (n));
1164                 return base.GetNodeXPath (n);
1165         }
1166
1167         protected virtual XmlDocument GetNamespaceDocument (string ns)
1168         {
1169                 return GetHelpXmlWithChanges ("xml.summary." + ns);
1170         }
1171
1172         public override string RenderNamespaceLookup (string nsurl, out Node match_node)
1173         {
1174                 foreach (Node ns_node in Tree.Nodes){
1175                         if (ns_node.Element != nsurl)
1176                                 continue;
1177
1178                         match_node = ns_node;
1179                         string ns_name = nsurl.Substring (2);
1180                         
1181                         XmlDocument doc = GetNamespaceDocument (ns_name);
1182                         if (doc == null)
1183                                 return null;
1184
1185                         XsltArgumentList args = new XsltArgumentList();
1186                         args.AddExtensionObject("monodoc:///extensions", ExtObject);
1187                         args.AddParam("show", "", "namespace");
1188                         args.AddParam("namespace", "", ns_name);
1189                         args.AddParam ("source-id", "", SourceID.ToString ());
1190                         string s = Htmlize(new XmlNodeReader (doc), args);
1191                         return BuildHtml (css_ecma_code, js_code, s); 
1192
1193                 }
1194                 match_node = null;
1195                 return null;
1196         }
1197
1198         private string SelectString(XmlNode node, string xpath) {
1199                 XmlNode ret = node.SelectSingleNode(xpath);
1200                 if (ret == null) return "";
1201                 return ret.InnerText;
1202         }
1203         private int SelectCount(XmlNode node, string xpath) {
1204                 return node.SelectNodes(xpath).Count;
1205         }
1206
1207         //
1208         // Returns the XmlDocument from the given url, and fills in `rest'
1209         //
1210         protected virtual XmlDocument GetXmlFromUrl(string url, out string rest) {
1211                 // Remove ecma:
1212                 url = url.Substring (5);
1213                 string file = GetFile (url, out rest);
1214
1215                 // Console.WriteLine ("Got [{0}] and [{1}]", file, rest);
1216                 return GetHelpXmlWithChanges (file);
1217         }
1218         
1219         string GetTextFromUrl (string url)
1220         {
1221                 if (nozip) {
1222                         string path = XmlDocUtils.GetCachedFileName (base_dir, url);
1223                         if (File.Exists (path))
1224                                 return File.OpenText (path).ReadToEnd ();
1225                         return null;
1226                 }
1227
1228                 string rest, rest2;
1229                 Node node;
1230
1231                 XmlDocument doc = GetXmlFromUrl (url, out rest);
1232                 
1233                 // Load base-type information so the stylesheet can draw the inheritance
1234                 // tree and (optionally) include inherited members in the members list.
1235                 XmlElement basenode = (XmlElement)doc.SelectSingleNode("Type/Base");
1236                 XmlElement membersnode = (XmlElement)doc.SelectSingleNode("Type/Members");
1237                 XmlNode basetype = doc.SelectSingleNode("Type/Base/BaseTypeName");
1238                 int baseindex = 0;
1239                 while (basetype != null) {
1240                         // Add the ParentType node to Type/Base
1241                         XmlElement inheritancenode = doc.CreateElement("ParentType");
1242                         inheritancenode.SetAttribute("Type", basetype.InnerText);
1243                         inheritancenode.SetAttribute("Order", (baseindex++).ToString());
1244                         basenode.AppendChild(inheritancenode);
1245                         
1246                         // Load the base type XML data
1247                         int dot = basetype.InnerText.LastIndexOf('.');
1248                         string ns = basetype.InnerText.Substring(0, dot == -1 ? 0 : dot);
1249                         string n = basetype.InnerText.Substring(dot == -1 ? 0 : dot+1);
1250                         string basetypeurl = GetUrlForType("T:", ns, n, null, out node);
1251                         XmlDocument basetypedoc = null;
1252                         if (basetypeurl != null)
1253                                 basetypedoc = GetXmlFromUrl (basetypeurl, out rest2);
1254                         if (basetypedoc == null) {
1255                                 inheritancenode.SetAttribute("Incomplete", "1");
1256                                 break;
1257                         }
1258                         
1259                         if (SettingsHandler.Settings.ShowInheritedMembers) {
1260                                 // Add inherited members
1261                                 foreach (XmlElement member in basetypedoc.SelectNodes("Type/Members/Member[not(MemberType='Constructor')]")) {
1262                                         string sig = SelectString(member, "MemberSignature[@Language='C#']/@Value");
1263                                         if (sig.IndexOf(" static ") >= 0) continue;
1264                                         
1265                                         // If the signature of member matches the signature of a member already in the XML,
1266                                         // don't add it.
1267                                         string xpath = "@MemberName='" + SelectString(member, "@MemberName") + "'";
1268                                         xpath       += " and ReturnValue/ReturnType='" + SelectString(member, "ReturnValue/ReturnType") + "'";
1269                                         xpath       += " and count(Parameters/Parameter)=" + SelectCount(member, "Parameters/Parameter") + "";
1270                                         int pi = 1;
1271                                         foreach (XmlElement p in member.SelectNodes("Parameters/Parameter")) {
1272                                                 xpath   += " and Parameters/Parameter[position()=" + pi + "]/@Type = '" + p.GetAttribute("Type") + "'";
1273                                                 pi++;
1274                                         }
1275                                         
1276                                         // If a signature match is found, don't add.
1277                                         XmlNode match = membersnode.SelectSingleNode("Member[" + xpath + "]");
1278                                         if (match != null)
1279                                                 continue;
1280                                         
1281                                         member.SetAttribute("DeclaredIn", basetype.InnerText);
1282                                         membersnode.AppendChild(membersnode.OwnerDocument.ImportNode(member, true));                            
1283                                 }
1284                         }
1285                         
1286                         basetype = basetypedoc.SelectSingleNode("Type/Base/BaseTypeName");
1287                 }
1288                 ArrayList extensions = new ArrayList ();
1289                 AddExtensionMethodsFromHelpSource (extensions, this);
1290                 foreach (HelpSource hs in RootTree.HelpSources) {
1291                         EcmaHelpSource es = hs as EcmaHelpSource;
1292                         if (es == null)
1293                                 continue;
1294                         if (es == this)
1295                                 continue;
1296                         AddExtensionMethodsFromHelpSource (extensions, es);
1297                 }
1298                 XmlDocUtils.AddExtensionMethods (doc, extensions, delegate (string s) {
1299                                 s = s.StartsWith ("T:") ? s : "T:" + s;
1300                                 return RootTree.GetHelpXml (s);
1301                 });
1302
1303                 XsltArgumentList args = new XsltArgumentList();
1304
1305                 args.AddExtensionObject("monodoc:///extensions", ExtObject);
1306
1307                 args.AddParam ("source-id", "", SourceID.ToString ());
1308                 
1309                 if (rest == "") {
1310                         args.AddParam("show", "", "typeoverview");
1311                         string s = Htmlize(new XmlNodeReader (doc), args);
1312                         return BuildHtml (css_ecma_code, js_code, s); 
1313                 }
1314                 
1315                 string [] nodes = rest.Split (new char [] {'/'});
1316                 
1317                 switch (nodes.Length) {
1318                         case 1:
1319                                 args.AddParam("show", "", "members");
1320                                 args.AddParam("index", "", "all");
1321                                 break;
1322                         case 2:
1323                                 // Could either be a single member, or an overload thingy
1324                                 try {
1325                                         int.Parse (nodes [1]); // is it an int
1326                                         
1327                                         args.AddParam("show", "", "member");
1328                                         args.AddParam("index", "", nodes [1]);
1329                                 } catch {
1330                                         args.AddParam("show", "", "overloads");
1331                                         args.AddParam("index", "", nodes [1]);
1332                                 }
1333                                 break;
1334                         case 3:
1335                                 args.AddParam("show", "", "member");
1336                                 args.AddParam("index", "", nodes [2]);
1337                                 break;
1338                         default:
1339                                 return "What the hell is this URL " + url;
1340                 }
1341
1342                 switch (nodes [0]){
1343                 case "C":
1344                         args.AddParam("membertype", "", "Constructor");
1345                         break;
1346                 case "M":
1347                         args.AddParam("membertype", "", "Method");
1348                         break;
1349                 case "P":
1350                         args.AddParam("membertype", "", "Property");
1351                         break;
1352                 case "F":
1353                         args.AddParam("membertype", "", "Field");
1354                         break;
1355                 case "E":
1356                         args.AddParam("membertype", "", "Event");
1357                         break;
1358                 case "O":
1359                         args.AddParam("membertype", "", "Operator");
1360                         break;
1361                 case "X":
1362                         args.AddParam("membertype", "", "ExtensionMethod");
1363                         break;
1364                 case "*":
1365                         args.AddParam("membertype", "", "All");
1366                         break;
1367                 default:
1368                         return "Unknown url: " + url;
1369                 }
1370
1371                 string html = Htmlize(new XmlNodeReader (doc), args);
1372                 return BuildHtml (css_ecma_code, js_code, html); 
1373         }
1374
1375         void AddExtensionMethodsFromHelpSource (ArrayList extensions, EcmaHelpSource es)
1376         {
1377                 Stream s = es.GetHelpStream ("ExtensionMethods.xml");
1378                 if (s != null) {
1379                         XmlDocument d = new XmlDocument ();
1380                         d.Load (s);
1381                         foreach (XmlNode n in d.SelectNodes ("/ExtensionMethods/*")) {
1382                                 extensions.Add (n);
1383                         }
1384                 }
1385         }
1386
1387         
1388         public override void RenderPreviewDocs (XmlNode newNode, XmlWriter writer)
1389         {
1390                 XsltArgumentList args = new XsltArgumentList ();
1391                 args.AddExtensionObject ("monodoc:///extensions", ExtObject);
1392                 args.AddParam ("source-id", "", SourceID.ToString ());
1393                 
1394                 Htmlize (new XmlNodeReader (newNode), args, writer);
1395         }
1396
1397         static XslCompiledTransform ecma_transform;
1398
1399         public string Htmlize (XmlReader ecma_xml)
1400         {
1401                 return Htmlize(ecma_xml, null);
1402         }
1403
1404         public string Htmlize (XmlReader ecma_xml, XsltArgumentList args)
1405         {
1406                 EnsureTransform ();
1407                 
1408                 var output = new StringBuilder ();
1409                 ecma_transform.Transform (ecma_xml, 
1410                                 args, 
1411                                 XmlWriter.Create (output, ecma_transform.OutputSettings),
1412                                 CreateDocumentResolver ());
1413                 return output.ToString ();
1414         }
1415
1416         protected virtual XmlResolver CreateDocumentResolver ()
1417         {
1418                 // results in using XmlUrlResolver
1419                 return null;
1420         }
1421         
1422         static void Htmlize (XmlReader ecma_xml, XsltArgumentList args, XmlWriter w)
1423         {
1424                 EnsureTransform ();
1425                 
1426                 if (ecma_xml == null)
1427                         return;
1428
1429                 ecma_transform.Transform (ecma_xml, args, w, null);
1430         }
1431         
1432         static XslCompiledTransform ecma_transform_css, ecma_transform_no_css;
1433         static void EnsureTransform ()
1434         {
1435                 if (ecma_transform == null) {
1436                         ecma_transform_css = new XslCompiledTransform ();
1437                         ecma_transform_no_css = new XslCompiledTransform ();
1438                         Assembly assembly = System.Reflection.Assembly.GetCallingAssembly ();
1439                         
1440                         Stream stream = assembly.GetManifestResourceStream ("mono-ecma-css.xsl");
1441                         XmlReader xml_reader = new XmlTextReader (stream);
1442                         XmlResolver r = new ManifestResourceResolver (".");
1443                         ecma_transform_css.Load (xml_reader, XsltSettings.TrustedXslt, r);
1444                         
1445                         stream = assembly.GetManifestResourceStream ("mono-ecma.xsl");
1446                         xml_reader = new XmlTextReader (stream);
1447                         ecma_transform_no_css.Load (xml_reader, XsltSettings.TrustedXslt, r);
1448                 }
1449                 if (use_css)
1450                         ecma_transform = ecma_transform_css;
1451                 else
1452                         ecma_transform = ecma_transform_no_css;
1453         }
1454
1455         // This ExtensionObject stuff is used to check at run time whether
1456         // types and members have been implemented and whether there are any
1457         // MonoTODO attributes left on them. 
1458
1459         public readonly ExtensionObject ExtObject;
1460         public class ExtensionObject {
1461                 readonly EcmaHelpSource hs;
1462
1463                 //
1464                 // We are setting this to quiet now, as we need to transition
1465                 // monodoc to run with the 2.x runtime and provide accurate
1466                 // information in those cases.
1467                 //
1468                 bool quiet = true;
1469                 
1470                 public ExtensionObject (EcmaHelpSource hs)
1471                 {
1472                         this.hs = hs;
1473                 }
1474                 
1475                 public string Colorize(string code, string lang) {
1476                         return(Mono.Utilities.Colorizer.Colorize(code,lang));
1477                 }
1478                 // Used by stylesheet to nicely reformat the <see cref=> tags. 
1479                 public string MakeNiceSignature(string sig, string contexttype)
1480                 {
1481                         if (sig.Length < 3)
1482                                 return sig;
1483                         if (sig[1] != ':')
1484                                 return sig;
1485
1486                         char s = sig[0];
1487                         sig = sig.Substring(2);
1488                         
1489                         switch (s) {
1490                                 case 'N': return sig;
1491                                 case 'T': return ShortTypeName(sig, contexttype);
1492
1493                                 case 'C': case 'M': case 'P': case 'F': case 'E':
1494                                         string type, mem, arg;
1495                                         
1496                                         // Get arguments
1497                                         int paren;
1498                                         if (s == 'C' || s == 'M')
1499                                                 paren = sig.IndexOf("(");
1500                                         else if (s == 'P')
1501                                                 paren = sig.IndexOf("[");
1502                                         else
1503                                                 paren = 0;
1504                                         
1505                                         if (paren > 0 && paren < sig.Length-1) {
1506                                                 string[] args = sig.Substring(paren+1, sig.Length-paren-2).Split(',');                                          
1507                                                 for (int i = 0; i < args.Length; i++)
1508                                                         args[i] = ShortTypeName(args[i], contexttype);
1509                                                 arg = "(" + String.Join(", ", args) + ")";
1510                                                 sig = sig.Substring(0, paren); 
1511                                         } else {
1512                                                 arg = "";
1513                                         }
1514
1515                                         // Get type and member names
1516                                         int dot = sig.LastIndexOf(".");
1517                                         if (s == 'C' || dot <= 0 || dot == sig.Length-1) {
1518                                                 mem = "";
1519                                                 type = sig;
1520                                         } else {
1521                                                 type = sig.Substring(0, dot);
1522                                                 mem = sig.Substring(dot);
1523                                         }
1524                                                 
1525                                         type = ShortTypeName(type, contexttype);
1526                                         
1527                                         return type + mem + arg;
1528
1529                                 default:
1530                                         return sig;
1531                         }
1532                 }
1533                 
1534                 public string EditUrl (XPathNodeIterator itr)
1535                 {
1536                         if (itr.MoveNext ())
1537                                 return hs.GetEditUri (itr.Current);
1538                         
1539                         return "";
1540                 }
1541
1542                 public string EditUrlNamespace (XPathNodeIterator itr, string ns, string section)
1543                 {
1544                         if (hs is EcmaUncompiledHelpSource)
1545                                 return "edit:file:" + Path.Combine(((EcmaUncompiledHelpSource)hs).BasePath, ns + ".xml") + "@/Namespace/Docs/" + section; 
1546                         else if (itr.MoveNext ())
1547                                 return EditingUtils.FormatEditUri(itr.Current.BaseURI, "/elements/" + section);
1548                         return "";
1549                 }
1550
1551                 private static string ShortTypeName(string name, string contexttype)
1552                 {
1553                         int dot = contexttype.LastIndexOf(".");
1554                         if (dot < 0) return name;
1555                         string contextns = contexttype.Substring(0, dot+1);
1556
1557                         if (name == contexttype)
1558                                 return name.Substring(dot+1);
1559                         
1560                         if (name.StartsWith(contextns))
1561                                 return name.Substring(contextns.Length);
1562                         
1563                         return name.Replace("+", ".");
1564                 }
1565
1566                 public string MonoImpInfo(string assemblyname, string typename, string membername, string arglist, bool strlong)
1567                 {
1568                         if (quiet)
1569                                 return "";
1570                                 
1571                         ArrayList a = new ArrayList();
1572                         if (arglist != "") a.Add(arglist);
1573                         return MonoImpInfo(assemblyname, typename, membername, a, strlong);
1574                 }
1575
1576                 public string MonoImpInfo(string assemblyname, string typename, string membername, XPathNodeIterator itr, bool strlong)
1577                 {
1578                         if (quiet)
1579                                 return "";
1580                                 
1581                         ArrayList rgs = new ArrayList ();
1582                         while (itr.MoveNext ())
1583                                 rgs.Add (itr.Current.Value);
1584                         
1585                         return MonoImpInfo (assemblyname, typename, membername, rgs, strlong);
1586                 }
1587                 
1588                 public string MonoImpInfo(string assemblyname, string typename, string membername, ArrayList arglist, bool strlong)
1589                 {
1590                         try {
1591                                 Assembly assembly = null;
1592                                 
1593                                 try {
1594                                         assembly = Assembly.LoadWithPartialName(assemblyname);
1595                                 } catch (Exception) {
1596                                         // nothing.
1597                                 }
1598                                 
1599                                 if (assembly == null) {
1600                                         /*if (strlong) return "The assembly " + assemblyname + " is not available to MonoDoc.";
1601                                         else return "";*/
1602                                         return ""; // silently ignore
1603                                 }
1604
1605                                 Type t = assembly.GetType(typename, false);
1606                                 if (t == null) {
1607                                         if (strlong)
1608                                                 return typename + " has not been implemented.";
1609                                         else
1610                                                 return "Not implemented.";
1611                                 }
1612
1613                                 // The following code is flakey and fails to find existing members
1614                                 return "";
1615 #if false
1616                                 MemberInfo[] mis = t.GetMember(membername, BF.Static | BF.Instance | BF.Public | BF.NonPublic);
1617
1618                                 if (mis.Length == 0)
1619                                         return "This member has not been implemented.";
1620                                 if (mis.Length == 1)
1621                                         return MonoImpInfo(mis[0], "member", strlong);
1622
1623                                 // Scan for the appropriate member
1624                                 foreach (MemberInfo mi in mis) {
1625                                         System.Reflection.ParameterInfo[] pis;
1626
1627                                         if (mi is MethodInfo || mi is ConstructorInfo)
1628                                                 pis = ((MethodBase)mi).GetParameters();
1629                                         else if (mi is PropertyInfo)
1630                                                 pis = ((PropertyInfo)mi).GetIndexParameters();
1631                                         else
1632                                                 pis = null;
1633                                         
1634                                         if (pis != null) {
1635                                                 bool good = true;
1636                                                 if (pis.Length != arglist.Count) continue;
1637                                                 for (int i = 0; i < pis.Length; i++) {
1638                                                         if (pis[i].ParameterType.FullName != (string)arglist[i]) { good = false; break; }
1639                                                 }
1640                                                 if (!good) continue;
1641                                         }
1642
1643                                         return MonoImpInfo(mi, "member", strlong);
1644                                 }
1645 #endif
1646                         } catch (Exception) {
1647                                 return "";
1648                         }
1649                 }
1650                 
1651                 public string MonoImpInfo(System.Reflection.MemberInfo mi, string itemtype, bool strlong)
1652                 {
1653                         if (quiet)
1654                                 return "";
1655                                 
1656                         string s = "";
1657
1658                         object[] atts = mi.GetCustomAttributes(true);
1659                         int todoctr = 0;
1660                         foreach (object att in atts) if (att.GetType().Name == "MonoTODOAttribute") todoctr++;
1661
1662                         if (todoctr > 0) {
1663                                 if (strlong)
1664                                         s = "This " + itemtype + " is marked as being unfinished.<BR/>\n";
1665                                 else 
1666                                         s = "Unfinished.";
1667                         }
1668
1669                         return s;
1670                 }
1671
1672                 public string MonoImpInfo(string assemblyname, string typename, bool strlong)
1673                 {
1674                         if (quiet)
1675                                 return "";
1676                                 
1677                         try {
1678                                 if (assemblyname == "")
1679                                         return "";
1680
1681                                 Assembly assembly = Assembly.LoadWithPartialName(assemblyname);
1682                                 if (assembly == null)
1683                                         return "";
1684
1685                                 Type t = assembly.GetType(typename, false);
1686                                 if (t == null) {
1687                                         if (strlong)
1688                                                 return typename + " has not been implemented.";
1689                                         else
1690                                                 return "Not implemented.";
1691                                 }
1692
1693                                 string s = MonoImpInfo(t, "type", strlong);
1694
1695                                 if (strlong) {
1696                                         MemberInfo[] mis = t.GetMembers(BF.Static | BF.Instance | BF.Public | BF.NonPublic);
1697
1698                                         // Scan members for MonoTODO attributes
1699                                         int mctr = 0;
1700                                         foreach (MemberInfo mi in mis) {
1701                                                 string mii = MonoImpInfo(mi, null, false);
1702                                                 if (mii != "") mctr++; 
1703                                         }
1704                                         if (mctr > 0) {
1705                                                 s += "This type has " + mctr + " members that are marked as unfinished.<BR/>";
1706                                         }
1707                                 }
1708
1709                                 return s;
1710
1711                         } catch (Exception) {
1712                                 return "";
1713                         }                       
1714                 }
1715
1716                 public bool MonoEditing ()
1717                 {
1718                         return SettingsHandler.Settings.EnableEditing;
1719                 }
1720                 
1721                 public bool IsToBeAdded(string text) {
1722                         return text.StartsWith("To be added");
1723                 }
1724         }
1725
1726         //
1727         // This takes one of the ecma urls, which look like this:
1728         // ecma:NUMERIC_ID#OPAQUE/REST
1729         //
1730         // NUMERIC_ID is the numeric ID assigned by the compressor
1731         // OPAQUE is opaque for node rendering (it typically contains T:System.Byte for example)
1732         // REST is the rest of the argument used to decode information
1733         //
1734         static string GetFile (string url, out string rest)
1735         {
1736                 int pound = url.IndexOf ("#");
1737                 int slash = url.IndexOf ("/");
1738                 
1739                 string fname = url.Substring (0, pound);
1740                 rest = url.Substring (slash+1);
1741
1742                 return fname;
1743         }
1744
1745 #if false
1746         // This should have a little cache or something.
1747         static XmlDocument GetDocument (HelpSource hs, string fname)
1748         {
1749                 Stream s = hs.GetHelpStream (fname);
1750                 if (s == null){
1751                         Error ("Could not fetch document {0}", fname);
1752                         return null;
1753                 }
1754                 
1755                 XmlDocument doc = new XmlDocument ();
1756
1757                 doc.Load (s);
1758                 
1759                 return doc;
1760         }
1761 #endif
1762         
1763         string GetKindFromCaption (string s)
1764         {
1765                 int p = s.LastIndexOf (' ');
1766                 if (p > 0)
1767                         return s.Substring (p + 1);
1768                 return null;
1769         }
1770         
1771         //
1772         // Obtain an URL of the type T:System.Object from the node
1773         // 
1774         public static string GetNiceUrl (Node node) {
1775                 if (node.Element.StartsWith("N:"))
1776                         return node.Element;
1777                 string name, full;
1778                 int bk_pos = node.Caption.IndexOf (' ');
1779                 // node from an overview
1780                 if (bk_pos != -1) {
1781                         name = node.Caption.Substring (0, bk_pos);
1782                         full = node.Parent.Caption + "." + name.Replace ('.', '+');
1783                         return "T:" + full;
1784                 }
1785                 // node that lists constructors, methods, fields, ...
1786                 if ((node.Caption == "Constructors") || (node.Caption == "Fields") || (node.Caption == "Events") 
1787                         || (node.Caption == "Members") || (node.Caption == "Properties") || (node.Caption == "Methods")
1788                         || (node.Caption == "Operators")) {
1789                         bk_pos = node.Parent.Caption.IndexOf (' ');
1790                         name = node.Parent.Caption.Substring (0, bk_pos);
1791                         full = node.Parent.Parent.Caption + "." + name.Replace ('.', '+');
1792                         return "T:" + full + "/" + node.Element; 
1793                 }
1794                 int pr_pos = node.Caption.IndexOf ('(');
1795                 // node from a constructor
1796                 if (node.Parent.Element == "C") {
1797                         name = node.Parent.Parent.Parent.Caption;
1798                         int idx = node.URL.IndexOf ('/');
1799                         return node.URL[idx+1] + ":" + name + "." + node.Caption.Replace ('.', '+');
1800                 // node from a method with one signature, field, property, operator
1801                 } else if (pr_pos == -1) {
1802                         bk_pos = node.Parent.Parent.Caption.IndexOf (' ');
1803                         name = node.Parent.Parent.Caption.Substring (0, bk_pos);
1804                         full = node.Parent.Parent.Parent.Caption + "." + name.Replace ('.', '+');
1805                         int idx = node.URL.IndexOf ('/');
1806                         return node.URL[idx+1] + ":" + full + "." + node.Caption;
1807                 // node from a method with several signatures
1808                 } else {
1809                         bk_pos = node.Parent.Parent.Parent.Caption.IndexOf (' ');
1810                         name = node.Parent.Parent.Parent.Caption.Substring (0, bk_pos);
1811                         full = node.Parent.Parent.Parent.Parent.Caption + "." + name.Replace ('.', '+');
1812                         int idx = node.URL.IndexOf ('/');
1813                         return node.URL[idx+1] + ":" + full + "." + node.Caption;
1814                 }
1815         }
1816
1817         public override Stream GetImage (string url)
1818         {
1819                 if (url.Contains ("/"))
1820                         url = url.Substring (url.LastIndexOf ('/') + 1);
1821                 return GetHelpStream (url);
1822         }
1823                                 
1824         //
1825         // Populates the searchable index.
1826         //
1827         // The idea of this index is to capture the most common search terms, the UI for this
1828         // usually updates automatically as the user types.
1829         //
1830         public override void PopulateIndex (IndexMaker index_maker)
1831         {
1832                 foreach (Node ns_node in Tree.Nodes){
1833                         foreach (Node type_node in ns_node.Nodes){
1834                                 string typename = type_node.Caption.Substring (0, type_node.Caption.IndexOf (' '));
1835                                 string full = ns_node.Caption + "." + typename;
1836
1837                                 string doc_tag = GetKindFromCaption (type_node.Caption);
1838                                 string url = "T:" + full;
1839
1840
1841                                 //
1842                                 // Add MonoMac/MonoTouch [Export] attributes, those live only in classes
1843                                 //
1844                                 if (doc_tag == "Class" && (ns_node.Caption.StartsWith ("MonoTouch") || ns_node.Caption.StartsWith ("MonoMac"))){
1845                                         try {
1846                                                 string rest;
1847                                                 var xdoc = GetXmlFromUrl (type_node.URL, out rest);
1848                                                 if (xdoc != null){
1849                                                         var nodesWithExports = xdoc.SelectNodes ("/Type/Members/Member[contains (Attributes/Attribute/AttributeName, 'Foundation.Export') and (MemberType='Property' or MemberType='Method' or MemberType='Constructor')]");
1850                                                         
1851                                                         foreach (XmlNode n in nodesWithExports){
1852                                                                 string cref = EcmaDoc.GetCref ((XmlElement) n);
1853                                                                 
1854                                                                 var exports = n.SelectNodes ("Attributes/Attribute/AttributeName");
1855                                                                 foreach (XmlNode exportNode in exports){
1856                                                                         var inner = exportNode.InnerText;
1857                                                                         int p = inner.IndexOf ("Foundation.Export(\"");
1858                                                                         if (p == -1){
1859                                                                                 Console.WriteLine ("Not found the Export attribute in {0}", inner);
1860                                                                                 continue;
1861                                                                         }
1862                                                                         var pa = inner.IndexOf ("\"", p);
1863                                                                         if (pa == -1){
1864                                                                                 Console.WriteLine ("Export has no target in {0}", inner);
1865                                                                                 continue;
1866                                                                         }
1867                                                                         var end = inner.IndexOf ("\"", pa+1);
1868                                                                         
1869                                                                         var export = end == -1 ? inner.Substring (pa+1) : inner.Substring (pa+1, end-(pa+1));
1870
1871                                                                         index_maker.Add (export + " selector", export, cref);
1872                                                                 }
1873                                                         }
1874                                                 }
1875                                         } catch (Exception e){
1876                                                 Console.WriteLine ("Problem processing {0} for MonoTouch/MonoMac exports\n\n{0}", e);
1877                                         }
1878                                 }
1879
1880                                 if (doc_tag == "Class" || doc_tag == "Structure" || doc_tag == "Interface"){
1881
1882                                         index_maker.Add (type_node.Caption, typename, url);
1883                                         index_maker.Add (full + " " + doc_tag, full, url);
1884
1885                                         foreach (Node c in type_node.Nodes){
1886                                                 switch (c.Caption){
1887                                                 case "Constructors":
1888                                                         index_maker.Add ("  constructors", typename+"0", url + "/C");
1889                                                         break;
1890                                                 case "Fields":
1891                                                         index_maker.Add ("  fields", typename+"1", url + "/F");
1892                                                         break;
1893                                                 case "Events":
1894                                                         index_maker.Add ("  events", typename+"2", url + "/E");
1895                                                         break;
1896                                                 case "Properties":
1897                                                         index_maker.Add ("  properties", typename+"3", url + "/P");
1898                                                         break;
1899                                                 case "Methods":
1900                                                         index_maker.Add ("  methods", typename+"4", url + "/M");
1901                                                         break;
1902                                                 case "Operators":
1903                                                         index_maker.Add ("  operators", typename+"5", url + "/O");
1904                                                         break;
1905                                                 }
1906                                         }
1907
1908                                         //
1909                                         // Now repeat, but use a different sort key, to make sure we come after
1910                                         // the summary data above, start the counter at 6
1911                                         //
1912                                         string keybase = typename + "6.";
1913                                         
1914                                         foreach (Node c in type_node.Nodes){
1915                                                 switch (c.Caption){
1916                                                 case "Constructors":
1917                                                         break;
1918                                                 case "Fields":
1919                                                         foreach (Node nc in c.Nodes){
1920                                                                 string res = nc.Caption;
1921
1922                                                                 string nurl = String.Format ("F:{0}.{1}", full, res);
1923                                                                 index_maker.Add (String.Format ("{0}.{1} field", typename, res),
1924                                                                                  keybase + res, nurl);
1925                                                                 index_maker.Add (String.Format ("{0} field", res), res, nurl);
1926                                                         }
1927
1928                                                         break;
1929                                                 case "Events":
1930                                                         foreach (Node nc in c.Nodes){
1931                                                                 string res = nc.Caption;
1932                                                                 string nurl = String.Format ("E:{0}.{1}", full, res);
1933                                                                 
1934                                                                 index_maker.Add (String.Format ("{0}.{1} event", typename, res),
1935                                                                                  keybase + res, nurl);
1936                                                                 index_maker.Add (String.Format ("{0} event", res), res, nurl);
1937                                                         }
1938                                                         break;
1939                                                 case "Properties":
1940                                                         foreach (Node nc in c.Nodes){
1941                                                                 string res = nc.Caption;
1942                                                                 string nurl = String.Format ("P:{0}.{1}", full, res);
1943                                                                 index_maker.Add (String.Format ("{0}.{1} property", typename, res),
1944                                                                                  keybase + res, nurl);
1945                                                                 index_maker.Add (String.Format ("{0} property", res), res, nurl);
1946                                                         }
1947                                                         break;
1948                                                 case "Methods":
1949                                                         foreach (Node nc in c.Nodes){
1950                                                                 string res = nc.Caption;
1951                                                                 int p = res.IndexOf ("(");
1952                                                                 if (p > 0)
1953                                                                         res = res.Substring (0, p); 
1954                                                                 string nurl = String.Format ("M:{0}.{1}", full, res);
1955                                                                 index_maker.Add (String.Format ("{0}.{1} method", typename, res),
1956                                                                                  keybase + res, nurl);
1957                                                                 index_maker.Add (String.Format ("{0} method", res), res, nurl);
1958                                                         }
1959                                         
1960                                                         break;
1961                                                 case "Operators":
1962                                                         foreach (Node nc in c.Nodes){
1963                                                                 string res = nc.Caption;
1964                                                                 string nurl = String.Format ("O:{0}.{1}", full, res);
1965                                                                 index_maker.Add (String.Format ("{0}.{1} operator", typename, res),
1966                                                                                  keybase + res, nurl);
1967                                                         }
1968                                                         break;
1969                                                 }
1970                                         }
1971                                 } else if (doc_tag == "Enumeration"){
1972                                         //
1973                                         // Enumerations: add the enumeration values
1974                                         //
1975                                         index_maker.Add (type_node.Caption, typename, url);
1976                                         index_maker.Add (full + " " + doc_tag, full, url);
1977
1978                                         // Now, pull the values.
1979                                         string rest;
1980                                         XmlDocument x = GetXmlFromUrl (type_node.URL, out rest);
1981                                         if (x == null)
1982                                                 continue;
1983                                         
1984                                         XmlNodeList members = x.SelectNodes ("/Type/Members/Member");
1985
1986                                         if (members == null)
1987                                                 continue;
1988
1989                                         foreach (XmlNode member_node in members){
1990                                                 string enum_value = member_node.Attributes ["MemberName"].InnerText;
1991                                                 string caption = enum_value + " value";
1992                                                 index_maker.Add (caption, caption, url);
1993                                         }
1994                                 } else if (doc_tag == "Delegate"){
1995                                         index_maker.Add (type_node.Caption, typename, url);
1996                                         index_maker.Add (full + " " + doc_tag, full, url);
1997                                 }
1998                         }
1999                 }
2000         }
2001         //
2002         // Create list of documents for searching
2003         //
2004         public override void PopulateSearchableIndex (IndexWriter writer)
2005         {
2006                 StringBuilder text;
2007                 foreach (Node ns_node in Tree.Nodes) {
2008                         Message (TraceLevel.Info, "\tNamespace: {0} ({1})", ns_node.Caption, ns_node.Nodes.Count);
2009                         foreach (Node type_node in ns_node.Nodes) {
2010                                 string typename = type_node.Caption.Substring (0, type_node.Caption.IndexOf (' '));
2011                                 string full = ns_node.Caption + "." + typename;
2012                                 string doc_tag = GetKindFromCaption (type_node.Caption);
2013                                 string url = "T:" + full;
2014                                 string rest;
2015                                 XmlDocument xdoc = GetXmlFromUrl (type_node.URL, out rest);
2016                                 if (xdoc == null)
2017                                         continue;
2018                                 
2019                                 // 
2020                                 // For classes, structures or interfaces add a doc for the overview and
2021                                 // add a doc for every constructor, method, event, ...
2022                                 // 
2023                                 if (doc_tag == "Class" || doc_tag == "Structure" || doc_tag == "Interface"){
2024                                         
2025                                         // Adds a doc for every overview of every type
2026                                         SearchableDocument doc = new SearchableDocument ();
2027                                         doc.title = type_node.Caption;
2028                                         doc.hottext = typename;
2029                                         doc.url = url;
2030                                         doc.fulltitle = full;
2031                                         
2032                                         XmlNode node_sel = xdoc.SelectSingleNode ("/Type/Docs");
2033                                         text  = new StringBuilder ();
2034                                         GetTextFromNode (node_sel, text);
2035                                         doc.text = text.ToString ();
2036
2037                                         text  = new StringBuilder ();
2038                                         GetExamples (node_sel, text);
2039                                         doc.examples = text.ToString ();
2040                                         
2041                                         writer.AddDocument (doc.LuceneDoc);
2042                                         var exportParsable = doc_tag == "Class" && (ns_node.Caption.StartsWith ("MonoTouch") || ns_node.Caption.StartsWith ("MonoMac"));
2043
2044                                         //Add docs for contructors, methods, etc.
2045                                         foreach (Node c in type_node.Nodes) { // c = Constructors || Fields || Events || Properties || Methods || Operators
2046                                                 
2047                                                 if (c.Element == "*")
2048                                                         continue;
2049                                                 int i = 1;
2050                                                 const float innerTypeBoost = 0.2f;
2051
2052                                                 foreach (Node nc in c.Nodes) {
2053                                                         // Disable constructors indexing as it's often "polluting" search queries
2054                                                         // because it has the same hottext than standard types
2055                                                         if (c.Caption == "Constructors")
2056                                                                 continue;
2057                                                         //xpath to the docs xml node
2058                                                         string xpath;
2059                                                         if (c.Caption == "Constructors")
2060                                                                 xpath = String.Format ("/Type/Members/Member[{0}]/Docs", i++);
2061                                                         else if (c.Caption == "Operators")
2062                                                                 xpath = String.Format ("/Type/Members/Member[@MemberName='op_{0}']/Docs", nc.Caption);
2063                                                         else
2064                                                                 xpath = String.Format ("/Type/Members/Member[@MemberName='{0}']/Docs", nc.Caption);
2065                                                         //construct url of the form M:Array.Sort
2066                                                         string urlnc;
2067                                                         if (c.Caption == "Constructors")
2068                                                                 urlnc = String.Format ("{0}:{1}.{2}", c.Caption[0], ns_node.Caption, nc.Caption);
2069                                                         else
2070                                                                 urlnc = String.Format ("{0}:{1}.{2}.{3}", c.Caption[0], ns_node.Caption, typename, nc.Caption);
2071
2072                                                         //create the doc
2073                                                         SearchableDocument doc_nod = new SearchableDocument ();
2074                                                         doc_nod.title = LargeName (nc);
2075                                                         switch (c.Caption[0]) {
2076                                                         case 'M':
2077                                                                 doc_nod.title += " Method";
2078                                                                 break;
2079                                                         case 'P':
2080                                                                 doc_nod.title += " Property";
2081                                                                 break;
2082                                                         case 'E':
2083                                                                 doc_nod.title += " Event";
2084                                                                 break;
2085                                                         case 'O':
2086                                                                 doc_nod.title += " Operator";
2087                                                                 break;
2088                                                         default:
2089                                                                 break;
2090                                                         }
2091                                                         doc_nod.fulltitle = string.Format ("{0}.{1}::{2}", ns_node.Caption, typename, nc.Caption);
2092                                                         //dont add the parameters to the hottext
2093                                                         int ppos = nc.Caption.IndexOf ('(');
2094                                                         if (ppos != -1)
2095                                                                 doc_nod.hottext =  nc.Caption.Substring (0, ppos);
2096                                                         else
2097                                                                 doc_nod.hottext = nc.Caption;
2098
2099                                                         doc_nod.url = urlnc;
2100
2101                                                         XmlNode xmln = xdoc.SelectSingleNode (xpath);
2102                                                         if (xmln == null) {
2103                                                                 Error ("Problem: {0}, with xpath: {1}", urlnc, xpath);
2104                                                                 continue;
2105                                                         }
2106
2107                                                         text = new StringBuilder ();
2108                                                         GetTextFromNode (xmln, text);
2109                                                         doc_nod.text = text.ToString ();
2110
2111                                                         text = new StringBuilder ();
2112                                                         GetExamples (xmln, text);
2113                                                         doc_nod.examples = text.ToString ();
2114
2115                                                         Document lucene_doc = doc_nod.LuceneDoc;
2116                                                         lucene_doc.SetBoost (innerTypeBoost);
2117                                                         writer.AddDocument (lucene_doc);
2118
2119                                                         // MonoTouch/Monomac specific parsing of [Export] attributes
2120                                                         if (exportParsable) {
2121                                                                 try {
2122                                                                         var exports =
2123                                                                                 xdoc.SelectNodes (string.Format ("/Type/Members/Member[@MemberName='{0}']/Attributes/Attribute/AttributeName[contains(text(), 'Foundation.Export')]", nc.Caption));
2124                                                                         foreach (XmlNode exportNode in exports) {
2125                                                                                 var inner = exportNode.InnerText;
2126                                                                                 var parts = inner.Split ('"');
2127                                                                                 if (parts.Length != 3) {
2128                                                                                         Console.WriteLine ("Export attribute not found or not usable in {0}", inner);
2129                                                                                         continue;
2130                                                                                 }
2131                                                                                 
2132                                                                                 var export = parts[1];
2133                                                                                 var export_node = new SearchableDocument ();
2134                                                                                 export_node.title = export + " Export";
2135                                                                                 export_node.fulltitle = string.Format ("{0}.{1}::{2}", ns_node.Caption, typename, export);
2136                                                                                 export_node.url = urlnc;
2137                                                                                 export_node.hottext = export + ":";
2138                                                                                 export_node.text = string.Empty;
2139                                                                                 export_node.examples = string.Empty;
2140                                                                                 lucene_doc = export_node.LuceneDoc;
2141                                                                                 lucene_doc.SetBoost (innerTypeBoost);
2142                                                                                 writer.AddDocument (lucene_doc);
2143                                                                         }
2144                                                                 } catch (Exception e){
2145                                                                         Console.WriteLine ("Problem processing {0} for MonoTouch/MonoMac exports\n\n{0}", e);
2146                                                                 }
2147                                                         }
2148                                                 }
2149                                         }
2150                                 //
2151                                 // Enumerations: add the enumeration values
2152                                 //
2153                                 } else if (doc_tag == "Enumeration"){
2154                                                                                 
2155                                         XmlNodeList members = xdoc.SelectNodes ("/Type/Members/Member");
2156                                         if (members == null)
2157                                                 continue;
2158
2159                                         text = new StringBuilder ();
2160                                         foreach (XmlNode member_node in members) {
2161                                                 string enum_value = member_node.Attributes ["MemberName"].InnerText;
2162                                                 text.Append (enum_value);
2163                                                 text.Append (" ");
2164                                                 GetTextFromNode (member_node["Docs"], text);
2165                                                 text.Append ("\n");
2166                                         }
2167                                         SearchableDocument doc = new SearchableDocument ();
2168
2169                                         text = new StringBuilder ();
2170                                         GetExamples (xdoc.SelectSingleNode ("/Type/Docs"), text);
2171                                         doc.examples = text.ToString ();
2172
2173                                         doc.title = type_node.Caption;
2174                                         doc.hottext = xdoc.DocumentElement.Attributes["Name"].Value;
2175                                         doc.fulltitle = full;
2176                                         doc.url = url;
2177                                         doc.text = text.ToString();
2178                                         writer.AddDocument (doc.LuceneDoc);
2179                                 //
2180                                 // Add delegates
2181                                 //
2182                                 } else if (doc_tag == "Delegate"){
2183                                         SearchableDocument doc = new SearchableDocument ();
2184                                         doc.title = type_node.Caption;
2185                                         doc.hottext = xdoc.DocumentElement.Attributes["Name"].Value;
2186                                         doc.fulltitle = full;
2187                                         doc.url = url; 
2188                                         
2189                                         XmlNode node_sel = xdoc.SelectSingleNode ("/Type/Docs");
2190
2191                                         text = new StringBuilder ();
2192                                         GetTextFromNode (node_sel, text);
2193                                         doc.text = text.ToString();
2194
2195                                         text = new StringBuilder ();
2196                                         GetExamples (node_sel, text);
2197                                         doc.examples = text.ToString();
2198
2199                                         writer.AddDocument (doc.LuceneDoc);
2200                                 }
2201                         }
2202                 }
2203         }
2204         
2205         //
2206         // Extract the interesting text from the docs node
2207         //
2208         void GetTextFromNode (XmlNode n, StringBuilder sb) 
2209         {
2210                 //don't include example code
2211                 if (n.Name == "code") 
2212                         return;
2213
2214                 //include the url to which points the see tag
2215                 if (n.Name == "see" && n.Attributes.Count > 0)
2216                                 sb.Append (n.Attributes [0].Value);
2217                 
2218                 //include the name of the parameter
2219                 if (n.Name == "paramref" && n.Attributes.Count > 0)
2220                         sb.Append (n.Attributes [0].Value);
2221
2222                 //include the contents for the node that contains text
2223                 if (n.NodeType == XmlNodeType.Text)
2224                         sb.Append (n.Value);
2225                 
2226                 //add the rest of xml tags recursively
2227                 if (n.HasChildNodes)
2228                         foreach (XmlNode n_child in n.ChildNodes)
2229                                 GetTextFromNode (n_child, sb);
2230         }
2231         //
2232         // Extract the code nodes from the docs
2233         //
2234         void GetExamples (XmlNode n, StringBuilder sb)
2235         {
2236                 if (n.Name == "code") {
2237                         sb.Append (n.InnerText);
2238                 } else {
2239                         if (n.HasChildNodes)
2240                                 foreach (XmlNode n_child in n.ChildNodes)
2241                                         GetExamples (n_child, sb);
2242                 }
2243         }
2244         //
2245         // Extract a large name for the Node
2246         //  (copied from mono-tools/docbrowser/browser.Render()
2247         static string LargeName (Node matched_node)
2248         {
2249                 string[] parts = matched_node.URL.Split('/', '#');                      
2250                 if(parts.Length == 3 && parts[2] != String.Empty) { //List of Members, properties, events, ...
2251                         return parts[1] + ": " + matched_node.Caption;
2252                 } else if(parts.Length >= 4) { //Showing a concrete Member, property, ...                                       
2253                         return parts[1] + "." + matched_node.Caption;
2254                 } else {
2255                         return matched_node.Caption;
2256                 }
2257         }
2258
2259 }
2260
2261 public class EcmaUncompiledHelpSource : EcmaHelpSource {
2262         readonly DirectoryInfo basedir;
2263         readonly XmlDocument basedoc;
2264         
2265         public new readonly string Name;
2266         public     readonly string BasePath;
2267         
2268         public EcmaUncompiledHelpSource (string base_file) : base ()
2269         {
2270                 Message (TraceLevel.Info, "Loading uncompiled help from " + base_file);
2271                 
2272                 basedir = new DirectoryInfo(base_file);
2273                 BasePath = basedir.FullName;
2274                 
2275                 basedoc = new XmlDocument();
2276                 basedoc.Load(Path.Combine(basedir.FullName, "index.xml"));
2277                 
2278                 Name = basedoc.SelectSingleNode("Overview/Title").InnerText;
2279                 
2280                 bool has_content = false;
2281                 
2282                 foreach (XmlElement ns in basedoc.SelectNodes("Overview/Types/Namespace")) {
2283                         has_content = true;
2284                         Node nsnode = Tree.CreateNode(ns.GetAttribute("Name"), "N:" + ns.GetAttribute("Name"));
2285                         
2286                         bool has_types = false;
2287                         foreach (XmlElement t in ns.SelectNodes("Type")) {
2288                                 has_types = true;
2289                                 string typename = EcmaDoc.GetDisplayName (t).Replace("+", ".");
2290                                 
2291                                 // Must load in each document to get the list of members...
2292                                 XmlDocument typedoc = new XmlDocument();
2293                                 typedoc.Load(Path.Combine(Path.Combine(basedir.FullName, ns.GetAttribute("Name")), t.GetAttribute("Name") + ".xml"));
2294                                 string kind = EcmaDoc.GetTypeKind (typedoc);
2295                                 
2296                                 string url = ns.GetAttribute("Name") + "." + t.GetAttribute("Name");
2297                                 Node typenode = nsnode.CreateNode(typename + " " + kind, "T:" + url);                           
2298                                 //Node typemembers = typenode.CreateNode("Members", "T:" + url + "/*");
2299                                 
2300                                 Hashtable groups = new Hashtable();
2301                                 Hashtable groups_count = new Hashtable();
2302                                 foreach (XmlElement member in typedoc.SelectNodes("Type/Members/Member")) {
2303                                         string membername = member.GetAttribute("MemberName");
2304                                         string membertype = member.SelectSingleNode("MemberType").InnerText;
2305                                         
2306                                         if (membertype == "Constructor")
2307                                                 membername = t.GetAttribute("Name");
2308                                         if (membername.StartsWith("op_"))
2309                                                 membertype = "Operator";
2310                                         
2311                                         Node group;
2312                                         if (groups.ContainsKey(membertype)) {
2313                                                 group = (Node)groups[membertype];
2314                                         } else {
2315                                                 string membertypeplural = membertype + "s";
2316                                                 if (membertypeplural == "Propertys") membertypeplural = "Properties";
2317                                                 
2318                                                 group = typenode.CreateNode(membertypeplural, "T:" + url + "/" + membertype[0]);
2319                                                 groups[membertype] = group;
2320                                                 groups_count[membertype] = 0;
2321                                         }
2322                                         
2323                                         if (membertype == "Constructor" || membertype == "Method" || 
2324                                                 (membertype == "Property" && member.SelectNodes("Parameters/Parameter").Count > 0)) {
2325                                                 membername = EcmaHelpSource.MakeSignature(member, membertype == "Constructor" ? membername : null);
2326                                         } else if (membertype == "Operator") {
2327                                                 string dummy;
2328                                                 EcmaHelpSource.MakeOperatorSignature(member, out dummy, out membername);
2329                                         }
2330                                         
2331                                         int index = (int)groups_count[membertype];
2332                                         groups_count[membertype] = index + 1;
2333                                         
2334                                         group.CreateNode(membername, index.ToString());
2335                                 }
2336
2337                                 foreach (Node group in groups.Values)
2338                                         group.Sort();                   
2339                         }
2340                         
2341                         if (has_types)
2342                                 nsnode.Sort();
2343                 }
2344                 
2345                 if (has_content)
2346                         Tree.Sort();
2347         }
2348         
2349         public override string GetIdFromUrl (string prefix, string ns, string type)
2350         {
2351                 if (prefix != "T:")
2352                         throw new NotImplementedException();
2353                 return Path.Combine(Path.Combine(basedir.FullName, ns), type + ".xml");
2354         }
2355
2356         protected override XmlDocument GetXmlFromUrl(string url, out string rest) {
2357                 // strip off the T:
2358                 url = url.Substring(2);
2359                 
2360                 int sidx = url.IndexOf("/");
2361                 if (sidx == -1) {
2362                         rest = "";
2363                 } else {
2364                         rest = url.Substring(sidx+1);
2365                         url = url.Substring(0, sidx);
2366                 }
2367                 
2368                 string ns, type;
2369                 if (!RootTree.GetNamespaceAndType (url, out ns, out type)) {
2370                         Message (TraceLevel.Error, "Could not determine namespace/type for {0}", url);
2371                         return null;
2372                 }
2373                 
2374                 string file = Path.Combine(Path.Combine(basedir.FullName, ns), 
2375                                 ToEscapedTypeName (type).Replace ('.', '+') + ".xml");
2376                 if (!new FileInfo(file).Exists) return null;
2377                 
2378                 XmlDocument typedoc = new XmlDocument();
2379                 typedoc.Load(file);
2380                 return typedoc;
2381         }
2382         
2383         public override string GetText (string url, out Node match_node) {
2384                 if (url == "root:") {
2385                         match_node = null;
2386                         
2387                         //load index.xml
2388                         XmlDocument index = new XmlDocument ();
2389                         index.Load (Path.Combine (basedir.FullName, "index.xml"));
2390                         XmlNodeList nodes = index.SelectNodes ("/Overview/Types/Namespace");
2391                         
2392                         //recreate masteroverview.xml
2393                         XmlDocument summary = new XmlDocument ();
2394                         XmlElement elements = summary.CreateElement ("elements");
2395                         foreach (XmlNode node in nodes) {
2396                                 XmlElement ns = summary.CreateElement ("namespace");
2397                                 XmlAttribute attr = summary.CreateAttribute ("ns");
2398                                 attr.Value = EcmaDoc.GetDisplayName (node);
2399                                 ns.Attributes.Append (attr);
2400                                 elements.AppendChild (ns);
2401                         }
2402                         summary.AppendChild (elements);
2403
2404                         XmlReader reader = new XmlTextReader (new StringReader (summary.OuterXml));
2405
2406                         //transform the recently created masteroverview.xml
2407                         XsltArgumentList args = new XsltArgumentList();
2408                         args.AddExtensionObject("monodoc:///extensions", ExtObject);
2409                         args.AddParam("show", "", "masteroverview");
2410                         string s = Htmlize(reader, args);
2411                         return BuildHtml (css_ecma_code, js_code, s); 
2412                 }
2413                 return base.GetText(url, out match_node);
2414         }
2415         
2416         protected override XmlDocument GetNamespaceDocument (string ns)
2417         {
2418                 XmlDocument nsdoc = new XmlDocument();
2419                 nsdoc.Load (EcmaDoc.GetNamespaceFile (basedir.FullName, ns));
2420                 
2421                 XmlDocument elements = new XmlDocument();
2422                 XmlElement docnode = elements.CreateElement("elements");
2423                 elements.AppendChild (docnode);
2424                 
2425                 foreach (XmlElement doc in nsdoc.SelectNodes("Namespace/Docs/*")) {
2426                         docnode.AppendChild(elements.ImportNode(doc, true));
2427                 }
2428                                 
2429                 foreach (XmlElement t in basedoc.SelectNodes("Overview/Types/Namespace[@Name='" + ns + "']/Type")) {
2430                         XmlDocument typedoc = new XmlDocument();
2431                         typedoc.Load(Path.Combine(Path.Combine(basedir.FullName, ns), t.GetAttribute("Name") + ".xml"));
2432                         
2433                         string typekind;
2434                         switch (EcmaDoc.GetTypeKind(typedoc)) {
2435                         case "Class": typekind = "class"; break;
2436                         case "Enumeration": typekind = "enum"; break;
2437                         case "Structure": typekind = "struct"; break;
2438                         case "Delegate": typekind = "delegate"; break;
2439                         case "Interface": typekind = "interface"; break;
2440                         default: throw new InvalidOperationException();
2441                         }
2442                         
2443                         XmlElement typenode = elements.CreateElement(typekind);
2444                         typenode.SetAttribute("name", EcmaDoc.GetDisplayName (t).Replace ('+', '.'));
2445                         typenode.SetAttribute("fullname", ns + "." + t.GetAttribute("Name"));
2446                         typenode.AppendChild(elements.ImportNode(typedoc.SelectSingleNode("Type/Docs/summary"), true));
2447                         
2448                         docnode.AppendChild(typenode);
2449                 }
2450
2451                 return elements;
2452         }
2453         
2454         public override Stream GetHelpStream (string id)
2455         {
2456                 if (id == "ExtensionMethods.xml") {
2457                         // TODO: generate ExtensionMethods.xml based on index.xml contents.
2458                 }
2459                 return null;
2460         }
2461
2462         public override XmlDocument GetHelpXmlWithChanges (string id)
2463         {
2464                 XmlDocument doc = new XmlDocument ();
2465                 doc.Load (id);
2466                 return doc;
2467         }
2468
2469         public virtual Stream GetImage (string url)
2470         {
2471                 string path = EcmaDoc.GetImageFile (basedir.FullName, url);
2472                 if (path == null)
2473                         return null;
2474                 return File.OpenRead (path);
2475         }
2476         
2477         class UncompiledResolver : XmlResolver {
2478                 public override Uri ResolveUri (Uri baseUri, string relativeUri)
2479                 {
2480                         return null;
2481                 }
2482
2483                 public override object GetEntity (Uri absoluteUri, string role, Type ofObjectToReturn)
2484                 {
2485                         return null;
2486                 }
2487
2488                 public override System.Net.ICredentials Credentials {
2489                         set {/* ignore */}
2490                 }
2491         }
2492
2493         protected override XmlResolver CreateDocumentResolver ()
2494         {
2495                 return new UncompiledResolver ();
2496         }
2497 }
2498
2499 }
2500
2501