//
        protected static List <AbstractBuffEvent> GetFilteredList(CombatData combatData, long buffID, AbstractSingleActor target, bool beginWithStart)
        {
            bool needStart = beginWithStart;
            var  main      = combatData.GetBuffData(buffID).Where(x => x.To == target.AgentItem && (x is BuffApplyEvent || x is BuffRemoveAllEvent)).ToList();
            var  filtered  = new List <AbstractBuffEvent>();

            for (int i = 0; i < main.Count; i++)
            {
                AbstractBuffEvent c = main[i];
                if (needStart && c is BuffApplyEvent)
                {
                    needStart = false;
                    filtered.Add(c);
                }
                else if (!needStart && c is BuffRemoveAllEvent)
                {
                    // consider only last remove event before another application
                    if ((i == main.Count - 1) || (i < main.Count - 1 && main[i + 1] is BuffApplyEvent))
                    {
                        needStart = true;
                        filtered.Add(c);
                    }
                }
            }
            return(filtered);
        }
        private void SolveWvWPlayers(AgentData agentData, List <CombatItem> combatData, IReadOnlyDictionary <uint, AbstractExtensionHandler> extensions)
        {
            IReadOnlyList <AgentItem> aList = agentData.GetAgentByType(AgentItem.AgentType.NonSquadPlayer);
            var set            = new HashSet <string>();
            var toRemove       = new HashSet <AgentItem>();
            var garbageList    = new List <AbstractSingleActor>();
            var teamChangeDict = combatData.Where(x => x.IsStateChange == ArcDPSEnums.StateChange.TeamChange).GroupBy(x => x.SrcAgent).ToDictionary(x => x.Key, x => x.ToList());
            //
            IReadOnlyList <AgentItem> squadPlayers = agentData.GetAgentByType(AgentItem.AgentType.Player);
            ulong greenTeam  = ulong.MaxValue;
            var   greenTeams = new List <ulong>();

            foreach (AgentItem a in squadPlayers)
            {
                if (teamChangeDict.TryGetValue(a.Agent, out List <CombatItem> teamChangeList))
                {
                    greenTeams.AddRange(teamChangeList.Where(x => x.SrcMatchesAgent(a)).Select(x => x.DstAgent));
                }
            }
            if (greenTeams.Any())
            {
                greenTeam = greenTeams.GroupBy(x => x).OrderByDescending(x => x.Count()).Select(x => x.Key).First();
            }
            var playersToMerge         = new Dictionary <PlayerNonSquad, AbstractSingleActor>();
            var agentsToPlayersToMerge = new Dictionary <ulong, PlayerNonSquad>();

            //
            foreach (AgentItem a in aList)
            {
                if (teamChangeDict.TryGetValue(a.Agent, out List <CombatItem> teamChangeList))
                {
                    a.OverrideIsNotInSquadFriendlyPlayer(teamChangeList.Where(x => x.SrcMatchesAgent(a)).Select(x => x.DstAgent).Any(x => x == greenTeam));
                }
                List <AbstractSingleActor> actorListToFill = a.IsNotInSquadFriendlyPlayer ? _nonPlayerFriendlies : _detailed ? _targets : garbageList;
                var nonSquadPlayer = new PlayerNonSquad(a);
                if (!set.Contains(nonSquadPlayer.Character))
                {
                    actorListToFill.Add(nonSquadPlayer);
                    set.Add(nonSquadPlayer.Character);
                }
                else
                {
                    // we merge
                    AbstractSingleActor mainPlayer = actorListToFill.FirstOrDefault(x => x.Character == nonSquadPlayer.Character);
                    playersToMerge[nonSquadPlayer] = mainPlayer;
                    agentsToPlayersToMerge[nonSquadPlayer.AgentItem.Agent] = nonSquadPlayer;
                }
            }
            if (playersToMerge.Any())
            {
                foreach (CombatItem c in combatData)
                {
                    if (agentsToPlayersToMerge.TryGetValue(c.SrcAgent, out PlayerNonSquad nonSquadPlayer) && c.SrcMatchesAgent(nonSquadPlayer.AgentItem, extensions))
                    {
                        AbstractSingleActor mainPlayer = playersToMerge[nonSquadPlayer];
                        c.OverrideSrcAgent(mainPlayer.AgentItem.Agent);
                    }
                    if (agentsToPlayersToMerge.TryGetValue(c.DstAgent, out nonSquadPlayer) && c.DstMatchesAgent(nonSquadPlayer.AgentItem, extensions))
                    {
                        AbstractSingleActor mainPlayer = playersToMerge[nonSquadPlayer];
                        c.OverrideDstAgent(mainPlayer.AgentItem.Agent);
                    }
                }
                foreach (KeyValuePair <PlayerNonSquad, AbstractSingleActor> pair in playersToMerge)
                {
                    PlayerNonSquad      nonSquadPlayer = pair.Key;
                    AbstractSingleActor mainPlayer     = pair.Value;
                    agentData.SwapMasters(nonSquadPlayer.AgentItem, mainPlayer.AgentItem);
                    mainPlayer.AgentItem.OverrideAwareTimes(Math.Min(nonSquadPlayer.FirstAware, mainPlayer.FirstAware), Math.Max(nonSquadPlayer.LastAware, mainPlayer.LastAware));
                    toRemove.Add(nonSquadPlayer.AgentItem);
                }
            }
            agentData.RemoveAllFrom(toRemove);
        }
        internal EXTFinalIncomingHealingStat(ParsedEvtcLog log, long start, long end, AbstractSingleActor actor, AbstractSingleActor target)
        {
            foreach (EXTAbstractHealingEvent healingEvent in actor.EXTHealing.GetIncomingHealEvents(target, log, start, end))
            {
                Healed += healingEvent.HealingDone;
                switch (healingEvent.GetHealingType(log))
                {
                case EXTHealingType.ConversionBased:
                    ConversionHealed += healingEvent.HealingDone;
                    break;

                case EXTHealingType.Hybrid:
                    HybridHealed += healingEvent.HealingDone;
                    break;

                case EXTHealingType.HealingPower:
                    HealingPowerHealed += healingEvent.HealingDone;
                    break;

                default:
                    break;
                }
                if (healingEvent.AgainstDowned)
                {
                    DownedHealed += healingEvent.HealingDone;
                }
            }
        }