public static Dictionary <string, object> CompareRuns(CompareCommandOptions opts)
        {
            if (opts is null)
            {
                throw new ArgumentNullException(nameof(opts));
            }

            if (opts.SaveToDatabase)
            {
                DatabaseManager.InsertCompareRun(opts.FirstRunId, opts.SecondRunId, RUN_STATUS.RUNNING);
            }

            var results = new Dictionary <string, object>();

            comparators = new List <BaseCompare>();

            Dictionary <string, string> EndEvent = new Dictionary <string, string>();
            BaseCompare c     = new BaseCompare();
            var         watch = System.Diagnostics.Stopwatch.StartNew();

            if (!c.TryCompare(opts.FirstRunId, opts.SecondRunId))
            {
                Log.Warning(Strings.Get("Err_Comparing") + " : {0}", c.GetType().Name);
            }

            c.Results.ToList().ForEach(x => results.Add(x.Key, x.Value));

            watch.Stop();
            TimeSpan t      = TimeSpan.FromMilliseconds(watch.ElapsedMilliseconds);
            string   answer = string.Format(CultureInfo.InvariantCulture, "{0:D2}h:{1:D2}m:{2:D2}s:{3:D3}ms",
                                            t.Hours,
                                            t.Minutes,
                                            t.Seconds,
                                            t.Milliseconds);

            Log.Information(Strings.Get("Completed"), "Comparing", answer);

            if (opts.Analyze)
            {
                watch = System.Diagnostics.Stopwatch.StartNew();
                Analyzer analyzer;

                analyzer = new Analyzer(DatabaseManager.RunIdToPlatform(opts.FirstRunId), opts.AnalysesFile);

                if (results.Count > 0)
                {
                    foreach (var key in results.Keys)
                    {
                        try
                        {
                            Parallel.ForEach(results[key] as ConcurrentQueue <CompareResult>, (result) =>
                            {
                                result.Analysis = analyzer.Analyze(result);
                            });
                        }
                        catch (ArgumentNullException)
                        {
                        }
                    }
                }

                watch.Stop();
                t      = TimeSpan.FromMilliseconds(watch.ElapsedMilliseconds);
                answer = string.Format(CultureInfo.InvariantCulture, "{0:D2}h:{1:D2}m:{2:D2}s:{3:D3}ms",
                                       t.Hours,
                                       t.Minutes,
                                       t.Seconds,
                                       t.Milliseconds);
                Log.Information(Strings.Get("Completed"), "Analysis", answer);
            }

            watch = System.Diagnostics.Stopwatch.StartNew();


            if (opts.SaveToDatabase)
            {
                foreach (var key in results.Keys)
                {
                    try
                    {
                        foreach (var result in (results[key] as ConcurrentQueue <CompareResult>))
                        {
                            DatabaseManager.InsertAnalyzed(result);
                        }
                    }
                    catch (NullReferenceException)
                    {
                        Log.Debug(key);
                    }
                }
            }


            watch.Stop();
            t      = TimeSpan.FromMilliseconds(watch.ElapsedMilliseconds);
            answer = string.Format(CultureInfo.InvariantCulture, "{0:D2}h:{1:D2}m:{2:D2}s:{3:D3}ms",
                                   t.Hours,
                                   t.Minutes,
                                   t.Seconds,
                                   t.Milliseconds);
            Log.Information(Strings.Get("Completed"), "Flushing", answer);

            if (opts.SaveToDatabase)
            {
                DatabaseManager.UpdateCompareRun(opts.FirstRunId, opts.SecondRunId, RUN_STATUS.COMPLETED);
            }

            DatabaseManager.Commit();
            AsaTelemetry.TrackEvent("End Command", EndEvent);
            return(results);
        }
        private static int RunExportCollectCommand(ExportCollectCommandOptions opts)
        {
#if DEBUG
            Logger.Setup(true, opts.Verbose, opts.Quiet);
#else
            Logger.Setup(opts.Debug, opts.Verbose, opts.Quiet);
#endif

            if (opts.OutputPath != null && !Directory.Exists(opts.OutputPath))
            {
                Log.Fatal(Strings.Get("Err_OutputPathNotExist"), opts.OutputPath);
                return(0);
            }

            DatabaseManager.Setup(opts.DatabaseFilename);
            CheckFirstRun();
            AsaTelemetry.Setup();
            DatabaseManager.VerifySchemaVersion();

            if (opts.FirstRunId == "Timestamps" || opts.SecondRunId == "Timestamps")
            {
                List <string> runIds = DatabaseManager.GetLatestRunIds(2, "collect");

                if (runIds.Count < 2)
                {
                    Log.Fatal(Strings.Get("Err_CouldntDetermineTwoRun"));
                    System.Environment.Exit(-1);
                }
                else
                {
                    opts.SecondRunId = runIds.First();
                    opts.FirstRunId  = runIds.ElementAt(1);
                }
            }

            Log.Information(Strings.Get("Comparing"), opts.FirstRunId, opts.SecondRunId);

            Dictionary <string, string> StartEvent = new Dictionary <string, string>();
            StartEvent.Add("OutputPathSet", (opts.OutputPath != null).ToString(CultureInfo.InvariantCulture));

            AsaTelemetry.TrackEvent("{0} Export Compare", StartEvent);

            CompareCommandOptions options = new CompareCommandOptions()
            {
                DatabaseFilename = opts.DatabaseFilename,
                FirstRunId       = opts.FirstRunId,
                SecondRunId      = opts.SecondRunId,
                AnalysesFile     = opts.AnalysesFile,
                Analyze          = opts.Analyze,
                SaveToDatabase   = opts.SaveToDatabase
            };

            Dictionary <string, object> results = CompareRuns(options);

            JsonSerializer serializer = JsonSerializer.Create(new JsonSerializerSettings()
            {
                Formatting           = Formatting.Indented,
                NullValueHandling    = NullValueHandling.Ignore,
                DefaultValueHandling = DefaultValueHandling.Ignore,
                Converters           = new List <JsonConverter>()
                {
                    new StringEnumConverter()
                },
                ContractResolver = new AsaExportContractResolver()
            });

            if (opts.ExplodedOutput)
            {
                results.Add("metadata", AsaHelpers.GenerateMetadata());
                string path = Path.Combine(opts.OutputPath, AsaHelpers.MakeValidFileName(opts.FirstRunId + "_vs_" + opts.SecondRunId));
                Directory.CreateDirectory(path);
                foreach (var key in results.Keys)
                {
                    string filePath = Path.Combine(path, AsaHelpers.MakeValidFileName(key));
                    using (StreamWriter sw = new StreamWriter(filePath)) //lgtm[cs/path-injection]
                    {
                        using (JsonWriter writer = new JsonTextWriter(sw))
                        {
                            serializer.Serialize(writer, results[key]);
                        }
                    }
                }
                Log.Information(Strings.Get("OutputWrittenTo"), (new DirectoryInfo(path)).FullName);
            }
            else
            {
                string path   = Path.Combine(opts.OutputPath, AsaHelpers.MakeValidFileName(opts.FirstRunId + "_vs_" + opts.SecondRunId + "_summary.json.txt"));
                var    output = new Dictionary <string, Object>();
                output["results"]  = results;
                output["metadata"] = AsaHelpers.GenerateMetadata();
                using (StreamWriter sw = new StreamWriter(path)) //lgtm[cs/path-injection]
                {
                    using (JsonWriter writer = new JsonTextWriter(sw))
                    {
                        serializer.Serialize(writer, output);
                    }
                }
                Log.Information(Strings.Get("OutputWrittenTo"), (new FileInfo(path)).FullName);
            }
            return(0);
        }