private static void SortRoster(SorterConfiguration configuration, TroopRoster troopRoster, ICollection <PartyCharacterVM> partyList, Action <MBBindingList <PartyCharacterVM> > apply)
        {
            FieldInfo troopRosterDataField = troopRoster.GetType().GetField("data", BindingFlags.NonPublic | BindingFlags.Instance);

            TroopRosterElement[] originalTroops = (TroopRosterElement[])troopRosterDataField?.GetValue(troopRoster);
            if (originalTroops == null || originalTroops.All(x => x.Character == null))
            {
                return;
            }

            List <TroopRosterElement> originalTroopList = originalTroops.Where(x => x.Character != null).ToList();
            List <TroopRosterElement> sortedTroops      = originalTroopList.Where(x => !x.Character.IsHero).ToList();
            List <TroopRosterElement> heroTroops        = originalTroopList.Where(x => x.Character.IsHero && !x.Character.IsPlayerCharacter).ToList();
            TroopRosterElement        player            = originalTroopList.FirstOrDefault(x => x.Character.IsPlayerCharacter);

            TroopSorterService.Sort(ref sortedTroops, ref heroTroops, configuration);
            if (heroTroops.Count > 0)
            {
                sortedTroops.InsertRange(0, heroTroops);
            }
            if (player.Character != null)
            {
                sortedTroops.Insert(0, player);
            }
            troopRosterDataField.SetValue(troopRoster, sortedTroops.ToArray());

            List <PartyCharacterVM>          tempTroopList = partyList.ToList();
            MBBindingList <PartyCharacterVM> newTroopList  = new MBBindingList <PartyCharacterVM>();

            partyList.Clear();
            foreach (PartyCharacterVM troop in sortedTroops.Select(sortedTroop => tempTroopList.FirstOrDefault(x => x.Troop.Character.ToString() == sortedTroop.Character.ToString())))
            {
                newTroopList.Add(troop);
            }

            apply(newTroopList);
        }
        public static void Sort(ref List <TroopRosterElement> sortedTroops, ref List <TroopRosterElement> heroTroops, SorterConfiguration configuration)
        {
            sortedTroops = configuration.CurrentThenByMode == SortMode.NONE || configuration.CurrentThenByMode == configuration.CurrentSortByMode
                               ? sortedTroops.SortBy(configuration.CurrentSortByMode, configuration).ToList()
                               : sortedTroops.SortBy(configuration.CurrentSortByMode, configuration)
                           .ThenSortBy(configuration.CurrentThenByMode, configuration)
                           .ToList();
            heroTroops = configuration.CurrentThenByMode == SortMode.NONE || configuration.CurrentThenByMode == configuration.CurrentSortByMode
                             ? heroTroops.SortBy(configuration.CurrentSortByMode, configuration).ToList()
                             : heroTroops.SortBy(configuration.CurrentSortByMode, configuration)
                         .ThenSortBy(configuration.CurrentThenByMode, configuration)
                         .ToList();

            if (!configuration.UpgradableOnTop)
            {
                return;
            }

            // TODO: Re-visit this to use PartyCharacterVM to allow better sorting and upgrade detection
            List <TroopRosterElement> upgradableTroops = sortedTroops.Where(x => x.NumberReadyToUpgrade > 0).ToList();

            upgradableTroops = upgradableTroops.OrderByDescending(x => x.Character.UpgradeRequiresItemFromCategory == null).ToList();
            sortedTroops     = sortedTroops.Where(x => x.NumberReadyToUpgrade <= 0).ToList();
            sortedTroops.InsertRange(0, upgradableTroops);
        }
        public static IOrderedEnumerable <TroopRosterElement> SortBy(this IEnumerable <TroopRosterElement> troops, SortMode sortMode, SorterConfiguration configuration)
        {
            SortDirection sortDirection = configuration.SortDirection;

            return(sortMode switch {
                SortMode.NONE => troops.OrderBy(x => x),
                SortMode.ALPHABETICAL => sortDirection == SortDirection.ASCENDING ? troops.OrderBy(SortAlphabetically) : troops.OrderByDescending(SortAlphabetically),
                SortMode.TYPE => sortDirection == SortDirection.ASCENDING
                                     ? troops.OrderBy(x => x, new TroopTypeComparer(configuration.SortByTypeOrder))
                                     : troops.OrderByDescending(x => x, new TroopTypeComparer(configuration.SortByTypeOrder)),
                SortMode.GROUP => sortDirection == SortDirection.ASCENDING ? troops.OrderBy(SortByGroup) : troops.OrderByDescending(SortByGroup),
                SortMode.TIER => sortDirection == SortDirection.ASCENDING ? troops.OrderBy(SortByTier) : troops.OrderByDescending(SortByTier),
                SortMode.CULTURE => sortDirection == SortDirection.ASCENDING ? troops.OrderBy(SortByCulture) : troops.OrderByDescending(SortByCulture),
                SortMode.COUNT => sortDirection == SortDirection.ASCENDING ? troops.OrderBy(SortByCount) : troops.OrderByDescending(SortByCount),
                _ => throw new ArgumentOutOfRangeException(nameof(sortMode))
            });