2007-02-03 Marek Sieradzki <marek.sieradzki@gmail.com>
[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                                 
273                         return true;
274                 }
275
276                 [MonoTODO]
277                 public string[] GetConditionedPropertyValues (string propertyName)
278                 {
279                         if (conditionedProperties.ContainsKey (propertyName))
280                                 return conditionedProperties [propertyName].ToArray ();
281                         else
282                                 return new string [0];
283                 }
284
285                 public BuildItemGroup GetEvaluatedItemsByName (string itemName)
286                 {                       
287                         if (needToReevaluate) {
288                                 needToReevaluate = false;
289                                 Reevaluate ();
290                         }
291
292                         if (evaluatedItemsByName.ContainsKey (itemName))
293                                 return evaluatedItemsByName [itemName];
294                         else
295                                 return new BuildItemGroup ();
296                 }
297
298                 public BuildItemGroup GetEvaluatedItemsByNameIgnoringCondition (string itemName)
299                 {
300                         if (needToReevaluate) {
301                                 needToReevaluate = false;
302                                 Reevaluate ();
303                         }
304
305                         if (evaluatedItemsByNameIgnoringCondition.ContainsKey (itemName))
306                                 return evaluatedItemsByNameIgnoringCondition [itemName];
307                         else
308                                 return new BuildItemGroup ();
309                 }
310
311                 public string GetEvaluatedProperty (string propertyName)
312                 {
313                         if (needToReevaluate) {
314                                 needToReevaluate = false;
315                                 Reevaluate ();
316                         }
317
318                         if (propertyName == null)
319                                 throw new ArgumentNullException ("propertyName");
320
321                         BuildProperty bp = evaluatedProperties [propertyName];
322
323                         return bp == null ? null : (string) bp;
324                 }
325
326                 [MonoTODO ("We should remember that node and not use XPath to get it")]
327                 public string GetProjectExtensions (string id)
328                 {
329                         if (id == null || id == String.Empty)
330                                 return String.Empty;
331
332                         XmlNode node = xmlDocument.SelectSingleNode (String.Format ("/tns:Project/tns:ProjectExtensions/tns:{0}", id), XmlNamespaceManager);
333
334                         if (node == null)
335                                 return String.Empty;
336                         else
337                                 return node.InnerXml;
338                 }
339
340
341                 public void Load (string projectFileName)
342                 {
343                         this.fullFileName = Path.GetFullPath (projectFileName);
344                         DoLoad (new StreamReader (projectFileName));
345                 }
346                 
347                 [MonoTODO ("Not tested")]
348                 public void Load (TextReader textReader)
349                 {
350                         fullFileName = String.Empty;
351                         DoLoad (textReader);
352                 }
353
354                 public void LoadXml (string projectXml)
355                 {
356                         fullFileName = String.Empty;
357                         DoLoad (new StringReader (projectXml));
358                         MarkProjectAsDirty ();
359                 }
360
361
362                 public void MarkProjectAsDirty ()
363                 {
364                         isDirty = true;
365                         timeOfLastDirty = DateTime.Now;
366                 }
367
368                 [MonoTODO ("Not tested")]
369                 public void RemoveAllItemGroups ()
370                 {
371                         int length = ItemGroups.Count;
372                         BuildItemGroup [] groups = new BuildItemGroup [length];
373                         ItemGroups.CopyTo (groups, 0);
374
375                         for (int i = 0; i < length; i++)
376                                 RemoveItemGroup (groups [i]);
377
378                         MarkProjectAsDirty ();
379                         NeedToReevaluate ();
380                 }
381
382                 [MonoTODO ("Not tested")]
383                 public void RemoveAllPropertyGroups ()
384                 {
385                         int length = PropertyGroups.Count;
386                         BuildPropertyGroup [] groups = new BuildPropertyGroup [length];
387                         PropertyGroups.CopyTo (groups, 0);
388
389                         for (int i = 0; i < length; i++)
390                                 RemovePropertyGroup (groups [i]);
391
392                         MarkProjectAsDirty ();
393                         NeedToReevaluate ();
394                 }
395
396                 [MonoTODO]
397                 public void RemoveItem (BuildItem itemToRemove)
398                 {
399                         if (itemToRemove == null)
400                                 throw new ArgumentNullException ("itemToRemove");
401
402                         if (!itemToRemove.FromXml && !itemToRemove.HasParent)
403                                 throw new InvalidOperationException ("The object passed in is not part of the project.");
404
405                         BuildItemGroup big = itemToRemove.ParentItemGroup;
406
407                         if (big.Count == 1) {
408                                 // ParentItemGroup for items from xml and that have parent is the same
409                                 groupingCollection.Remove (big);
410                         } else {
411                                 if (big.ParentProject != this)
412                                         throw new InvalidOperationException ("The object passed in is not part of the project.");
413
414                                 if (itemToRemove.FromXml)
415                                         big.RemoveItem (itemToRemove);
416                                 else
417                                         big.RemoveItem (itemToRemove.ParentItem);
418                         }
419
420                         MarkProjectAsDirty ();
421                         NeedToReevaluate ();
422                 }
423
424                 [MonoTODO ("Not tested")]
425                 public void RemoveItemGroup (BuildItemGroup itemGroupToRemove)
426                 {
427                         if (itemGroupToRemove == null)
428                                 throw new ArgumentNullException ("itemGroupToRemove");
429
430                         groupingCollection.Remove (itemGroupToRemove);
431                         MarkProjectAsDirty ();
432                 }
433                 
434                 [MonoTODO]
435                 // NOTE: does not modify imported projects
436                 public void RemoveItemGroupsWithMatchingCondition (string matchingCondition)
437                 {
438                         throw new NotImplementedException ();
439                 }
440
441                 [MonoTODO]
442                 public void RemoveItemsByName (string itemName)
443                 {
444                         if (itemName == null)
445                                 throw new ArgumentNullException ("itemName");
446
447                         throw new NotImplementedException ();
448                 }
449
450                 [MonoTODO ("Not tested")]
451                 public void RemovePropertyGroup (BuildPropertyGroup propertyGroupToRemove)
452                 {
453                         if (propertyGroupToRemove == null)
454                                 throw new ArgumentNullException ("propertyGroupToRemove");
455
456                         groupingCollection.Remove (propertyGroupToRemove);
457                         MarkProjectAsDirty ();
458                 }
459                 
460                 [MonoTODO]
461                 // NOTE: does not modify imported projects
462                 public void RemovePropertyGroupsWithMatchingCondition (string matchCondition)
463                 {
464                         throw new NotImplementedException ();
465                 }
466
467                 [MonoTODO]
468                 public void ResetBuildStatus ()
469                 {
470                         throw new NotImplementedException ();
471                 }
472
473                 public void Save (string projectFileName)
474                 {
475                         Save (projectFileName, Encoding.Default);
476                         isDirty = false;
477                 }
478
479                 [MonoTODO ("Ignores encoding")]
480                 public void Save (string projectFileName, Encoding encoding)
481                 {
482                         xmlDocument.Save (projectFileName);
483                         isDirty = false;
484                 }
485
486                 public void Save (TextWriter outTextWriter)
487                 {
488                         xmlDocument.Save (outTextWriter);
489                         isDirty = false;
490                 }
491
492                 public void SetImportedProperty (string propertyName,
493                                                  string propertyValue,
494                                                  string condition,
495                                                  Project importProject)
496                 {
497                         SetImportedProperty (propertyName, propertyValue, condition, importProject,
498                                 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup);
499                 }
500
501                 public void SetImportedProperty (string propertyName,
502                                                  string propertyValue,
503                                                  string condition,
504                                                  Project importedProject,
505                                                  PropertyPosition position)
506                 {
507                         SetImportedProperty (propertyName, propertyValue, condition, importedProject,
508                                 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
509                 }
510
511                 [MonoTODO]
512                 public void SetImportedProperty (string propertyName,
513                                                  string propertyValue,
514                                                  string condition,
515                                                  Project importedProject,
516                                                  PropertyPosition position,
517                                                  bool treatPropertyValueAsLiteral)
518                 {
519                         throw new NotImplementedException ();
520                 }
521
522                 public void SetProjectExtensions (string id, string xmlText)
523                 {
524                         if (id == null)
525                                 throw new ArgumentNullException ("id");
526                         if (xmlText == null)
527                                 throw new ArgumentNullException ("xmlText");
528
529                         XmlNode projectExtensions, node;
530
531                         projectExtensions = xmlDocument.SelectSingleNode ("/tns:Project/tns:ProjectExtensions", XmlNamespaceManager);
532                         
533                         if (projectExtensions == null) {
534                                 projectExtensions = xmlDocument.CreateElement ("ProjectExtensions", XmlNamespace);
535                                 xmlDocument.DocumentElement.AppendChild (projectExtensions);
536
537                                 node = xmlDocument.CreateElement (id, XmlNamespace);
538                                 node.InnerXml = xmlText;
539                                 projectExtensions.AppendChild (node);
540                         } else {
541                                 node = xmlDocument.SelectSingleNode (String.Format ("/tns:Project/tns:ProjectExtensions/tns:{0}", id), XmlNamespaceManager);
542
543                                 if (node == null) {
544                                         node = xmlDocument.CreateElement (id, XmlNamespace);
545                                         projectExtensions.AppendChild (node);
546                                 }
547                                 
548                                 node.InnerXml = xmlText;
549                                 
550                         }
551
552                         MarkProjectAsDirty ();
553                 }
554                 
555                 public void SetProperty (string propertyName,
556                                          string propertyValue)
557                 {
558                         SetProperty (propertyName, propertyValue, "true",
559                                 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
560                 }
561
562                 public void SetProperty (string propertyName,
563                                          string propertyValue,
564                                          string condition)
565                 {
566                         SetProperty (propertyName, propertyValue, condition,
567                                 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup);
568                 }
569
570                 public void SetProperty (string propertyName,
571                                          string propertyValue,
572                                          string condition,
573                                          PropertyPosition position)
574                 {
575                         SetProperty (propertyName, propertyValue, condition,
576                                 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
577                 }
578
579                 [MonoTODO]
580                 public void SetProperty (string propertyName,
581                                          string propertyValue,
582                                          string condition,
583                                          PropertyPosition position,
584                                          bool treatPropertyValueAsLiteral)
585                 {
586                         throw new NotImplementedException ();
587                 }
588
589                 internal void Unload ()
590                 {
591                         unloaded = true;
592                 }
593
594                 internal void CheckUnloaded ()
595                 {
596                         if (unloaded)
597                                 throw new InvalidOperationException ("This project object has been unloaded from the MSBuild engine and is no longer valid.");
598                 }
599
600                 internal void NeedToReevaluate ()
601                 {
602                         needToReevaluate = true;
603                 }
604                                 
605                 // Does the actual loading.
606                 void DoLoad (TextReader textReader)
607                 {
608                         try {
609                                 ParentEngine.RemoveLoadedProject (this);
610         
611                                 XmlReaderSettings settings = new XmlReaderSettings ();
612         
613                                 if (SchemaFile != null) {
614                                         settings.Schemas.Add (null, SchemaFile);
615                                         settings.ValidationType = ValidationType.Schema;
616                                         settings.ValidationEventHandler += new ValidationEventHandler (ValidationCallBack);
617                                 }
618         
619                                 XmlReader xmlReader = XmlReader.Create (textReader, settings);
620                                 xmlDocument.Load (xmlReader);
621
622                                 if (xmlDocument.DocumentElement.Name != "Project") {
623                                         throw new InvalidProjectFileException (String.Format (
624                                                 "The element <{0}> is unrecognized, or not supported in this context.", xmlDocument.DocumentElement.Name));
625                                 }
626         
627                                 if (xmlDocument.DocumentElement.GetAttribute ("xmlns") != ns) {
628                                         throw new InvalidProjectFileException (
629                                                 @"The default XML namespace of the project must be the MSBuild XML namespace." + 
630                                                 " If the project is authored in the MSBuild 2003 format, please add " +
631                                                 "xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\" to the <Project> element. " +
632                                                 "If the project has been authored in the old 1.0 or 1.2 format, please convert it to MSBuild 2003 format.  ");
633                                 }
634                                 ProcessXml ();
635                                 ParentEngine.AddLoadedProject (this);
636                         } catch (Exception e) {
637                                 throw new InvalidProjectFileException (e.Message, e);
638                         } finally {
639                                 textReader.Close ();
640                         }
641                 }
642
643                 void Reevaluate ()
644                 {
645                         ProcessXml ();
646                 }
647
648                 void ProcessXml ()
649                 {
650                         groupingCollection = new GroupingCollection (this);
651                         imports = new ImportCollection (groupingCollection);
652                         usingTasks = new UsingTaskCollection (this);
653                         itemGroups = new BuildItemGroupCollection (groupingCollection);
654                         propertyGroups = new BuildPropertyGroupCollection (groupingCollection);
655                         targets = new TargetCollection (this);
656                         last_item_group_containing = new Dictionary <string, BuildItemGroup> ();
657                         
658                         taskDatabase = new TaskDatabase ();
659                         if (ParentEngine.DefaultTasksRegistered)
660                                 taskDatabase.CopyTasks (ParentEngine.DefaultTasks);     
661
662                         if (xmlDocument.DocumentElement.GetAttributeNode ("DefaultTargets") != null)
663                                 defaultTargets = xmlDocument.DocumentElement.GetAttribute ("DefaultTargets").Split (';');
664                         else
665                                 defaultTargets = new string [0];
666                         
667                         ProcessElements (xmlDocument.DocumentElement, null);
668                         
669                         isDirty = false;
670                         Evaluate ();
671                 }
672                 
673                 internal void ProcessElements (XmlElement rootElement, ImportedProject ip)
674                 {
675                         foreach (XmlNode xn in rootElement.ChildNodes) {
676                                 if (xn is XmlElement) {
677                                         XmlElement xe = (XmlElement) xn;
678                                         switch (xe.Name) {
679                                         case "ProjectExtensions":
680                                                 AddProjectExtensions (xe);
681                                                 break;
682                                         case "Warning":
683                                         case "Message":
684                                         case "Error":
685                                                 AddMessage (xe);
686                                                 break;
687                                         case "Target":
688                                                 AddTarget (xe, ip);
689                                                 break;
690                                         case "UsingTask":
691                                                 AddUsingTask (xe, ip);
692                                                 break;
693                                         case "Import":
694                                                 AddImport (xe, ip);
695                                                 break;
696                                         case "ItemGroup":
697                                                 AddItemGroup (xe, ip);
698                                                 break;
699                                         case "PropertyGroup":
700                                                 AddPropertyGroup (xe, ip);
701                                                 break;
702                                         case  "Choose":
703                                                 AddChoose (xe);
704                                                 break;
705                                         default:
706                                                 throw new InvalidProjectFileException ("Invalid element in project file.");
707                                         }
708                                 }
709                         }
710                 }
711                 
712                 void Evaluate ()
713                 {
714                         evaluatedItems = new BuildItemGroup (null, this, null, true);
715                         evaluatedItemsIgnoringCondition = new BuildItemGroup (null, this, null, true);
716                         evaluatedItemsByName = new Dictionary <string, BuildItemGroup> (StringComparer.InvariantCultureIgnoreCase);
717                         evaluatedItemsByNameIgnoringCondition = new Dictionary <string, BuildItemGroup> (StringComparer.InvariantCultureIgnoreCase);
718                         evaluatedProperties = new BuildPropertyGroup (null, null, null, true);
719
720                         InitializeProperties ();
721
722                         groupingCollection.Evaluate ();
723
724                         //FIXME: UsingTasks aren't really evaluated. (shouldn't use expressions or anything)
725                         foreach (UsingTask usingTask in UsingTasks)
726                                 usingTask.Evaluate ();
727                 }
728
729                 void InitializeProperties ()
730                 {
731                         BuildProperty bp;
732
733                         foreach (BuildProperty gp in GlobalProperties) {
734                                 bp = new BuildProperty (gp.Name, gp.Value, PropertyType.Global);
735                                 EvaluatedProperties.AddProperty (bp);
736                         }
737                         
738                         foreach (DictionaryEntry de in Environment.GetEnvironmentVariables ()) {
739                                 bp = new BuildProperty ((string) de.Key, (string) de.Value, PropertyType.Environment);
740                                 EvaluatedProperties.AddProperty (bp);
741                         }
742
743                         EvaluatedProperties.AddProperty (new BuildProperty ("MSBuildBinPath", parentEngine.BinPath, PropertyType.Reserved));
744
745                         // FIXME: make some internal method that will work like GetDirectoryName but output String.Empty on null/String.Empty
746                         string projectDir;
747                         if (FullFileName == String.Empty)
748                                 projectDir = Environment.CurrentDirectory;
749                         else
750                                 projectDir = Path.GetDirectoryName (FullFileName);
751
752                         EvaluatedProperties.AddProperty (new BuildProperty ("MSBuildProjectDirectory", projectDir, PropertyType.Reserved));
753                 }
754                 
755                 void AddProjectExtensions (XmlElement xmlElement)
756                 {
757                 }
758                 
759                 void AddMessage (XmlElement xmlElement)
760                 {
761                 }
762                 
763                 void AddTarget (XmlElement xmlElement, ImportedProject importedProject)
764                 {
765                         Target target = new Target (xmlElement, this, importedProject);
766                         targets.AddTarget (target);
767                         
768                         if (firstTargetName == null)
769                                 firstTargetName = target.Name;
770                 }
771                 
772                 void AddUsingTask (XmlElement xmlElement, ImportedProject importedProject)
773                 {
774                         UsingTask usingTask;
775
776                         usingTask = new UsingTask (xmlElement, this, importedProject);
777                         UsingTasks.Add (usingTask);
778                 }
779                 
780                 void AddImport (XmlElement xmlElement, ImportedProject importingProject)
781                 {
782                         Import import;
783                         
784                         import = new Import (xmlElement, this, importingProject);
785                         Imports.Add (import);
786                 }
787                 
788                 void AddItemGroup (XmlElement xmlElement, ImportedProject importedProject)
789                 {
790                         BuildItemGroup big = new BuildItemGroup (xmlElement, this, importedProject, false);
791                         ItemGroups.Add (big);
792                 }
793                 
794                 void AddPropertyGroup (XmlElement xmlElement, ImportedProject importedProject)
795                 {
796                         BuildPropertyGroup bpg = new BuildPropertyGroup (xmlElement, this, importedProject, false);
797                         PropertyGroups.Add (bpg);
798                 }
799                 
800                 void AddChoose (XmlElement xmlElement)
801                 {
802                         BuildChoose bc = new BuildChoose (xmlElement, this);
803                         groupingCollection.Add (bc);
804                 }
805                 
806                 static void ValidationCallBack (object sender, ValidationEventArgs e)
807                 {
808                         Console.WriteLine ("Validation Error: {0}", e.Message);
809                 }
810                 
811                 public bool BuildEnabled {
812                         get {
813                                 return buildEnabled;
814                         }
815                         set {
816                                 buildEnabled = value;
817                         }
818                 }
819
820                 [MonoTODO]
821                 public Encoding Encoding {
822                         get { return encoding; }
823                 }
824
825                 public string DefaultTargets {
826                         get {
827                                 return xmlDocument.DocumentElement.GetAttribute ("DefaultTargets");
828                         }
829                         set {
830                                 xmlDocument.DocumentElement.SetAttribute ("DefaultTargets", value);
831                                 defaultTargets = value.Split (';');
832                         }
833                 }
834
835                 public BuildItemGroup EvaluatedItems {
836                         get {
837                                 if (needToReevaluate) {
838                                         needToReevaluate = false;
839                                         Reevaluate ();
840                                 }
841                                 return evaluatedItems;
842                         }
843                 }
844
845                 public BuildItemGroup EvaluatedItemsIgnoringCondition {
846                         get {
847                                 if (needToReevaluate) {
848                                         needToReevaluate = false;
849                                         Reevaluate ();
850                                 }
851                                 return evaluatedItemsIgnoringCondition;
852                         }
853                 }
854                 
855                 internal IDictionary <string, BuildItemGroup> EvaluatedItemsByName {
856                         get {
857                                 // FIXME: do we need to do this here?
858                                 if (needToReevaluate) {
859                                         needToReevaluate = false;
860                                         Reevaluate ();
861                                 }
862                                 return evaluatedItemsByName;
863                         }
864                 }
865                 
866                 internal IDictionary <string, BuildItemGroup> EvaluatedItemsByNameIgnoringCondition {
867                         get {
868                                 // FIXME: do we need to do this here?
869                                 if (needToReevaluate) {
870                                         needToReevaluate = false;
871                                         Reevaluate ();
872                                 }
873                                 return evaluatedItemsByNameIgnoringCondition;
874                         }
875                 }
876
877                 public BuildPropertyGroup EvaluatedProperties {
878                         get {
879                                 if (needToReevaluate) {
880                                         needToReevaluate = false;
881                                         Reevaluate ();
882                                 }
883                                 return evaluatedProperties;
884                         }
885                 }
886
887                 public string FullFileName {
888                         get { return fullFileName; }
889                         set { fullFileName = value; }
890                 }
891
892                 public BuildPropertyGroup GlobalProperties {
893                         get { return globalProperties; }
894                         set {
895                                 if (value == null)
896                                         throw new ArgumentNullException ("value");
897                                 
898                                 if (value.FromXml)
899                                         throw new InvalidOperationException ("GlobalProperties can not be set to persisted property group.");
900                                 
901                                 globalProperties = value;
902                                 NeedToReevaluate ();
903                         }
904                 }
905
906                 public bool IsDirty {
907                         get { return isDirty; }
908                 }
909
910                 public bool IsValidated {
911                         get { return isValidated; }
912                         set { isValidated = value; }
913                 }
914
915                 public BuildItemGroupCollection ItemGroups {
916                         get { return itemGroups; }
917                 }
918                 
919                 public ImportCollection Imports {
920                         get { return imports; }
921                 }
922                 
923                 public string InitialTargets {
924                         get { return initialTargets; }
925                         set { initialTargets = value; }
926                 }
927
928                 public Engine ParentEngine {
929                         get { return parentEngine; }
930                 }
931
932                 public BuildPropertyGroupCollection PropertyGroups {
933                         get { return propertyGroups; }
934                 }
935
936                 public string SchemaFile {
937                         get { return schemaFile; }
938                         set { schemaFile = value; }
939                 }
940
941                 public TargetCollection Targets {
942                         get { return targets; }
943                 }
944
945                 public DateTime TimeOfLastDirty {
946                         get { return timeOfLastDirty; }
947                 }
948                 
949                 public UsingTaskCollection UsingTasks {
950                         get { return usingTasks; }
951                 }
952
953                 [MonoTODO]
954                 public string Xml {
955                         get { return xmlDocument.InnerXml; }
956                 }
957
958                 internal Dictionary <string, BuildItemGroup> LastItemGroupContaining {
959                         get { return last_item_group_containing; }
960                 }
961                 
962                 internal static XmlNamespaceManager XmlNamespaceManager {
963                         get {
964                                 if (manager == null) {
965                                         manager = new XmlNamespaceManager (new NameTable ());
966                                         manager.AddNamespace ("tns", ns);
967                                 }
968                                 
969                                 return manager;
970                         }
971                 }
972                 
973                 internal TaskDatabase TaskDatabase {
974                         get { return taskDatabase; }
975                 }
976                 
977                 internal XmlDocument XmlDocument {
978                         get { return xmlDocument; }
979                 }
980                 
981                 internal static string XmlNamespace {
982                         get { return ns; }
983                 }
984         }
985 }
986
987 #endif