/// <summary>
        /// Called after all output changes occur and right before the output is bound into its final format.
        /// </summary>
        public override void Finish(Output output)
        {
            // Only finish bundles.
            if (OutputType.Bundle != output.Type)
            {
                return;
            }

            this.overallRegid = null; // always reset overall regid on initialize.

            Table tagTable = output.Tables["WixBundleTag"];

            if (null != tagTable)
            {
                Table        table         = output.Tables["WixBundle"];
                WixBundleRow bundleInfo    = (WixBundleRow)table.Rows[0];
                Version      bundleVersion = TagBinder.CreateFourPartVersion(bundleInfo.Version);

                // Try to collect all the software id tags from all the child packages.
                IList <SoftwareTag> allTags = TagBinder.CollectPackageTags(output);

                foreach (Row tagRow in tagTable.Rows)
                {
                    string regid      = (string)tagRow[1];
                    string name       = (string)tagRow[2];
                    bool   licensed   = (null != tagRow[3] && 0 != (int)tagRow[3]);
                    string typeString = (string)tagRow[5];

                    TagType             type          = String.IsNullOrEmpty(typeString) ? TagType.Unknown : (TagType)Enum.Parse(typeof(TagType), typeString);
                    IList <SoftwareTag> containedTags = TagBinder.CalculateContainedTagsAndType(allTags, ref type);

                    using (MemoryStream ms = new MemoryStream())
                    {
                        TagBinder.CreateTagFile(ms, regid, bundleInfo.BundleId.ToString("D").ToUpperInvariant(), bundleInfo.Name, bundleVersion, bundleInfo.Publisher, licensed, type, containedTags);
                        tagRow[4] = Encoding.UTF8.GetString(ms.ToArray());
                    }
                }
            }
        }
        private List <WixFileRow> CreateProductTagFiles(Output output)
        {
            List <WixFileRow> updatedFileRows   = new List <WixFileRow>();
            SourceLineNumber  sourceLineNumbers = null;

            Table tagTable = output.Tables["WixProductTag"];

            if (null != tagTable)
            {
                string  productCode    = null;
                string  productName    = null;
                Version productVersion = null;
                string  manufacturer   = null;

                Table properties = output.Tables["Property"];
                foreach (Row property in properties.Rows)
                {
                    switch ((string)property[0])
                    {
                    case "ProductCode":
                        productCode = (string)property[1];
                        break;

                    case "ProductName":
                        productName = (string)property[1];
                        break;

                    case "ProductVersion":
                        productVersion = TagBinder.CreateFourPartVersion((string)property[1]);
                        break;

                    case "Manufacturer":
                        manufacturer = (string)property[1];
                        break;
                    }
                }

                // If the ProductCode is available, only keep it if it is a GUID.
                if (!String.IsNullOrEmpty(productCode))
                {
                    if (productCode.Equals("*"))
                    {
                        productCode = null;
                    }
                    else
                    {
                        try
                        {
                            Guid guid = new Guid(productCode);
                            productCode = guid.ToString("D").ToUpperInvariant();
                        }
                        catch // not a GUID, erase it.
                        {
                            productCode = null;
                        }
                    }
                }

                Table wixFileTable = output.Tables["WixFile"];
                foreach (Row tagRow in tagTable.Rows)
                {
                    string fileId     = (string)tagRow[0];
                    string regid      = (string)tagRow[1];
                    string name       = (string)tagRow[2];
                    bool   licensed   = (null != tagRow[3] && 1 == (int)tagRow[3]);
                    string typeString = (string)tagRow[4];

                    TagType type     = String.IsNullOrEmpty(typeString) ? TagType.Application : (TagType)Enum.Parse(typeof(TagType), typeString);
                    string  uniqueId = String.IsNullOrEmpty(productCode) ? name.Replace(" ", "-") : productCode;

                    if (String.IsNullOrEmpty(this.overallRegid))
                    {
                        this.overallRegid = regid;
                        sourceLineNumbers = tagRow.SourceLineNumbers;
                    }
                    else if (!this.overallRegid.Equals(regid, StringComparison.Ordinal))
                    {
                        // TODO: display error that only one regid supported.
                    }

                    // Find the WixFileRow that matches for this WixProductTag.
                    foreach (WixFileRow wixFileRow in wixFileTable.Rows)
                    {
                        if (fileId == wixFileRow.File)
                        {
                            // Write the tag file.
                            wixFileRow.Source = Path.GetTempFileName();
                            using (FileStream fs = new FileStream(wixFileRow.Source, FileMode.Create))
                            {
                                TagBinder.CreateTagFile(fs, regid, uniqueId, productName, productVersion, manufacturer, licensed, type, null);
                            }

                            updatedFileRows.Add(wixFileRow); // remember that we modified this file.

                            // Ensure the matching "SoftwareIdentificationTag" row exists and
                            // is populated correctly.
                            Row swidRow;
                            if (!this.swidRows.TryGetValue(fileId, out swidRow))
                            {
                                Table swid = output.Tables["SoftwareIdentificationTag"];
                                swidRow    = swid.CreateRow(wixFileRow.SourceLineNumbers);
                                swidRow[0] = fileId;
                                swidRow[1] = this.overallRegid;

                                this.swidRows.Add(swidRow);
                            }

                            // Always rewrite.
                            swidRow[2] = uniqueId;
                            swidRow[3] = type.ToString();

                            break;
                        }
                    }
                }
            }

            // If we remembered the source line number for the regid, then add
            // a WixVariable to map to the regid.
            if (null != sourceLineNumbers)
            {
                Table          wixVariableTable = output.EnsureTable(this.Core.TableDefinitions["WixVariable"]);
                WixVariableRow wixVariableRow   = (WixVariableRow)wixVariableTable.CreateRow(sourceLineNumbers);
                wixVariableRow.Id          = "WixTagRegid";
                wixVariableRow.Value       = this.overallRegid;
                wixVariableRow.Overridable = false;
            }

            return(updatedFileRows);
        }