Merge pull request #347 from JamesB7/master
[mono.git] / mcs / class / System.Web / System.Web.Configuration_2.0 / nBrowser / Build.cs
1 #if NET_2_0
2 /*
3 Used to determine Browser Capabilities by the Browsers UserAgent String and related
4 Browser supplied Headers.
5 Copyright (C) 2002-Present  Owen Brady (Ocean at owenbrady dot net) 
6 and Dean Brettle (dean at brettle dot com)
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy 
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights 
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
12 copies of the Software, and to permit persons to whom the Software is furnished
13 to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all 
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
19 INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
20 PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
21 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
22 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
23 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26 namespace System.Web.Configuration.nBrowser
27 {
28         using System;
29         using System.Collections.Generic;
30         using System.Text;
31         internal class Build : System.Web.Configuration.CapabilitiesBuild
32         {
33                 //This keeps a list of filenames and FileNodes linked
34                 private System.Collections.Generic.Dictionary<string, System.Web.Configuration.nBrowser.File> Browserfiles;
35
36                 //Just links FileNodes
37                 private System.Collections.Generic.List<System.Web.Configuration.nBrowser.File> nbrowserfiles;
38
39                 //
40                 private System.Collections.Generic.Dictionary<string, string> DefaultKeys;
41                 private System.Collections.Generic.Dictionary<string, string> BrowserKeys;
42
43                 //
44                 private object browserSyncRoot = new object();
45                 private System.Web.Configuration.nBrowser.Node browser;
46
47                 /// <summary>
48                 /// 
49                 /// </summary>
50                 public Build()
51                         : base()
52                 {
53                         Browserfiles = new System.Collections.Generic.Dictionary<string, System.Web.Configuration.nBrowser.File>();
54                         nbrowserfiles = new System.Collections.Generic.List<System.Web.Configuration.nBrowser.File>();
55
56                         DefaultKeys = new System.Collections.Generic.Dictionary<string, string>();
57                         BrowserKeys = new System.Collections.Generic.Dictionary<string, string>();
58                 }
59                 /// <summary>
60                 /// Reads an entire directory and process's all of the browser files in that
61                 /// directory.
62                 /// </summary>
63                 /// <param name="path"></param>
64                 public void AddBrowserDirectory(string path)
65                 {
66                         //I allow this function to be a little messy
67                         //just in case they pass in a path that really a file
68                         //name
69                         if (System.IO.Directory.Exists(path) == true)
70                         {
71                                 System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(path);
72                                 System.IO.FileInfo[] file = dir.GetFiles("*.browser");
73                                 //we are done with it so let the GC have it early as possible
74                                 dir = null;
75                                 for (int a = 0;a <= file.Length - 1;a++)
76                                 {
77                                         AddBrowserFile(file[a].FullName);
78                                 }
79                         }
80                         else if (System.IO.File.Exists(path) == true)
81                         {
82                                 AddBrowserFile(path);
83                         }
84                 }
85                 /// <summary>
86                 /// Reads a browser file and builds the Nodes which that file contains.
87                 /// </summary>
88                 /// <param name="filename"></param>
89                 public void AddBrowserFile(string fileName)
90                 {
91                         if (Browserfiles.ContainsKey(fileName) == false)
92                         {
93                                 nBrowser.File b = new nBrowser.File(fileName);
94                                 this.AddBrowserFile(b);
95                         }
96
97                 }
98                 private void AddBrowserFile(nBrowser.File file)
99                 {
100                         if (Browserfiles.ContainsKey(file.FileName) == false)
101                         {
102                                 Browserfiles.Add(file.FileName, file);
103                                 nbrowserfiles.Add(file);
104
105                                 string[] keys = file.Keys;
106                                 for (int i = 0;i <= keys.Length - 1;i++)
107                                 {
108                                         if (BrowserKeys.ContainsKey(keys[i]) == false)
109                                         {
110                                                 BrowserKeys.Add(keys[i], file.FileName);
111                                         }
112                                         else
113                                         {
114                                                 throw new nBrowser.Exception("Duplicate Key \"" + keys[i] + "\" found in " + file.FileName + " and in file " + BrowserKeys[keys[i]]);
115                                         }
116                                 }
117                                 keys = file.DefaultKeys;
118                                 for (int i = 0;i <= keys.Length - 1;i++)
119                                 {
120                                         if (DefaultKeys.ContainsKey(keys[i]) == false)
121                                         {
122                                                 DefaultKeys.Add(keys[i], file.FileName);
123                                         }
124                                         else
125                                         {
126                                                 throw new nBrowser.Exception("Duplicate Key \"" + keys[i] + "\" found in " + file.FileName + " and in file " + DefaultKeys[keys[i]]);
127                                         }
128                                 }
129                         }
130                 }
131                 /// <summary>
132                 /// Reads a browser file and builds the Nodes which that file contains.
133                 /// </summary>
134                 /// <param name="file"></param>
135                 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1059")]
136                 public void AddBrowserFile(System.Xml.XmlDocument browser, string fileName)
137                 {
138                         if (Browserfiles.ContainsKey(fileName) == false)
139                         {
140                                 nBrowser.File file = new nBrowser.File(browser, fileName);
141                                 this.AddBrowserFile(file);
142                         }
143                 }
144                 /// <summary>
145                 /// Returns the root Node of the Browser Tree.
146                 /// </summary>
147                 /// <returns></returns>
148                 public Node Browser()
149                 {
150                         if (browser == null)
151                         {
152                                 lock (browserSyncRoot)
153                                 {
154                                         if (browser == null)
155                                         {
156                                                 browser = InitializeTree();
157                                         }
158                                 }
159                         }
160                         return browser;
161                 }
162
163                 private Node InitializeTree()
164                 {
165                         Node root = new Node();
166                         //Custom Sorted List, to allow where Multple files in Diff directorys might have the same
167                         //filename. So still to some degree first come first serve but might be close enough
168                         //to how microsoft System to match much more closely.
169                         System.Collections.Generic.SortedList<string, System.Collections.Generic.List<nBrowser.File>> list;
170                         list = new System.Collections.Generic.SortedList<string, System.Collections.Generic.List<nBrowser.File>>();
171
172                         for (int i = 0;i <= Browserfiles.Count - 1;i++)
173                         {
174                                 if (list.ContainsKey(nbrowserfiles[i].FileName) == false)
175                                 {
176                                         System.Collections.Generic.List<nBrowser.File> l;
177                                         l = new System.Collections.Generic.List<nBrowser.File>();
178                                         list.Add(nbrowserfiles[i].FileName, l);
179                                 }
180                                 list[nbrowserfiles[i].FileName].Add(nbrowserfiles[i]);
181                         }
182                         nBrowser.File[] files = new nBrowser.File[Browserfiles.Count];
183
184                         int count = 0;
185                         for (int i = 0;i <= list.Count - 1;i++)
186                         {
187                                 System.Collections.Generic.List<nBrowser.File> l = list[list.Keys[i]];
188                                 for (int b = 0;b <= l.Count - 1;b++)
189                                 {
190                                         files[count] = l[b];
191                                         count++;
192                                 }
193                         }
194
195                         #region Connect Nodes
196                         for (int i = 0;i <= Browserfiles.Count - 1;i++)
197                         {
198                                 for (int a = 0;a <= files[i].Keys.Length - 1;a++)
199                                 {
200                                         Node child = files[i].GetNode(files[i].Keys[a]);
201                                         Node parent = null;
202                                         if (child.ParentId.Length > 0)
203                                         {
204                                                 parent = this.GetNode(child.ParentId);
205                                                 if (parent == null)
206                                                         throw new nBrowser.Exception(String.Format("Parent not found with id = {0}", child.ParentId));
207                                         }
208                                         if (parent == null)
209                                                 parent = root;
210                                         parent.AddChild(child);
211                                 }
212                         }
213                         #endregion
214                         
215                         #region Inject DefaultBrowser Nodes
216                         for (int i = 0;i <= Browserfiles.Count - 1;i++)
217                         {
218                                 for (int a = 0;a <= files[i].DefaultKeys.Length - 1;a++)
219                                 {
220                                         Node defaultNode = files[i].GetDefaultNode(files[i].DefaultKeys[a]);
221                                         Node node = this.GetNode(defaultNode.Id);
222                                         if (node == defaultNode) 
223                                         {
224                                                 // there is no regular node so the defaultNode is already at
225                                                 // the correct spot in the tree.
226                                                 continue;
227                                         }
228                                         Node parentNode = this.GetNode(node.ParentId);
229                                         if (parentNode == null)
230                                                 parentNode = root;
231                                         // insert the default node between the regular node and it's parent.
232                                         parentNode.RemoveChild(node);
233                                         defaultNode.AddChild(node);
234                                         parentNode.AddChild(defaultNode);
235                                 }
236                         }
237                         #endregion
238
239                         #region Merge Ref Nodes
240                         for (int i = 0;i <= Browserfiles.Count - 1;i++)
241                         {
242                                 foreach (Node refNode in files[i].RefNodes) {
243                                         GetNode(refNode.RefId).MergeFrom(refNode);
244                                 }
245                         }
246                         #endregion
247
248                         return root;
249                 }
250                                                 
251                 /// <summary>
252                 /// returns a Node Matching the Key supplied, for either a 
253                 /// DefaultBrowser, or Gatway/Browser node.
254                 /// </summary>
255                 /// <param name="Key"></param>
256                 /// <returns></returns>
257                 private Node GetNode(string Key)
258                 {
259                         if (Key == null || Key.Length == 0)
260                                 return null;
261                                 
262                         string filename;
263                         //Must find what file node that this key is located in
264                         //so we look it up in the string dictionary's
265                         if (!BrowserKeys.TryGetValue(Key, out filename)
266                                 && !DefaultKeys.TryGetValue(Key, out filename))
267                                 return null;
268                                 
269                         //fxcop sugguested this was faster then
270                         //filename!= string.Empty
271                         if (filename != null && filename.Length > 0)
272                         {
273                                 //now that we have a name we look it up in the hasttable containing
274                                 //the actual node.
275                                 nBrowser.File b = Browserfiles[filename];
276                                 Node n = b.GetNode(Key);
277                                 return n;
278                         }
279
280                         return null;                    
281                 }
282                 
283                 /// <summary>
284                 /// Returns an Array of Nodes that have been built. To be used for Design/Editors of Browser
285                 /// files.
286                 /// </summary>
287                 /// <returns></returns>
288                 public Node[] Nodes()
289                 {
290                         Node[] browsers;
291                         nBrowser.File[] files = new nBrowser.File[Browserfiles.Count];
292                         Browserfiles.Values.CopyTo(files, 0);
293                         int count = 0;
294                         for (int i = 0;i <= files.Length - 1;i++)
295                         {
296                                 count += files[i].Nodes.Length;
297                         }
298                         browsers = new Node[count];
299                         count = 0;
300                         for (int i = 0;i <= files.Length - 1;i++)
301                         {
302                                 for (int a = 0;a <= files[i].Nodes.Length - 1;a++)
303                                 {
304                                         browsers[count] = files[i].Nodes[a];
305                                         count++;
306                                 }
307                         }
308                         return browsers;
309                 }
310                 /// <summary>
311                 /// 
312                 /// </summary>
313                 /// <param name="header"></param>
314                 /// <param name="initialCapabilities"></param>
315                 /// <returns></returns>
316                 public override System.Web.Configuration.CapabilitiesResult Process(System.Collections.Specialized.NameValueCollection header, System.Collections.IDictionary initialCapabilities)
317                 {
318                         if (initialCapabilities == null)
319                                 initialCapabilities = new System.Collections.Generic.Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
320                         System.Web.Configuration.nBrowser.Result r = new System.Web.Configuration.nBrowser.Result(initialCapabilities);
321
322 #if trace
323                         System.Diagnostics.Trace.WriteLine(string.Join("+", new string[50]));
324                         for (int i=0;i <= header.Count -1;i++)
325                         {
326                                 System.Diagnostics.Trace.WriteLine(string.Format("{0}{1}",header.GetKey(i).PadRight(25),header[i]));
327                         }
328                         System.Diagnostics.Trace.WriteLine(string.Join("+", new string[50]));
329 #endif                  
330                         Browser().Process(header, r, new System.Collections.Generic.List<System.Text.RegularExpressions.Match>());
331                         return r;
332                 }
333                 /// <summary>
334                 /// 
335                 /// </summary>
336                 /// <param name="list"></param>
337                 /// <returns></returns>
338                 protected override System.Collections.ObjectModel.Collection<string> HeaderNames(System.Collections.ObjectModel.Collection<string> list)
339                 {
340                         return this.Browser().HeaderNames(list);
341                 }
342         }
343 }
344 #endif