/// <summary>
        /// Gets a complete list of external cabs referenced by the given installer database file.
        /// </summary>
        /// <returns>True upon completion of the task execution.</returns>
        public override bool Execute()
        {
            ArrayList payloadGroupRefs = new ArrayList();
            ArrayList packageGroupRefs = new ArrayList();

            for (int i = 0; i < this.ProjectReferencePaths.Length; i++)
            {
                ITaskItem item = this.ProjectReferencePaths[i];

                if (!String.IsNullOrEmpty(item.GetMetadata(Common.DoNotHarvest)))
                {
                    continue;
                }

                string projectPath   = CreateProjectReferenceDefineConstants.GetProjectPath(this.ProjectReferencePaths, i);
                string projectName   = Path.GetFileNameWithoutExtension(projectPath);
                string referenceName = Common.GetIdentifierFromName(CreateProjectReferenceDefineConstants.GetReferenceName(item, projectName));

                string[] pogs = item.GetMetadata("RefProjectOutputGroups").Split(';');
                foreach (string pog in pogs)
                {
                    if (!String.IsNullOrEmpty(pog))
                    {
                        // TODO: Add payload group references and package group references once heat is generating them
                        ////payloadGroupRefs.Add(String.Format(CultureInfo.InvariantCulture, "{0}.{1}", referenceName, pog));
                        packageGroupRefs.Add(String.Format(CultureInfo.InvariantCulture, "{0}.{1}", referenceName, pog));
                    }
                }
            }

            XmlDocument doc = new XmlDocument();

            XmlProcessingInstruction head = doc.CreateProcessingInstruction("xml", "version='1.0' encoding='UTF-8'");

            doc.AppendChild(head);

            XmlElement rootElement = doc.CreateElement("Wix");

            rootElement.SetAttribute("xmlns", "http://schemas.microsoft.com/wix/2006/wi");
            doc.AppendChild(rootElement);

            XmlElement fragment = doc.CreateElement("Fragment");

            rootElement.AppendChild(fragment);

            XmlElement payloadGroup = doc.CreateElement("PayloadGroup");

            payloadGroup.SetAttribute("Id", "Bundle.Generated.Payloads");
            fragment.AppendChild(payloadGroup);

            XmlElement packageGroup = doc.CreateElement("PackageGroup");

            packageGroup.SetAttribute("Id", "Bundle.Generated.Packages");
            fragment.AppendChild(packageGroup);

            foreach (string payloadGroupRef in payloadGroupRefs)
            {
                XmlElement payloadGroupRefElement = doc.CreateElement("PayloadGroupRef");
                payloadGroupRefElement.SetAttribute("Id", payloadGroupRef);
                payloadGroup.AppendChild(payloadGroupRefElement);
            }

            foreach (string packageGroupRef in packageGroupRefs)
            {
                XmlElement packageGroupRefElement = doc.CreateElement("PackageGroupRef");
                packageGroupRefElement.SetAttribute("Id", packageGroupRef);
                packageGroup.AppendChild(packageGroupRefElement);
            }

            foreach (ITaskItem item in this.GeneratedFiles)
            {
                string fullPath = item.GetMetadata("FullPath");

                payloadGroup.SetAttribute("Id", Path.GetFileNameWithoutExtension(fullPath) + ".Payloads");
                packageGroup.SetAttribute("Id", Path.GetFileNameWithoutExtension(fullPath) + ".Packages");
                try
                {
                    doc.Save(fullPath);
                }
                catch (Exception e)
                {
                    // e.Message will be something like: "Access to the path 'fullPath' is denied."
                    this.Log.LogMessage(MessageImportance.High, "Unable to save generated file to '{0}'. {1}", fullPath, e.Message);
                }
            }

            return(true);
        }
        public override bool Execute()
        {
            List <ITaskItem>            outputItems     = new List <ITaskItem>();
            Dictionary <string, string> defineConstants = new Dictionary <string, string>();

            for (int i = 0; i < this.ProjectReferencePaths.Length; i++)
            {
                ITaskItem item = this.ProjectReferencePaths[i];

                string configuration     = item.GetMetadata("Configuration");
                string fullConfiguration = item.GetMetadata("FullConfiguration");
                string platform          = item.GetMetadata("Platform");

                string projectPath     = CreateProjectReferenceDefineConstants.GetProjectPath(this.ProjectReferencePaths, i);
                string projectDir      = Path.GetDirectoryName(projectPath) + Path.DirectorySeparatorChar;
                string projectExt      = Path.GetExtension(projectPath);
                string projectFileName = Path.GetFileName(projectPath);
                string projectName     = Path.GetFileNameWithoutExtension(projectPath);

                string referenceName = CreateProjectReferenceDefineConstants.GetReferenceName(item, projectName);

                string targetPath     = item.GetMetadata("FullPath");
                string targetDir      = Path.GetDirectoryName(targetPath) + Path.DirectorySeparatorChar;
                string targetExt      = Path.GetExtension(targetPath);
                string targetFileName = Path.GetFileName(targetPath);
                string targetName     = Path.GetFileNameWithoutExtension(targetPath);

                // If there is no configuration metadata on the project reference task item,
                // check for any additional configuration data provided in the optional task property.
                if (String.IsNullOrEmpty(fullConfiguration))
                {
                    fullConfiguration = this.FindProjectConfiguration(projectName);
                    if (!String.IsNullOrEmpty(fullConfiguration))
                    {
                        string[] typeAndPlatform = fullConfiguration.Split('|');
                        configuration = typeAndPlatform[0];
                        platform      = (typeAndPlatform.Length > 1 ? typeAndPlatform[1] : String.Empty);
                    }
                }

                // write out the platform/configuration defines
                defineConstants[String.Format(CultureInfo.InvariantCulture, "{0}.Configuration", referenceName)]     = configuration;
                defineConstants[String.Format(CultureInfo.InvariantCulture, "{0}.FullConfiguration", referenceName)] = fullConfiguration;
                defineConstants[String.Format(CultureInfo.InvariantCulture, "{0}.Platform", referenceName)]          = platform;

                // write out the ProjectX defines
                defineConstants[String.Format(CultureInfo.InvariantCulture, "{0}.ProjectDir", referenceName)]      = projectDir;
                defineConstants[String.Format(CultureInfo.InvariantCulture, "{0}.ProjectExt", referenceName)]      = projectExt;
                defineConstants[String.Format(CultureInfo.InvariantCulture, "{0}.ProjectFileName", referenceName)] = projectFileName;
                defineConstants[String.Format(CultureInfo.InvariantCulture, "{0}.ProjectName", referenceName)]     = projectName;
                defineConstants[String.Format(CultureInfo.InvariantCulture, "{0}.ProjectPath", referenceName)]     = projectPath;

                // write out the TargetX defines
                string targetDirDefine = String.Format(CultureInfo.InvariantCulture, "{0}.TargetDir", referenceName);
                if (defineConstants.ContainsKey(targetDirDefine))
                {
                    //if target dir was already defined, redefine it as the common root shared by multiple references from the same project
                    string commonDir = FindCommonRoot(targetDir, defineConstants[targetDirDefine]);
                    if (!String.IsNullOrEmpty(commonDir))
                    {
                        targetDir = commonDir;
                    }
                }
                defineConstants[targetDirDefine] = targetDir;

                defineConstants[String.Format(CultureInfo.InvariantCulture, "{0}.TargetExt", referenceName)]      = targetExt;
                defineConstants[String.Format(CultureInfo.InvariantCulture, "{0}.TargetFileName", referenceName)] = targetFileName;
                defineConstants[String.Format(CultureInfo.InvariantCulture, "{0}.TargetName", referenceName)]     = targetName;

                //if target path was already defined, append to it creating a list of multiple references from the same project
                string targetPathDefine = String.Format(CultureInfo.InvariantCulture, "{0}.TargetPath", referenceName);
                if (defineConstants.ContainsKey(targetPathDefine))
                {
                    string oldTargetPath = defineConstants[targetPathDefine];
                    defineConstants[targetPathDefine] += ";" + targetPath;

                    //If there was only one targetpath we need to create it's culture specific define
                    if (!oldTargetPath.Contains(";"))
                    {
                        string oldSubFolder = FindSubfolder(oldTargetPath, targetDir, targetFileName);
                        if (!String.IsNullOrEmpty(oldSubFolder))
                        {
                            defineConstants[String.Format(CultureInfo.InvariantCulture, "{0}.{1}.TargetPath", referenceName, oldSubFolder.Replace('\\', '_'))] = oldTargetPath;
                        }
                    }

                    // Create a culture specific define
                    string subFolder = FindSubfolder(targetPath, targetDir, targetFileName);
                    if (!String.IsNullOrEmpty(subFolder))
                    {
                        defineConstants[String.Format(CultureInfo.InvariantCulture, "{0}.{1}.TargetPath", referenceName, subFolder.Replace('\\', '_'))] = targetPath;
                    }
                }
                else
                {
                    defineConstants[targetPathDefine] = targetPath;
                }
            }

            foreach (KeyValuePair <string, string> define in defineConstants)
            {
                outputItems.Add(new TaskItem(String.Format(CultureInfo.InvariantCulture, "{0}={1}", define.Key, define.Value)));
            }
            this.defineConstants = outputItems.ToArray();

            return(true);
        }