In corlib/System.Runtime.InteropServices:
[mono.git] / mcs / class / Microsoft.Build.Engine / Microsoft.Build.BuildEngine / Project.cs
1 //
2 // Project.cs: Project class
3 //
4 // Author:
5 //   Marek Sieradzki (marek.sieradzki@gmail.com)
6 //
7 // (C) 2005 Marek Sieradzki
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
28 #if NET_2_0
29
30 using System;
31 using System.Collections;
32 using System.Collections.Generic;
33 using System.Collections.Specialized;
34 using System.IO;
35 using System.Text;
36 using System.Xml;
37 using System.Xml.Schema;
38 using Microsoft.Build.Framework;
39 using Mono.XBuild.Framework;
40
41 namespace Microsoft.Build.BuildEngine {
42         public class Project {
43         
44                 bool                            buildEnabled;
45                 Dictionary <string, List <string>>      conditionedProperties;
46                 string[]                        defaultTargets;
47                 Encoding                        encoding;
48                 BuildItemGroup                  evaluatedItems;
49                 BuildItemGroup                  evaluatedItemsIgnoringCondition;
50                 Dictionary <string, BuildItemGroup>     evaluatedItemsByName;
51                 Dictionary <string, BuildItemGroup>     evaluatedItemsByNameIgnoringCondition;
52                 BuildPropertyGroup              evaluatedProperties;
53                 string                          firstTargetName;
54                 string                          fullFileName;
55                 BuildPropertyGroup              globalProperties;
56                 GroupingCollection              groupingCollection;
57                 bool                            isDirty;
58                 bool                            isValidated;
59                 BuildItemGroupCollection        itemGroups;
60                 ImportCollection                imports;
61                 string                          initialTargets;
62                 Dictionary <string, BuildItemGroup> last_item_group_containing;
63                 bool                            needToReevaluate;
64                 Engine                          parentEngine;
65                 BuildPropertyGroupCollection    propertyGroups;
66                 string                          schemaFile;
67                 TaskDatabase                    taskDatabase;
68                 TargetCollection                targets;
69                 DateTime                        timeOfLastDirty;
70                 UsingTaskCollection             usingTasks;
71                 XmlDocument                     xmlDocument;
72                 bool                            unloaded;
73
74                 static XmlNamespaceManager      manager;
75                 static string ns = "http://schemas.microsoft.com/developer/msbuild/2003";
76
77                 public Project ()
78                         : this (Engine.GlobalEngine)
79                 {
80                 }
81
82                 public Project (Engine engine)
83                 {
84                         parentEngine  = engine;
85
86                         buildEnabled = ParentEngine.BuildEnabled;
87                         xmlDocument = new XmlDocument ();
88                         xmlDocument.PreserveWhitespace = false;
89                         xmlDocument.AppendChild (xmlDocument.CreateElement ("Project", XmlNamespace));
90                         xmlDocument.DocumentElement.SetAttribute ("xmlns", ns);
91                         
92                         fullFileName = String.Empty;
93
94                         globalProperties = new BuildPropertyGroup (null, this, null, false);
95                         foreach (BuildProperty bp in parentEngine.GlobalProperties)
96                                 GlobalProperties.AddProperty (bp.Clone (true));
97                         
98                         ProcessXml ();
99                 }
100
101                 [MonoTODO ("Not tested")]
102                 public void AddNewImport (string importLocation,
103                                           string importCondition)
104                 {
105                         if (importLocation == null)
106                                 throw new ArgumentNullException ("importLocation");
107
108                         XmlElement importElement = xmlDocument.CreateElement ("Import", XmlNamespace);
109                         xmlDocument.DocumentElement.AppendChild (importElement);
110                         importElement.SetAttribute ("Project", importLocation);
111                         if (!String.IsNullOrEmpty (importCondition))
112                                 importElement.SetAttribute ("Condition", importCondition);
113
114                         Import import = new Import (importElement, this, null);
115                         imports.Add (import);
116                         MarkProjectAsDirty ();
117                         NeedToReevaluate ();
118                 }
119
120                 public BuildItem AddNewItem (string itemName,
121                                              string itemInclude)
122                 {
123                         return AddNewItem (itemName, itemInclude, false);
124                 }
125                 
126                 [MonoTODO ("Adds item not in the same place as MS")]
127                 public BuildItem AddNewItem (string itemName,
128                                              string itemInclude,
129                                              bool treatItemIncludeAsLiteral)
130                 {
131                         BuildItemGroup big;
132
133                         if (itemGroups.Count == 0)
134                                 big = AddNewItemGroup ();
135                         else {
136                                 if (last_item_group_containing.ContainsKey (itemName)) {
137                                         big = last_item_group_containing [itemName];
138                                 } else {
139                                         // FIXME: not tested
140                                         BuildItemGroup [] groups = new BuildItemGroup [itemGroups.Count];
141                                         itemGroups.CopyTo (groups, 0);
142                                         big = groups [0];
143                                 }
144                         }
145
146                         BuildItem item = big.AddNewItem (itemName, itemInclude, treatItemIncludeAsLiteral);
147                                 
148                         MarkProjectAsDirty ();
149                         NeedToReevaluate ();
150
151                         return item;
152                 }
153
154                 [MonoTODO ("Not tested")]
155                 public BuildItemGroup AddNewItemGroup ()
156                 {
157                         XmlElement element = xmlDocument.CreateElement ("ItemGroup", XmlNamespace);
158                         xmlDocument.DocumentElement.AppendChild (element);
159
160                         BuildItemGroup big = new BuildItemGroup (element, this, null, false);
161                         itemGroups.Add (big);
162                         MarkProjectAsDirty ();
163                         NeedToReevaluate ();
164
165                         return big;
166                 }
167
168                 [MonoTODO ("Ignores insertAtEndOfProject")]
169                 public BuildPropertyGroup AddNewPropertyGroup (bool insertAtEndOfProject)
170                 {
171                         XmlElement element = xmlDocument.CreateElement ("PropertyGroup", XmlNamespace);
172                         xmlDocument.DocumentElement.AppendChild (element);
173
174                         BuildPropertyGroup bpg = new BuildPropertyGroup (element, this, null, false);
175                         propertyGroups.Add (bpg);
176                         MarkProjectAsDirty ();
177                         NeedToReevaluate ();
178
179                         return bpg;
180                 }
181                 
182                 [MonoTODO ("Not tested, isn't added to TaskDatabase (no reevaluation)")]
183                 public void AddNewUsingTaskFromAssemblyFile (string taskName,
184                                                              string assemblyFile)
185                 {
186                         if (taskName == null)
187                                 throw new ArgumentNullException ("taskName");
188                         if (assemblyFile == null)
189                                 throw new ArgumentNullException ("assemblyFile");
190
191                         XmlElement element = xmlDocument.CreateElement ("UsingTask", XmlNamespace);
192                         xmlDocument.DocumentElement.AppendChild (element);
193                         element.SetAttribute ("TaskName", taskName);
194                         element.SetAttribute ("AssemblyFile", assemblyFile);
195
196                         UsingTask ut = new UsingTask (element, this, null);
197                         usingTasks.Add (ut);
198                         MarkProjectAsDirty ();
199                 }
200                 
201                 [MonoTODO ("Not tested, isn't added to TaskDatabase (no reevaluation)")]
202                 public void AddNewUsingTaskFromAssemblyName (string taskName,
203                                                              string assemblyName)
204                 {
205                         if (taskName == null)
206                                 throw new ArgumentNullException ("taskName");
207                         if (assemblyName == null)
208                                 throw new ArgumentNullException ("assemblyName");
209
210                         XmlElement element = xmlDocument.CreateElement ("UsingTask", XmlNamespace);
211                         xmlDocument.DocumentElement.AppendChild (element);
212                         element.SetAttribute ("TaskName", taskName);
213                         element.SetAttribute ("AssemblyName", assemblyName);
214
215                         UsingTask ut = new UsingTask (element, this, null);
216                         usingTasks.Add (ut);
217                         MarkProjectAsDirty ();
218                 }
219                 
220                 [MonoTODO ("Not tested")]
221                 public bool Build ()
222                 {
223                         return Build (new string [0]);
224                 }
225                 
226                 [MonoTODO ("Not tested")]
227                 public bool Build (string targetName)
228                 {
229                         return Build (new string [1] { targetName });
230                 }
231                 
232                 [MonoTODO ("Not tested")]
233                 public bool Build (string [] targetNames)
234                 {
235                         return Build (targetNames, null);
236                 }
237                 
238                 [MonoTODO ("Not tested")]
239                 public bool Build (string [] targetNames,
240                                    IDictionary targetOutputs)
241                 {
242                         return Build (targetNames, targetOutputs, BuildSettings.None);
243                 }
244                 
245                 [MonoTODO ("Not tested")]
246                 public bool Build (string [] targetNames,
247                                    IDictionary targetOutputs,
248                                    BuildSettings buildFlags)
249                 
250                 {
251                         CheckUnloaded ();
252                         ParentEngine.StartBuild ();
253                         NeedToReevaluate ();
254                         
255                         if (targetNames.Length == 0) {
256                                 if (defaultTargets != null && defaultTargets.Length != 0)
257                                         targetNames = defaultTargets;
258                                 else if (firstTargetName != null)
259                                         targetNames = new string [1] { firstTargetName};
260                                 else
261                                         return false;
262                         }
263                         
264                         foreach (string target in targetNames) {
265                                 if (!targets.Exists (target))
266                                         // FIXME: test if it's logged
267                                         return false;
268                                 
269                                 if (!targets [target].Build ())
270                                         return false;
271
272                                 if (targetOutputs != null)
273                                         targetOutputs.Add (target, targets [target].Outputs);
274                         }
275                                 
276                         return true;
277                 }
278
279                 [MonoTODO]
280                 public string [] GetConditionedPropertyValues (string propertyName)
281                 {
282                         if (conditionedProperties.ContainsKey (propertyName))
283                                 return conditionedProperties [propertyName].ToArray ();
284                         else
285                                 return new string [0];
286                 }
287
288                 public BuildItemGroup GetEvaluatedItemsByName (string itemName)
289                 {                       
290                         if (needToReevaluate) {
291                                 needToReevaluate = false;
292                                 Reevaluate ();
293                         }
294
295                         if (evaluatedItemsByName.ContainsKey (itemName))
296                                 return evaluatedItemsByName [itemName];
297                         else
298                                 return new BuildItemGroup ();
299                 }
300
301                 public BuildItemGroup GetEvaluatedItemsByNameIgnoringCondition (string itemName)
302                 {
303                         if (needToReevaluate) {
304                                 needToReevaluate = false;
305                                 Reevaluate ();
306                         }
307
308                         if (evaluatedItemsByNameIgnoringCondition.ContainsKey (itemName))
309                                 return evaluatedItemsByNameIgnoringCondition [itemName];
310                         else
311                                 return new BuildItemGroup ();
312                 }
313
314                 public string GetEvaluatedProperty (string propertyName)
315                 {
316                         if (needToReevaluate) {
317                                 needToReevaluate = false;
318                                 Reevaluate ();
319                         }
320
321                         if (propertyName == null)
322                                 throw new ArgumentNullException ("propertyName");
323
324                         BuildProperty bp = evaluatedProperties [propertyName];
325
326                         return bp == null ? null : (string) bp;
327                 }
328
329                 [MonoTODO ("We should remember that node and not use XPath to get it")]
330                 public string GetProjectExtensions (string id)
331                 {
332                         if (id == null || id == String.Empty)
333                                 return String.Empty;
334
335                         XmlNode node = xmlDocument.SelectSingleNode (String.Format ("/tns:Project/tns:ProjectExtensions/tns:{0}", id), XmlNamespaceManager);
336
337                         if (node == null)
338                                 return String.Empty;
339                         else
340                                 return node.InnerXml;
341                 }
342
343
344                 public void Load (string projectFileName)
345                 {
346                         this.fullFileName = Path.GetFullPath (projectFileName);
347                         DoLoad (new StreamReader (projectFileName));
348                 }
349                 
350                 [MonoTODO ("Not tested")]
351                 public void Load (TextReader textReader)
352                 {
353                         fullFileName = String.Empty;
354                         DoLoad (textReader);
355                 }
356
357                 public void LoadXml (string projectXml)
358                 {
359                         fullFileName = String.Empty;
360                         DoLoad (new StringReader (projectXml));
361                         MarkProjectAsDirty ();
362                 }
363
364
365                 public void MarkProjectAsDirty ()
366                 {
367                         isDirty = true;
368                         timeOfLastDirty = DateTime.Now;
369                 }
370
371                 [MonoTODO ("Not tested")]
372                 public void RemoveAllItemGroups ()
373                 {
374                         int length = ItemGroups.Count;
375                         BuildItemGroup [] groups = new BuildItemGroup [length];
376                         ItemGroups.CopyTo (groups, 0);
377
378                         for (int i = 0; i < length; i++)
379                                 RemoveItemGroup (groups [i]);
380
381                         MarkProjectAsDirty ();
382                         NeedToReevaluate ();
383                 }
384
385                 [MonoTODO ("Not tested")]
386                 public void RemoveAllPropertyGroups ()
387                 {
388                         int length = PropertyGroups.Count;
389                         BuildPropertyGroup [] groups = new BuildPropertyGroup [length];
390                         PropertyGroups.CopyTo (groups, 0);
391
392                         for (int i = 0; i < length; i++)
393                                 RemovePropertyGroup (groups [i]);
394
395                         MarkProjectAsDirty ();
396                         NeedToReevaluate ();
397                 }
398
399                 [MonoTODO]
400                 public void RemoveItem (BuildItem itemToRemove)
401                 {
402                         if (itemToRemove == null)
403                                 throw new ArgumentNullException ("itemToRemove");
404
405                         if (!itemToRemove.FromXml && !itemToRemove.HasParent)
406                                 throw new InvalidOperationException ("The object passed in is not part of the project.");
407
408                         BuildItemGroup big = itemToRemove.ParentItemGroup;
409
410                         if (big.Count == 1) {
411                                 // ParentItemGroup for items from xml and that have parent is the same
412                                 groupingCollection.Remove (big);
413                         } else {
414                                 if (big.ParentProject != this)
415                                         throw new InvalidOperationException ("The object passed in is not part of the project.");
416
417                                 if (itemToRemove.FromXml)
418                                         big.RemoveItem (itemToRemove);
419                                 else
420                                         big.RemoveItem (itemToRemove.ParentItem);
421                         }
422
423                         MarkProjectAsDirty ();
424                         NeedToReevaluate ();
425                 }
426
427                 [MonoTODO ("Not tested")]
428                 public void RemoveItemGroup (BuildItemGroup itemGroupToRemove)
429                 {
430                         if (itemGroupToRemove == null)
431                                 throw new ArgumentNullException ("itemGroupToRemove");
432
433                         groupingCollection.Remove (itemGroupToRemove);
434                         MarkProjectAsDirty ();
435                 }
436                 
437                 [MonoTODO]
438                 // NOTE: does not modify imported projects
439                 public void RemoveItemGroupsWithMatchingCondition (string matchingCondition)
440                 {
441                         throw new NotImplementedException ();
442                 }
443
444                 [MonoTODO]
445                 public void RemoveItemsByName (string itemName)
446                 {
447                         if (itemName == null)
448                                 throw new ArgumentNullException ("itemName");
449
450                         throw new NotImplementedException ();
451                 }
452
453                 [MonoTODO ("Not tested")]
454                 public void RemovePropertyGroup (BuildPropertyGroup propertyGroupToRemove)
455                 {
456                         if (propertyGroupToRemove == null)
457                                 throw new ArgumentNullException ("propertyGroupToRemove");
458
459                         groupingCollection.Remove (propertyGroupToRemove);
460                         MarkProjectAsDirty ();
461                 }
462                 
463                 [MonoTODO]
464                 // NOTE: does not modify imported projects
465                 public void RemovePropertyGroupsWithMatchingCondition (string matchCondition)
466                 {
467                         throw new NotImplementedException ();
468                 }
469
470                 [MonoTODO]
471                 public void ResetBuildStatus ()
472                 {
473                         throw new NotImplementedException ();
474                 }
475
476                 public void Save (string projectFileName)
477                 {
478                         Save (projectFileName, Encoding.Default);
479                         isDirty = false;
480                 }
481
482                 [MonoTODO ("Ignores encoding")]
483                 public void Save (string projectFileName, Encoding encoding)
484                 {
485                         xmlDocument.Save (projectFileName);
486                         isDirty = false;
487                 }
488
489                 public void Save (TextWriter outTextWriter)
490                 {
491                         xmlDocument.Save (outTextWriter);
492                         isDirty = false;
493                 }
494
495                 public void SetImportedProperty (string propertyName,
496                                                  string propertyValue,
497                                                  string condition,
498                                                  Project importProject)
499                 {
500                         SetImportedProperty (propertyName, propertyValue, condition, importProject,
501                                 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup);
502                 }
503
504                 public void SetImportedProperty (string propertyName,
505                                                  string propertyValue,
506                                                  string condition,
507                                                  Project importedProject,
508                                                  PropertyPosition position)
509                 {
510                         SetImportedProperty (propertyName, propertyValue, condition, importedProject,
511                                 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
512                 }
513
514                 [MonoTODO]
515                 public void SetImportedProperty (string propertyName,
516                                                  string propertyValue,
517                                                  string condition,
518                                                  Project importedProject,
519                                                  PropertyPosition position,
520                                                  bool treatPropertyValueAsLiteral)
521                 {
522                         throw new NotImplementedException ();
523                 }
524
525                 public void SetProjectExtensions (string id, string xmlText)
526                 {
527                         if (id == null)
528                                 throw new ArgumentNullException ("id");
529                         if (xmlText == null)
530                                 throw new ArgumentNullException ("xmlText");
531
532                         XmlNode projectExtensions, node;
533
534                         projectExtensions = xmlDocument.SelectSingleNode ("/tns:Project/tns:ProjectExtensions", XmlNamespaceManager);
535                         
536                         if (projectExtensions == null) {
537                                 projectExtensions = xmlDocument.CreateElement ("ProjectExtensions", XmlNamespace);
538                                 xmlDocument.DocumentElement.AppendChild (projectExtensions);
539
540                                 node = xmlDocument.CreateElement (id, XmlNamespace);
541                                 node.InnerXml = xmlText;
542                                 projectExtensions.AppendChild (node);
543                         } else {
544                                 node = xmlDocument.SelectSingleNode (String.Format ("/tns:Project/tns:ProjectExtensions/tns:{0}", id), XmlNamespaceManager);
545
546                                 if (node == null) {
547                                         node = xmlDocument.CreateElement (id, XmlNamespace);
548                                         projectExtensions.AppendChild (node);
549                                 }
550                                 
551                                 node.InnerXml = xmlText;
552                                 
553                         }
554
555                         MarkProjectAsDirty ();
556                 }
557                 
558                 public void SetProperty (string propertyName,
559                                          string propertyValue)
560                 {
561                         SetProperty (propertyName, propertyValue, "true",
562                                 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
563                 }
564
565                 public void SetProperty (string propertyName,
566                                          string propertyValue,
567                                          string condition)
568                 {
569                         SetProperty (propertyName, propertyValue, condition,
570                                 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup);
571                 }
572
573                 public void SetProperty (string propertyName,
574                                          string propertyValue,
575                                          string condition,
576                                          PropertyPosition position)
577                 {
578                         SetProperty (propertyName, propertyValue, condition,
579                                 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
580                 }
581
582                 [MonoTODO]
583                 public void SetProperty (string propertyName,
584                                          string propertyValue,
585                                          string condition,
586                                          PropertyPosition position,
587                                          bool treatPropertyValueAsLiteral)
588                 {
589                         throw new NotImplementedException ();
590                 }
591
592                 internal void Unload ()
593                 {
594                         unloaded = true;
595                 }
596
597                 internal void CheckUnloaded ()
598                 {
599                         if (unloaded)
600                                 throw new InvalidOperationException ("This project object has been unloaded from the MSBuild engine and is no longer valid.");
601                 }
602
603                 internal void NeedToReevaluate ()
604                 {
605                         needToReevaluate = true;
606                 }
607                                 
608                 // Does the actual loading.
609                 void DoLoad (TextReader textReader)
610                 {
611                         try {
612                                 ParentEngine.RemoveLoadedProject (this);
613         
614                                 XmlReaderSettings settings = new XmlReaderSettings ();
615         
616                                 if (SchemaFile != null) {
617                                         settings.Schemas.Add (null, SchemaFile);
618                                         settings.ValidationType = ValidationType.Schema;
619                                         settings.ValidationEventHandler += new ValidationEventHandler (ValidationCallBack);
620                                 }
621         
622                                 XmlReader xmlReader = XmlReader.Create (textReader, settings);
623                                 xmlDocument.Load (xmlReader);
624
625                                 if (xmlDocument.DocumentElement.Name != "Project") {
626                                         throw new InvalidProjectFileException (String.Format (
627                                                 "The element <{0}> is unrecognized, or not supported in this context.", xmlDocument.DocumentElement.Name));
628                                 }
629         
630                                 if (xmlDocument.DocumentElement.GetAttribute ("xmlns") != ns) {
631                                         throw new InvalidProjectFileException (
632                                                 @"The default XML namespace of the project must be the MSBuild XML namespace." + 
633                                                 " If the project is authored in the MSBuild 2003 format, please add " +
634                                                 "xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\" to the <Project> element. " +
635                                                 "If the project has been authored in the old 1.0 or 1.2 format, please convert it to MSBuild 2003 format.  ");
636                                 }
637                                 ProcessXml ();
638                                 ParentEngine.AddLoadedProject (this);
639                         } catch (Exception e) {
640                                 throw new InvalidProjectFileException (e.Message, e);
641                         } finally {
642                                 textReader.Close ();
643                         }
644                 }
645
646                 void Reevaluate ()
647                 {
648                         ProcessXml ();
649                 }
650
651                 void ProcessXml ()
652                 {
653                         groupingCollection = new GroupingCollection (this);
654                         imports = new ImportCollection (groupingCollection);
655                         usingTasks = new UsingTaskCollection (this);
656                         itemGroups = new BuildItemGroupCollection (groupingCollection);
657                         propertyGroups = new BuildPropertyGroupCollection (groupingCollection);
658                         targets = new TargetCollection (this);
659                         last_item_group_containing = new Dictionary <string, BuildItemGroup> ();
660                         
661                         taskDatabase = new TaskDatabase ();
662                         if (ParentEngine.DefaultTasksRegistered)
663                                 taskDatabase.CopyTasks (ParentEngine.DefaultTasks);     
664
665                         if (xmlDocument.DocumentElement.GetAttributeNode ("DefaultTargets") != null)
666                                 defaultTargets = xmlDocument.DocumentElement.GetAttribute ("DefaultTargets").Split (';');
667                         else
668                                 defaultTargets = new string [0];
669                         
670                         ProcessElements (xmlDocument.DocumentElement, null);
671                         
672                         isDirty = false;
673                         Evaluate ();
674                 }
675                 
676                 internal void ProcessElements (XmlElement rootElement, ImportedProject ip)
677                 {
678                         foreach (XmlNode xn in rootElement.ChildNodes) {
679                                 if (xn is XmlElement) {
680                                         XmlElement xe = (XmlElement) xn;
681                                         switch (xe.Name) {
682                                         case "ProjectExtensions":
683                                                 AddProjectExtensions (xe);
684                                                 break;
685                                         case "Warning":
686                                         case "Message":
687                                         case "Error":
688                                                 AddMessage (xe);
689                                                 break;
690                                         case "Target":
691                                                 AddTarget (xe, ip);
692                                                 break;
693                                         case "UsingTask":
694                                                 AddUsingTask (xe, ip);
695                                                 break;
696                                         case "Import":
697                                                 AddImport (xe, ip);
698                                                 break;
699                                         case "ItemGroup":
700                                                 AddItemGroup (xe, ip);
701                                                 break;
702                                         case "PropertyGroup":
703                                                 AddPropertyGroup (xe, ip);
704                                                 break;
705                                         case  "Choose":
706                                                 AddChoose (xe);
707                                                 break;
708                                         default:
709                                                 throw new InvalidProjectFileException ("Invalid element in project file.");
710                                         }
711                                 }
712                         }
713                 }
714                 
715                 void Evaluate ()
716                 {
717                         evaluatedItems = new BuildItemGroup (null, this, null, true);
718                         evaluatedItemsIgnoringCondition = new BuildItemGroup (null, this, null, true);
719                         evaluatedItemsByName = new Dictionary <string, BuildItemGroup> (StringComparer.InvariantCultureIgnoreCase);
720                         evaluatedItemsByNameIgnoringCondition = new Dictionary <string, BuildItemGroup> (StringComparer.InvariantCultureIgnoreCase);
721                         evaluatedProperties = new BuildPropertyGroup (null, null, null, true);
722
723                         InitializeProperties ();
724
725                         groupingCollection.Evaluate ();
726
727                         //FIXME: UsingTasks aren't really evaluated. (shouldn't use expressions or anything)
728                         foreach (UsingTask usingTask in UsingTasks)
729                                 usingTask.Evaluate ();
730                 }
731
732                 void InitializeProperties ()
733                 {
734                         BuildProperty bp;
735
736                         foreach (BuildProperty gp in GlobalProperties) {
737                                 bp = new BuildProperty (gp.Name, gp.Value, PropertyType.Global);
738                                 EvaluatedProperties.AddProperty (bp);
739                         }
740                         
741                         foreach (DictionaryEntry de in Environment.GetEnvironmentVariables ()) {
742                                 bp = new BuildProperty ((string) de.Key, (string) de.Value, PropertyType.Environment);
743                                 EvaluatedProperties.AddProperty (bp);
744                         }
745
746                         EvaluatedProperties.AddProperty (new BuildProperty ("MSBuildBinPath", parentEngine.BinPath, PropertyType.Reserved));
747
748                         // FIXME: make some internal method that will work like GetDirectoryName but output String.Empty on null/String.Empty
749                         string projectDir;
750                         if (FullFileName == String.Empty)
751                                 projectDir = Environment.CurrentDirectory;
752                         else
753                                 projectDir = Path.GetDirectoryName (FullFileName);
754
755                         EvaluatedProperties.AddProperty (new BuildProperty ("MSBuildProjectDirectory", projectDir, PropertyType.Reserved));
756                 }
757                 
758                 void AddProjectExtensions (XmlElement xmlElement)
759                 {
760                 }
761                 
762                 void AddMessage (XmlElement xmlElement)
763                 {
764                 }
765                 
766                 void AddTarget (XmlElement xmlElement, ImportedProject importedProject)
767                 {
768                         Target target = new Target (xmlElement, this, importedProject);
769                         targets.AddTarget (target);
770                         
771                         if (firstTargetName == null)
772                                 firstTargetName = target.Name;
773                 }
774                 
775                 void AddUsingTask (XmlElement xmlElement, ImportedProject importedProject)
776                 {
777                         UsingTask usingTask;
778
779                         usingTask = new UsingTask (xmlElement, this, importedProject);
780                         UsingTasks.Add (usingTask);
781                 }
782                 
783                 void AddImport (XmlElement xmlElement, ImportedProject importingProject)
784                 {
785                         Import import;
786                         
787                         import = new Import (xmlElement, this, importingProject);
788                         Imports.Add (import);
789                 }
790                 
791                 void AddItemGroup (XmlElement xmlElement, ImportedProject importedProject)
792                 {
793                         BuildItemGroup big = new BuildItemGroup (xmlElement, this, importedProject, false);
794                         ItemGroups.Add (big);
795                 }
796                 
797                 void AddPropertyGroup (XmlElement xmlElement, ImportedProject importedProject)
798                 {
799                         BuildPropertyGroup bpg = new BuildPropertyGroup (xmlElement, this, importedProject, false);
800                         PropertyGroups.Add (bpg);
801                 }
802                 
803                 void AddChoose (XmlElement xmlElement)
804                 {
805                         BuildChoose bc = new BuildChoose (xmlElement, this);
806                         groupingCollection.Add (bc);
807                 }
808                 
809                 static void ValidationCallBack (object sender, ValidationEventArgs e)
810                 {
811                         Console.WriteLine ("Validation Error: {0}", e.Message);
812                 }
813                 
814                 public bool BuildEnabled {
815                         get {
816                                 return buildEnabled;
817                         }
818                         set {
819                                 buildEnabled = value;
820                         }
821                 }
822
823                 [MonoTODO]
824                 public Encoding Encoding {
825                         get { return encoding; }
826                 }
827
828                 public string DefaultTargets {
829                         get {
830                                 return xmlDocument.DocumentElement.GetAttribute ("DefaultTargets");
831                         }
832                         set {
833                                 xmlDocument.DocumentElement.SetAttribute ("DefaultTargets", value);
834                                 defaultTargets = value.Split (';');
835                         }
836                 }
837
838                 public BuildItemGroup EvaluatedItems {
839                         get {
840                                 if (needToReevaluate) {
841                                         needToReevaluate = false;
842                                         Reevaluate ();
843                                 }
844                                 return evaluatedItems;
845                         }
846                 }
847
848                 public BuildItemGroup EvaluatedItemsIgnoringCondition {
849                         get {
850                                 if (needToReevaluate) {
851                                         needToReevaluate = false;
852                                         Reevaluate ();
853                                 }
854                                 return evaluatedItemsIgnoringCondition;
855                         }
856                 }
857                 
858                 internal IDictionary <string, BuildItemGroup> EvaluatedItemsByName {
859                         get {
860                                 // FIXME: do we need to do this here?
861                                 if (needToReevaluate) {
862                                         needToReevaluate = false;
863                                         Reevaluate ();
864                                 }
865                                 return evaluatedItemsByName;
866                         }
867                 }
868                 
869                 internal IDictionary <string, BuildItemGroup> EvaluatedItemsByNameIgnoringCondition {
870                         get {
871                                 // FIXME: do we need to do this here?
872                                 if (needToReevaluate) {
873                                         needToReevaluate = false;
874                                         Reevaluate ();
875                                 }
876                                 return evaluatedItemsByNameIgnoringCondition;
877                         }
878                 }
879
880                 public BuildPropertyGroup EvaluatedProperties {
881                         get {
882                                 if (needToReevaluate) {
883                                         needToReevaluate = false;
884                                         Reevaluate ();
885                                 }
886                                 return evaluatedProperties;
887                         }
888                 }
889
890                 public string FullFileName {
891                         get { return fullFileName; }
892                         set { fullFileName = value; }
893                 }
894
895                 public BuildPropertyGroup GlobalProperties {
896                         get { return globalProperties; }
897                         set {
898                                 if (value == null)
899                                         throw new ArgumentNullException ("value");
900                                 
901                                 if (value.FromXml)
902                                         throw new InvalidOperationException ("GlobalProperties can not be set to persisted property group.");
903                                 
904                                 globalProperties = value;
905                                 NeedToReevaluate ();
906                         }
907                 }
908
909                 public bool IsDirty {
910                         get { return isDirty; }
911                 }
912
913                 public bool IsValidated {
914                         get { return isValidated; }
915                         set { isValidated = value; }
916                 }
917
918                 public BuildItemGroupCollection ItemGroups {
919                         get { return itemGroups; }
920                 }
921                 
922                 public ImportCollection Imports {
923                         get { return imports; }
924                 }
925                 
926                 public string InitialTargets {
927                         get { return initialTargets; }
928                         set { initialTargets = value; }
929                 }
930
931                 public Engine ParentEngine {
932                         get { return parentEngine; }
933                 }
934
935                 public BuildPropertyGroupCollection PropertyGroups {
936                         get { return propertyGroups; }
937                 }
938
939                 public string SchemaFile {
940                         get { return schemaFile; }
941                         set { schemaFile = value; }
942                 }
943
944                 public TargetCollection Targets {
945                         get { return targets; }
946                 }
947
948                 public DateTime TimeOfLastDirty {
949                         get { return timeOfLastDirty; }
950                 }
951                 
952                 public UsingTaskCollection UsingTasks {
953                         get { return usingTasks; }
954                 }
955
956                 [MonoTODO]
957                 public string Xml {
958                         get { return xmlDocument.InnerXml; }
959                 }
960
961                 internal Dictionary <string, BuildItemGroup> LastItemGroupContaining {
962                         get { return last_item_group_containing; }
963                 }
964                 
965                 internal static XmlNamespaceManager XmlNamespaceManager {
966                         get {
967                                 if (manager == null) {
968                                         manager = new XmlNamespaceManager (new NameTable ());
969                                         manager.AddNamespace ("tns", ns);
970                                 }
971                                 
972                                 return manager;
973                         }
974                 }
975                 
976                 internal TaskDatabase TaskDatabase {
977                         get { return taskDatabase; }
978                 }
979                 
980                 internal XmlDocument XmlDocument {
981                         get { return xmlDocument; }
982                 }
983                 
984                 internal static string XmlNamespace {
985                         get { return ns; }
986                 }
987         }
988 }
989
990 #endif