public async Task VerifySkorpyronHits()
        {
            var requestTemplate = new FightRequestTemplate("test", "reports/table/damage-taken/" + RequestWildcard.ReportId.Key + "/" + RequestWildcard.FightId.Key + "/" + RequestWildcard.FightStart.Key + "/" + RequestWildcard.FightEnd.Key + "/source/0/0/0/0/0/210074/-1.0.-1/0/Any/Any/2/1849?pins=2%24Off%24%23244F4B%24auras-gained%240%240.0.0.Any%240.0.0.Any%24true%240.0.0.Any%24true%24204284%24false%24false%2464&");
            var provider        = new GenericHitDetectionParser(requestTemplate);
            var context         = new FightContextData();

            context.ReportId = "ha6AMNZcYjBr3tbW";
            context.Fight    = new Fight()
            {
                id         = 2,
                start_time = 250751,
                end_time   = 642520,
            };


            var result = await provider.GetResultsAsync(context);

            Assert.That(result.Count, Is.EqualTo(5));

            Assert.That(result.FirstOrDefault(d => d.PlayerName == "Nullidan"), Is.Not.Null);
            Assert.That(result.FirstOrDefault(d => d.PlayerName == "Nullidan")?.TotalDamage, Is.EqualTo(2230363));
            Assert.That(result.FirstOrDefault(d => d.PlayerName == "Nullidan")?.AverageHitDamage, Is.EqualTo(1115181).Within(1));
            Assert.That(result.FirstOrDefault(d => d.PlayerName == "Nullidan")?.Casts, Is.EqualTo(6));
            Assert.That(result.FirstOrDefault(d => d.PlayerName == "Nullidan")?.Hits, Is.EqualTo(2));

            Assert.That(result.FirstOrDefault(d => d.PlayerName == "Abatuu"), Is.Not.Null);
            Assert.That(result.FirstOrDefault(d => d.PlayerName == "Abatuu")?.TotalDamage, Is.EqualTo(2164916));
            Assert.That(result.FirstOrDefault(d => d.PlayerName == "Abatuu")?.AverageHitDamage, Is.EqualTo(1082458).Within(1));
            Assert.That(result.FirstOrDefault(d => d.PlayerName == "Abatuu")?.Casts, Is.EqualTo(6));
            Assert.That(result.FirstOrDefault(d => d.PlayerName == "Abatuu")?.Hits, Is.EqualTo(2));

            Assert.That(result.FirstOrDefault(d => d.PlayerName == "Syrolyn"), Is.Not.Null);
            Assert.That(result.FirstOrDefault(d => d.PlayerName == "Syrolyn")?.TotalDamage, Is.EqualTo(1224738));
            Assert.That(result.FirstOrDefault(d => d.PlayerName == "Syrolyn")?.AverageHitDamage, Is.EqualTo(1224738).Within(1));
            Assert.That(result.FirstOrDefault(d => d.PlayerName == "Syrolyn")?.Casts, Is.EqualTo(6));
            Assert.That(result.FirstOrDefault(d => d.PlayerName == "Syrolyn")?.Hits, Is.EqualTo(1));

            Assert.That(result.FirstOrDefault(d => d.PlayerName == "Nubbadin"), Is.Not.Null);
            Assert.That(result.FirstOrDefault(d => d.PlayerName == "Nubbadin")?.TotalDamage, Is.EqualTo(1106572));
            Assert.That(result.FirstOrDefault(d => d.PlayerName == "Nubbadin")?.AverageHitDamage, Is.EqualTo(1106572).Within(1));
            Assert.That(result.FirstOrDefault(d => d.PlayerName == "Nubbadin")?.Casts, Is.EqualTo(6));
            Assert.That(result.FirstOrDefault(d => d.PlayerName == "Nubbadin")?.Hits, Is.EqualTo(1));

            Assert.That(result.FirstOrDefault(d => d.PlayerName == "Gorkow"), Is.Not.Null);
            Assert.That(result.FirstOrDefault(d => d.PlayerName == "Gorkow")?.TotalDamage, Is.EqualTo(975301));
            Assert.That(result.FirstOrDefault(d => d.PlayerName == "Gorkow")?.AverageHitDamage, Is.EqualTo(975301).Within(1));
            Assert.That(result.FirstOrDefault(d => d.PlayerName == "Gorkow")?.Casts, Is.EqualTo(6));
            Assert.That(result.FirstOrDefault(d => d.PlayerName == "Gorkow")?.Hits, Is.EqualTo(1));
        }
        public async Task GetScorpyronReportResults()
        {
            // https://www.warcraftlogs.com/reports/table/damage-taken/ha6AMNZcYjBr3tbW/2/250751/642520/source/0/0/0/0/0/0/-1.0.-1/0/Any/Any/2/1849?pins=2%24Off%24%23244F4B%24auras-gained%240%240.0.0.Any%240.0.0.Any%24true%240.0.0.Any%24true%24204284%24false%24false%2464&
            var template = new FightRequestTemplate("test", $"reports/table/damage-taken/{RequestWildcard.ReportId.Key}/{RequestWildcard.FightId.Key}/{RequestWildcard.FightStart.Key}/{RequestWildcard.FightEnd.Key}/source/0/0/0/0/0/0/-1.0.-1/0/Any/Any/2/1849?pins=2%24Off%24%23244F4B%24auras-gained%240%240.0.0.Any%240.0.0.Any%24true%240.0.0.Any%24true%24204284%24false%24false%2464&");

            var provider = new GenericDamageTakenParser(template);
            var context  = new FightContextData();

            context.ReportId = "ha6AMNZcYjBr3tbW";
            context.Fight    = new Fight()
            {
                id         = 2,
                start_time = 250751,
                end_time   = 642520,
            };
            var results = await provider.GetResultsAsync(context);


            Assert.That(results, Is.Not.Null);
            Assert.That(results.Count, Is.EqualTo(20));

            var example = results.FirstOrDefault(d => d.PlayerName == "Tremendous");

            Assert.That(example, Is.Not.Null);
            Assert.That(example.DTPS, Is.EqualTo(484996.7).Within(0.1));
            Assert.That(example.PlayerId, Is.EqualTo(7));
            Assert.That(example.PercentageTaken, Is.EqualTo(14.85).Within(0.01));

            Assert.That(example.Abilities.Count, Is.EqualTo(5));

            Assert.That(example.Abilities.FirstOrDefault(d => d.Name == "Arcanoslash")?.Amount, Is.EqualTo(41670000).Within(10000));

            Assert.That(example.Abilities.FirstOrDefault(d => d.Name == "Melee")?.Percentage, Is.EqualTo(43.14).Within(0.01));
            Assert.That(example.Abilities.FirstOrDefault(d => d.Name == "Arcanoslash")?.Percentage, Is.EqualTo(21.93).Within(0.01));
            Assert.That(example.Abilities.FirstOrDefault(d => d.Name == "Arcane Tether")?.Percentage, Is.EqualTo(9.96).Within(0.01));
            Assert.That(example.Abilities.FirstOrDefault(d => d.Name == "Acidic Fragments")?.Percentage, Is.EqualTo(8.85).Within(0.01));
            Assert.That(example.Abilities.FirstOrDefault(d => d.Name == "Toxic Chitin")?.Percentage, Is.EqualTo(4.49).Within(0.01));


            Assert.That(example.Sources.Count, Is.EqualTo(5));

            Assert.That(example.Sources.FirstOrDefault(d => d.Name == "Environment")?.Amount, Is.EqualTo(27460000).Within(10000));

            Assert.That(example.Sources.FirstOrDefault(d => d.Name == "Skorpyron")?.Percentage, Is.EqualTo(67.59).Within(0.01));
            Assert.That(example.Sources.FirstOrDefault(d => d.Name == "Environment")?.Percentage, Is.EqualTo(14.45).Within(0.01));
            Assert.That(example.Sources.FirstOrDefault(d => d.Name == "Crystalline Scorpid")?.Percentage, Is.EqualTo(7.21).Within(0.01));
            Assert.That(example.Sources.FirstOrDefault(d => d.Name == "Volatile Scorpid")?.Percentage, Is.EqualTo(3.59).Within(0.01));
            Assert.That(example.Sources.FirstOrDefault(d => d.Name == "Acidmaw Scorpid")?.Percentage, Is.EqualTo(2.98).Within(0.01));
        }
        public void VerifyResolution()
        {
            var context = new FightContextData()
            {
                Fight = new Fight()
                {
                    end_time   = 500,
                    start_time = 100
                },
                ReportId = "wasd"
            };

            var template   = new FightRequestTemplate(string.Empty, $"test/{RequestWildcard.ReportId.Key}/{RequestWildcard.FightStart.Key}/{RequestWildcard.FightEnd.Key}");
            var resolution = FightRequestTemplateResolver.Resolve(template, context);

            Assert.That(resolution.ResolvedTemplate, Is.EqualTo("test/wasd/100/500"));
            Assert.That(resolution.MappingValues[RequestWildcard.ReportId], Is.EqualTo("wasd"));
            Assert.That(resolution.MappingValues[RequestWildcard.FightStart], Is.EqualTo("100"));
            Assert.That(resolution.MappingValues[RequestWildcard.FightEnd], Is.EqualTo("500"));
        }
        private async Task LoadImplAsync(IProgress <string> progress, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            await Task.Delay(2000);

            cancellationToken.ThrowIfCancellationRequested();

            var provider = new ReportDataProvider();

            progress.Report($"Kampfdaten für {BossName} werden geladen.");
            var reportData = await provider.GetReportDataAsync(ReportId);

            var matchingFights = reportData.fights.Where(d => d.name.ToUpper() == BossName.ToUpper()).ToList();

            progress.Report($"{matchingFights.Count} Kämpfe gefunden.");
            await Task.Delay(1000);

            cancellationToken.ThrowIfCancellationRequested();

            var templates = Configuration.Templates.ToList();

            progress.Report($"{templates.Count} Auswertungsfelder gefunden.");
            await Task.Delay(1000);

            Dictionary <string, object>          tokenValueByPlayer = new Dictionary <string, object>();
            Dictionary <string, DynamicGridCell> cellByPlayer       = new Dictionary <string, DynamicGridCell>();

            var players = new HashSet <string>(reportData.friendlies.Select(s => s.name));

            foreach (var player in players)
            {
                var playerCell = new DynamicGridCell();
                playerCell["Spieler"] = player;
                cellByPlayer.Add(player, playerCell);
            }

            foreach (var template in templates)
            {
                tokenValueByPlayer.Clear();

                cancellationToken.ThrowIfCancellationRequested();

                var parser = ParserFactory.GetParser(template.ParserTypeName);
                parser.SetTemplate(template.Template);
//				var warcraftLogsContentParser = new GenericDamageTakenParser();
//				await warcraftLogsContentParser.GetResultsAsync(new FightContextData());
//				parser = warcraftLogsContentParser;
                foreach (var fight in matchingFights)
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    var fightContext = new FightContextData()
                    {
                        Fight = fight, ReportId = ReportId
                    };
                    await parser.ApplyResultMappingAsync(cancellationToken, fightContext, tokenValueByPlayer, template.FieldWildcard);
                }

                foreach (var playerWithTokenValue in tokenValueByPlayer)
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    DynamicGridCell cell;
                    if (cellByPlayer.TryGetValue(playerWithTokenValue.Key, out cell))
                    {
                        cell[template.FieldWildcard] = playerWithTokenValue.Value;
                    }
                }
            }

            var cells = new List <KeyValuePair <string, DynamicGridCell> >();

            foreach (var cell in cellByPlayer)
            {
                cells.Add(cell);
            }

            await Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
                                                                                                   ResultData.AddRange(cells.Select(s => s.Value))));
        }