public static void DoWork(OperationController operation)
        {
            System.Globalization.CultureInfo before = Thread.CurrentThread.CurrentCulture;
            Thread.CurrentThread.CurrentCulture =
                new System.Globalization.CultureInfo("en-US");
            operation.Reset();
            var sw = new Stopwatch();

            try
            {
                sw.Start();
                var fInfo = new FileInfo(operation.InputFile);

                var parser = new EvtcParser(new EvtcParserSettings(Properties.Settings.Default.Anonymous,
                                                                   Properties.Settings.Default.SkipFailedTries,
                                                                   Properties.Settings.Default.ParsePhases,
                                                                   Properties.Settings.Default.ParseCombatReplay,
                                                                   Properties.Settings.Default.ComputeDamageModifiers,
                                                                   Properties.Settings.Default.CustomTooShort,
                                                                   Properties.Settings.Default.DetailledWvW),
                                            APIController);

                //Process evtc here
                ParsedEvtcLog log = parser.ParseLog(operation, fInfo, out GW2EIEvtcParser.ParserHelpers.ParsingFailureReason failureReason);
                if (failureReason != null)
                {
                    failureReason.Throw();
                }
                var      externalTraces = new List <string>();
                string[] uploadresult   = UploadOperation(externalTraces, fInfo);
                if (Properties.Settings.Default.SendEmbedToWebhook && Properties.Settings.Default.UploadToDPSReports)
                {
                    var webhookSettings = new WebhookSettings(Properties.Settings.Default.WebhookURL, !Properties.Settings.Default.SendSimpleMessageToWebhook ? BuildEmbed(log, uploadresult[0]) : null);
                    WebhookController.SendMessage(externalTraces, uploadresult[0], webhookSettings);
                }
                foreach (string trace in externalTraces)
                {
                    operation.UpdateProgress(trace);
                }
                if (uploadresult[0].Contains("https"))
                {
                    operation.DPSReportLink = uploadresult[0];
                }
                //Creating File
                GenerateFiles(log, operation, uploadresult, fInfo);
            }
            catch (Exception ex)
            {
                throw new ProgramException(ex);
            }
            finally
            {
                sw.Stop();
                GC.Collect();
                Thread.CurrentThread.CurrentCulture = before;
                operation.Elapsed = ("Elapsed " + sw.ElapsedMilliseconds + " ms");
            }
        }
        private string DiscordBatch(out List <ulong> ids)
        {
            ids = new List <ulong>();
            AddTraceMessage("Sending batch to Discord");
            if (Properties.Settings.Default.WebhookURL == null)
            {
                return("Set a discord webhook url in settings first");
            }
            var fullDpsReportLogs = new List <FormOperationController>();

            foreach (FormOperationController operation in OperatorBindingSource)
            {
                if (operation.DPSReportLink != null && operation.DPSReportLink.Contains("https"))
                {
                    fullDpsReportLogs.Add(operation);
                }
            }
            if (!fullDpsReportLogs.Any())
            {
                return("Nothing to send");
            }
            // first sort by time
            fullDpsReportLogs.Sort((x, y) =>
            {
                return(DateTime.Parse(x.BasicMetaData.LogStart).CompareTo(DateTime.Parse(y.BasicMetaData.LogStart)));
            });
            var fullDpsReportsLogsByDate = fullDpsReportLogs.GroupBy(x => DateTime.Parse(x.BasicMetaData.LogStart).Date).ToDictionary(x => x.Key, x => x.ToList());
            // split the logs so that a single embed does not reach the discord embed limit and also keep a reasonable size by embed
            string message = "";
            bool   start   = true;

            foreach (KeyValuePair <DateTime, List <FormOperationController> > pair in fullDpsReportsLogsByDate)
            {
                if (!start)
                {
                    message += "\r\n";
                }
                start = false;
                var splitDpsReportLogs = new List <List <FormOperationController> >()
                {
                    new List <FormOperationController>()
                };
                message += pair.Key.ToString("yyyy-MM-dd") + " - ";
                List <FormOperationController> curListToFill = splitDpsReportLogs.First();
                foreach (FormOperationController controller in pair.Value)
                {
                    if (curListToFill.Count < 40)
                    {
                        curListToFill.Add(controller);
                    }
                    else
                    {
                        curListToFill = new List <FormOperationController>()
                        {
                            controller
                        };
                        splitDpsReportLogs.Add(curListToFill);
                    }
                }
                foreach (List <FormOperationController> dpsReportLogs in splitDpsReportLogs)
                {
                    EmbedBuilder embedBuilder = ProgramHelper.GetEmbedBuilder();
                    embedBuilder.WithCurrentTimestamp();
                    embedBuilder.WithFooter(pair.Key.ToString("yyyy-MM-dd"));
                    dpsReportLogs.Sort((x, y) =>
                    {
                        var categoryCompare = x.BasicMetaData.FightCategory.CompareTo(y.BasicMetaData.FightCategory);
                        if (categoryCompare == 0)
                        {
                            return(DateTime.Parse(x.BasicMetaData.LogStart).CompareTo(DateTime.Parse(y.BasicMetaData.LogStart)));
                        }
                        return(categoryCompare);
                    });
                    string currentSubCategory = "";
                    var    embedFieldBuilder  = new EmbedFieldBuilder();
                    var    fieldValue         = "I can not be empty";
                    foreach (FormOperationController controller in dpsReportLogs)
                    {
                        string subCategory = controller.BasicMetaData.FightCategory.GetSubCategoryName();
                        string toAdd       = "[" + controller.BasicMetaData.FightName + "](" + controller.DPSReportLink + ") " + (controller.BasicMetaData.FightSuccess ? " :white_check_mark: " : " :x: ") + ": " + controller.BasicMetaData.FightDuration;
                        if (subCategory != currentSubCategory)
                        {
                            embedFieldBuilder.WithValue(fieldValue);
                            embedFieldBuilder = new EmbedFieldBuilder();
                            fieldValue        = "";
                            embedBuilder.AddField(embedFieldBuilder);
                            embedFieldBuilder.WithName(subCategory);
                            currentSubCategory = subCategory;
                        }
                        else if (fieldValue.Length + toAdd.Length > 1024)
                        {
                            embedFieldBuilder.WithValue(fieldValue);
                            embedFieldBuilder = new EmbedFieldBuilder();
                            fieldValue        = "";
                            embedBuilder.AddField(embedFieldBuilder);
                        }
                        else
                        {
                            fieldValue += "\r\n";
                        }
                        fieldValue += toAdd;
                    }
                    embedFieldBuilder.WithValue(fieldValue);
                    ids.Add(WebhookController.SendMessage(Properties.Settings.Default.WebhookURL, embedBuilder.Build(), out string curMessage));
                    message += curMessage + " - ";
                }
            }
            return(message);
        }
        private static void GenerateFiles(ParsedLog log, OperationController operation, string[] uploadresult, FileInfo fInfo)
        {
            operation.UpdateProgressWithCancellationCheck("Creating File(s)");

            DirectoryInfo saveDirectory = GetSaveDirectory(fInfo);

            string result = log.FightData.Success ? "kill" : "fail";
            string encounterLengthTerm = Properties.Settings.Default.AddDuration ? "_" + (log.FightData.FightEnd / 1000).ToString() + "s" : "";
            string PoVClassTerm        = Properties.Settings.Default.AddPoVProf ? "_" + log.LogData.PoV.Prof.ToLower() : "";
            string fName = fInfo.Name.Split('.')[0];

            fName = $"{fName}{PoVClassTerm}_{log.FightData.Logic.Extension}{encounterLengthTerm}_{result}";

            // parallel stuff
            if (log.ParserSettings.MultiTasks)
            {
                log.FightData.GetPhases(log);
                operation.UpdateProgressWithCancellationCheck("Multi threading");
                var playersAndTargets = new List <AbstractSingleActor>(log.PlayerList);
                playersAndTargets.AddRange(log.FightData.Logic.Targets);
                foreach (AbstractSingleActor actor in playersAndTargets)
                {
                    // that part can't be //
                    actor.ComputeBuffMap(log);
                }
                if (log.CanCombatReplay)
                {
                    var playersAndTargetsAndMobs = new List <AbstractSingleActor>(log.FightData.Logic.TrashMobs);
                    playersAndTargetsAndMobs.AddRange(playersAndTargets);
                    // init all positions
                    Parallel.ForEach(playersAndTargetsAndMobs, actor => actor.GetCombatReplayPolledPositions(log));
                }
                else if (log.CombatData.HasMovementData)
                {
                    Parallel.ForEach(log.PlayerList, player => player.GetCombatReplayPolledPositions(log));
                }
                Parallel.ForEach(playersAndTargets, actor => actor.GetBuffGraphs(log));
                //
                Parallel.ForEach(log.PlayerList, player => player.GetDamageModifierStats(log, null));
                // once simulation is done, computing buff stats is thread safe
                Parallel.ForEach(log.PlayerList, player => player.GetBuffs(log, BuffEnum.Self));
                Parallel.ForEach(log.FightData.Logic.Targets, target => target.GetBuffs(log));
            }
            if (Properties.Settings.Default.SaveOutHTML)
            {
                operation.UpdateProgressWithCancellationCheck("Creating HTML");
                string outputFile = Path.Combine(
                    saveDirectory.FullName,
                    $"{fName}.html"
                    );
                operation.GeneratedFiles.Add(outputFile);
                operation.PathsToOpen.Add(outputFile);
                using (var fs = new FileStream(outputFile, FileMode.Create, FileAccess.Write))
                    using (var sw = new StreamWriter(fs))
                    {
                        var builder = new HTMLBuilder(log, uploadresult, Properties.Settings.Default.LightTheme, Properties.Settings.Default.HtmlExternalScripts);
                        builder.CreateHTML(sw, saveDirectory.FullName);
                    }
                operation.UpdateProgressWithCancellationCheck("HTML created");
            }
            if (Properties.Settings.Default.SaveOutCSV)
            {
                operation.UpdateProgressWithCancellationCheck("Creating CSV");
                string outputFile = Path.Combine(
                    saveDirectory.FullName,
                    $"{fName}.csv"
                    );
                operation.GeneratedFiles.Add(outputFile);
                operation.PathsToOpen.Add(outputFile);
                using (var fs = new FileStream(outputFile, FileMode.Create, FileAccess.Write))
                    using (var sw = new StreamWriter(fs, Encoding.GetEncoding(1252)))
                    {
                        var builder = new CSVBuilder(sw, ",", log, uploadresult);
                        builder.CreateCSV();
                    }
                operation.UpdateProgressWithCancellationCheck("CSV created");
            }
            if (Properties.Settings.Default.SaveOutJSON || Properties.Settings.Default.SaveOutXML)
            {
                var builder = new RawFormatBuilder(log, uploadresult);
                if (Properties.Settings.Default.SaveOutJSON)
                {
                    operation.UpdateProgressWithCancellationCheck("Creating JSON");
                    string outputFile = Path.Combine(
                        saveDirectory.FullName,
                        $"{fName}.json"
                        );
                    operation.PathsToOpen.Add(saveDirectory.FullName);
                    Stream str;
                    if (Properties.Settings.Default.CompressRaw)
                    {
                        str = new MemoryStream();
                    }
                    else
                    {
                        str = new FileStream(outputFile, FileMode.Create, FileAccess.Write);
                    }
                    using (var sw = new StreamWriter(str, GeneralHelper.NoBOMEncodingUTF8))
                    {
                        builder.CreateJSON(sw, Properties.Settings.Default.IndentJSON);
                    }
                    if (str is MemoryStream msr)
                    {
                        CompressFile(outputFile, msr, operation);
                        operation.UpdateProgressWithCancellationCheck("JSON compressed");
                    }
                    else
                    {
                        operation.GeneratedFiles.Add(outputFile);
                    }
                    operation.UpdateProgressWithCancellationCheck("JSON created");
                }
                if (Properties.Settings.Default.SaveOutXML)
                {
                    operation.UpdateProgressWithCancellationCheck("Creating XML");
                    string outputFile = Path.Combine(
                        saveDirectory.FullName,
                        $"{fName}.xml"
                        );
                    operation.PathsToOpen.Add(saveDirectory.FullName);
                    Stream str;
                    if (Properties.Settings.Default.CompressRaw)
                    {
                        str = new MemoryStream();
                    }
                    else
                    {
                        str = new FileStream(outputFile, FileMode.Create, FileAccess.Write);
                    }
                    using (var sw = new StreamWriter(str, GeneralHelper.NoBOMEncodingUTF8))
                    {
                        builder.CreateXML(sw, Properties.Settings.Default.IndentXML);
                    }
                    if (str is MemoryStream msr)
                    {
                        CompressFile(outputFile, msr, operation);
                        operation.UpdateProgressWithCancellationCheck("XML compressed");
                    }
                    else
                    {
                        operation.GeneratedFiles.Add(outputFile);
                    }
                    operation.UpdateProgressWithCancellationCheck("XML created");
                }
            }

            if (Properties.Settings.Default.SendEmbedToWebhook && Properties.Settings.Default.UploadToDPSReports && !Properties.Settings.Default.ParseMultipleLogs)
            {
                WebhookController.SendMessage(log, uploadresult);
            }
            operation.UpdateProgress($"Completed parsing for {result}ed {log.FightData.Logic.Extension}");
        }