private void WriteSummary(SummaryAnalyzer otherAnalyzer, StreamWriter writer)
        {
            writer.WriteLine("Current Execution Log = {0}", m_analyzer.ExecutionLogPath);
            writer.WriteLine("Previous Execution Log: {0}", otherAnalyzer.ExecutionLogPath);
            writer.WriteLine("Number of Process Pips :  {0}", m_analyzer.GetProcessPipCount());
            writer.WriteLine("Number of executed Process Pips :  {0}", m_analyzer.GetExecutedProcessPipCount());

            var fileDependencyDiff = SummaryAnalyzer.GetFileDependencyDiff(m_analyzer.Summary.FileArtifactSummary, otherAnalyzer.Summary.FileArtifactSummary);

            writer.WriteLine("Number of dependency files with mismatch hash : {0}", fileDependencyDiff.Count());

            var observedDiff = SummaryAnalyzer.GetFileDependencyDiff(m_analyzer.Summary.ObservedSummary, otherAnalyzer.Summary.ObservedSummary);

            writer.WriteLine("Number of observed inputs with mismatch hash : {0}", observedDiff.Count());

            if (m_analyzer.Summary.DirectoryMembership.Count == 0 || otherAnalyzer.Summary.DirectoryMembership.Count == 0)
            {
                var fileName = m_analyzer.Summary.DirectoryMembership.Count == 0 ? m_analyzer.ExecutionLogPath : otherAnalyzer.ExecutionLogPath;
                writer.WriteLine("No directory membership event in execution log : {0}", fileName);
            }
            else
            {
                var directoryMembershipNotInTwo = SummaryAnalyzer.GetDirectoryMembershipDiff(m_analyzer.Summary.DirectoryMembership, otherAnalyzer.Summary.DirectoryMembership);
                var directoryMembershipNotInOne = SummaryAnalyzer.GetDirectoryMembershipDiff(otherAnalyzer.Summary.DirectoryMembership, m_analyzer.Summary.DirectoryMembership);
                writer.WriteLine("Number of directory membership differences : {0}", directoryMembershipNotInTwo.Count() + directoryMembershipNotInOne.Count);
            }

            int produced = m_analyzer.GetProducedFileCount();
            var cached   = m_analyzer.GetCachedFileCount();
            var upToDate = m_analyzer.GetUpToDateFileCount();

            writer.WriteLine("Current XLG Output Files : {0}/{1}/{2}(Produced/FromCache/UpToDate)", produced, cached, upToDate);

            produced = otherAnalyzer.GetProducedFileCount();
            cached   = otherAnalyzer.GetCachedFileCount();
            upToDate = otherAnalyzer.GetUpToDateFileCount();
            writer.WriteLine("Previous XLG Output Files : {0}/{1}/{2}(Produced/FromCache/UpToDate)", produced, cached, upToDate);
            writer.WriteLine();
        }
        /// <summary>
        /// Writes the artifact reason for execution when comparing the two pips into the csv file.
        /// The pips comparared are the roots in order of longest critical path and only its difference is written. No transitive down pips are compared.
        /// </summary>
        private void PrintTransitiveDependenciesImpact(StreamWriter writer)
        {
            var summariesToReport = m_analyzer.GetDifferecesToReport();

            // keep track of distinct dependencies
            var fileArtifacts        = new HashSet <FileArtifactSummary>();
            var environmentVariables = new HashSet <DependencySummary <string> >();
            var observedInputs       = new HashSet <ObservedInputSummary>();

            foreach (var pipDiff in summariesToReport.OrderByDescending(a => a.pipSummary1.CriticalPath.Time))
            {
                var pipSummary      = pipDiff.pipSummary1;
                var otherPipSummary = pipDiff.pipSummary2;

                if (pipSummary.NewPip)
                {
                    continue;
                }

                // TODO: add removed dependencies in output
                if (!pipSummary.Fingerprint.Equals(otherPipSummary.Fingerprint))
                {
                    var filesDiff = SummaryAnalyzer.GetFileDependencyDiff(pipSummary.DependencySummary, otherPipSummary.DependencySummary).ToList();
                    foreach (var item in filesDiff)
                    {
                        if (item.CachedCount > 0)
                        {
                            // This was reported cached in other pips so it has not changed
                            continue;
                        }

                        if (item.OutputOrigin == PipOutputOrigin.Produced || fileArtifacts.Contains(item))
                        {
                            // Output file so not interesting or already written
                            continue;
                        }

                        PrintCsvArtifact(writer, pipSummary, item, "Input", item.GetHashName());
                        fileArtifacts.Add(item);
                    }

                    var environmentDiff = SummaryAnalyzer.GetDependencyDiff(pipSummary.EnvironmentSummary, otherPipSummary.EnvironmentSummary).ToList();
                    foreach (var item in environmentDiff)
                    {
                        if (!environmentVariables.Contains(item))
                        {
                            PrintCsvArtifact(writer, pipSummary, item, "EnvironmentVariable", string.Empty);
                            environmentVariables.Add(item);
                        }
                    }
                }

                var observedDiff = SummaryAnalyzer.GetFileDependencyDiff(pipSummary.ObservedInputSummary, otherPipSummary.ObservedInputSummary).ToList();
                foreach (var item in observedDiff)
                {
                    if (item.CachedCount > 0)
                    {
                        // This was reported cached in other pips so it has not changed
                        continue;
                    }

                    if (!observedInputs.Contains(item))
                    {
                        PrintCsvArtifact(writer, pipSummary, item, "ObservedInput", item.GetHashName());
                        observedInputs.Add(item);
                    }
                }
            }
        }
        /// <summary>
        /// Summary of directory membership differences
        /// </summary>
        internal string CompareDirectoryMembership(SummaryAnalyzer otherSummaryAnalyzer)
        {
            var directoryMembership = otherSummaryAnalyzer.Summary.DirectoryMembership;
            var otherLogPath        = otherSummaryAnalyzer.ExecutionLogPath;

            if (m_analyzer.Summary.DirectoryMembership.Count == 0 || otherSummaryAnalyzer.Summary.DirectoryMembership.Count == 0)
            {
                var fileName = m_analyzer.Summary.DirectoryMembership.Count == 0 ? m_analyzer.ExecutionLogPath : otherLogPath;
                return(string.Format(CultureInfo.InvariantCulture, "No directory membership events in execution log : {0}", fileName));
            }

            // Find the top observed imput directories that have changed and make sure the enumeration is listed
            var observedDiff           = SummaryAnalyzer.GetFileDependencyDiff(m_analyzer.Summary.ObservedSummary, otherSummaryAnalyzer.Summary.ObservedSummary).ToList();
            var count                  = 0;
            var directoriesToEnumerate = new HashSet <string>();

            foreach (var entry in observedDiff)
            {
                if (m_analyzer.Summary.DirectoryMembership.ContainsKey(entry.Name))
                {
                    directoriesToEnumerate.Add(entry.Name);
                }

                if (count++ > m_analyzer.MaxDifferenceReportCount)
                {
                    break;
                }
            }

            var directoryMembershipNotInTwo = SummaryAnalyzer.GetDirectoryMembershipDiff(m_analyzer.Summary.DirectoryMembership, directoryMembership);
            var directoryMembershipNotInOne = SummaryAnalyzer.GetDirectoryMembershipDiff(directoryMembership, m_analyzer.Summary.DirectoryMembership);

            using (var output = new StringWriter(CultureInfo.InvariantCulture))
            {
                var hadOutput = false;
                output.WriteLine("Top Directory Membership Differences:");
                output.WriteLine("Current Execution Log = {0}", m_analyzer.ExecutionLogPath);
                output.WriteLine("Previous Execution Log = {0}", otherLogPath);
                output.WriteLine("Directory  |  Current Execution Log   | Previous Execution Log");

                int outReportCount = 0;

                // Enumerate changes in observed inputs first to show those relevant changes
                foreach (var directory in directoriesToEnumerate)
                {
                    List <string> entry;
                    if (directoryMembershipNotInTwo.TryGetValue(directory, out entry))
                    {
                        hadOutput = PrintDirectoryEnumeration(output, directory, entry);
                        if (outReportCount++ > m_analyzer.MaxDifferenceReportCount)
                        {
                            break;
                        }
                    }
                }

                foreach (var s in directoryMembershipNotInTwo)
                {
                    if (directoriesToEnumerate.Contains(s.Key))
                    {
                        continue;
                    }

                    hadOutput = PrintDirectoryEnumeration(output, s.Key, s.Value);
                    if (outReportCount++ > m_analyzer.MaxDifferenceReportCount)
                    {
                        break;
                    }
                }

                foreach (var s in directoryMembershipNotInOne)
                {
                    hadOutput = PrintDirectoryEnumeration(output, s.Key, s.Value);
                    if (outReportCount++ > m_analyzer.MaxDifferenceReportCount)
                    {
                        break;
                    }
                }

                return(hadOutput ? output.ToString() : "Directory Membership Differences: none");
            }
        }