/// <summary>
        /// <para>Load all data required for calculating the statistics from the database.</para>
        /// <para>Must be called prior to <see cref="Calculate"/> if lazy loading is disabled!</para>
        /// </summary>
        /// <param name="dbContext">Database context from EntityFramework.</param>
        /// <param name="force">Force loading data again even if IsDataLoaded is true.</param>
        public virtual async Task LoadRequiredDataAsync(LeagueDbContext dbContext, bool force = false)
        {
            if (DriverStatistic == null || DriverStatistic.Count == 0)
            {
                await dbContext.Entry(this)
                .Collection(x => x.DriverStatistic)
                .LoadAsync();

                var memberIds  = DriverStatistic.Select(x => x.MemberId);
                var sessionIds = DriverStatistic
                                 .SelectMany(x => new long?[] { x.FirstSessionId, x.LastSessionId, x.FirstRaceId, x.LastRaceId })
                                 .Where(x => x != null)
                                 .Select(x => x.Value);
                var resultRowIds = DriverStatistic
                                   .SelectMany(x => new long?[] { x.FirstResultRowId, x.LastResultRowId })
                                   .Where(x => x != null)
                                   .Select(x => x.Value);

                await dbContext.Set <LeagueMemberEntity>()
                .Where(x => memberIds.Contains(x.MemberId))
                .LoadAsync();

                await dbContext.Set <SessionBaseEntity>()
                .Where(x => sessionIds.Contains(x.SessionId))
                .LoadAsync();

                await dbContext.Set <ResultRowEntity>()
                .Where(x => resultRowIds.Contains(x.ResultRowId))
                .LoadAsync();

                dbContext.ChangeTracker.DetectChanges();
            }
        }
Example #2
0
        public override void Calculate(LeagueDbContext dbContext)
        {
            if (ScoringTable == null)
            {
                return;
            }

            // Get standings
            var standings = ScoringTable.GetSeasonStandings(dbContext);

            // Get all connected scorings
            var scorings = ScoringTable.Scorings;

            // Get all scored races
            var scoredRaces = scorings.SelectMany(x => x.GetAllSessions().Where(y => y.SessionResult != null).Select(y => new { x, y })).GroupBy(x => x.x, x => x.y);

            // Get races that need recalculation and recalculate results
            scoredRaces.ForEach(x => x.Where(y => y.SessionResult.RequiresRecalculation).ForEach(y => x.Key.CalculateResults(y.SessionId, dbContext)));

            // Get all scored resultrows and group by driver
            var scoredResultsRows = scorings.SelectMany(x => x.ScoredResults).SelectMany(x => x.FinalResults).OrderBy(x => x.ResultRow.Date).GroupBy(x => x.ResultRow.Member);

            if (DriverStatistic == null)
            {
                DriverStatistic = new List <DriverStatisticRowEntity>();
            }

            List <DriverStatisticRowEntity> removeDriverStatisticRows = DriverStatistic.ToList();

            // Calculate common season statistics
            FinishedRaces    = scoredRaces.Count();
            IsSeasonFinished = Season.Finished;

            // Calculate statistics per driver
            foreach (var memberResultRows in scoredResultsRows)
            {
                var member             = memberResultRows.Key;
                var memberStandingsRow = standings.StandingsRows.SingleOrDefault(x => x.Member.MemberId == member.MemberId);
                DriverStatisticRowEntity driverStatRow;
                if (DriverStatistic.Any(x => x.Member == member))
                {
                    driverStatRow = DriverStatistic.SingleOrDefault(x => x.Member == member);
                    driverStatRow.ResetStatistic();
                    removeDriverStatisticRows.Remove(driverStatRow);
                }
                else
                {
                    driverStatRow = new DriverStatisticRowEntity()
                    {
                        Member = member
                    };
                    DriverStatistic.Add(driverStatRow);
                }

                if (memberResultRows.Count() == 0)
                {
                    continue;
                }

                driverStatRow.CurrentSeasonPosition = (standings.StandingsRows.SingleOrDefault(x => x.Member.MemberId == member.MemberId)?.Position).GetValueOrDefault(99999);

                // Calculate accumulative statistics
                foreach (var resultRow in memberResultRows)
                {
                    var result = resultRow.ResultRow.Result;
                    driverStatRow.CompletedLaps        += resultRow.ResultRow.CompletedLaps;
                    driverStatRow.DrivenKm             += resultRow.ResultRow.CompletedLaps * resultRow.ResultRow.Result.IRSimSessionDetails?.KmDistPerLap ?? 0;
                    driverStatRow.FastestLaps          += resultRow.ScoredResult.FastestLapDriver == member ? 1 : 0;
                    driverStatRow.Incidents            += resultRow.ResultRow.Incidents;
                    driverStatRow.LeadingKm            += resultRow.ResultRow.LeadLaps * resultRow.ResultRow.Result.IRSimSessionDetails?.KmDistPerLap ?? 0;
                    driverStatRow.LeadingLaps          += resultRow.ResultRow.LeadLaps;
                    driverStatRow.PenaltyPoints        += resultRow.PenaltyPoints;
                    driverStatRow.Poles                += resultRow.ResultRow.StartPosition == 1 ? 1 : 0;
                    driverStatRow.Races                += 1;
                    driverStatRow.RacesCompleted       += resultRow.ResultRow.Status == iRLeagueManager.Enums.RaceStatusEnum.Running ? 1 : 0;
                    driverStatRow.RacesInPoints        += resultRow.RacePoints > 0 ? 1 : 0;
                    driverStatRow.Top10                += resultRow.FinalPosition <= 10 ? 1 : 0;
                    driverStatRow.Top15                += resultRow.FinalPosition <= 15 ? 1 : 0;
                    driverStatRow.Top20                += resultRow.FinalPosition <= 20 ? 1 : 0;
                    driverStatRow.Top25                += resultRow.FinalPosition <= 25 ? 1 : 0;
                    driverStatRow.Top3                 += resultRow.FinalPosition <= 3 ? 1 : 0;
                    driverStatRow.Top5                 += resultRow.FinalPosition <= 5 ? 1 : 0;
                    driverStatRow.Wins                 += resultRow.FinalPosition == 1 ? 1 : 0;
                    driverStatRow.RacePoints           += resultRow.RacePoints;
                    driverStatRow.TotalPoints          += resultRow.TotalPoints;
                    driverStatRow.BonusPoints          += resultRow.BonusPoints;
                    driverStatRow.HardChargerAwards    += resultRow.ScoredResult.HardChargers.Contains(member) ? 1 : 0;
                    driverStatRow.CleanestDriverAwards += resultRow.ScoredResult.CleanestDrivers.Contains(member) ? 1 : 0;
                    driverStatRow.IncidentsWithPenalty += (resultRow.ReviewPenalties?.Count).GetValueOrDefault();
                }

                // Quick fix for penalty points
                // driverStatRow.PenaltyPoints = driverStatRow.RacePoints + driverStatRow.BonusPoints - driverStatRow.TotalPoints;

                // Calculate min/max statistics
                driverStatRow.BestFinalPosition   = memberResultRows.Min(x => x.FinalPosition);
                driverStatRow.BestFinishPosition  = memberResultRows.Min(x => x.ResultRow.FinishPosition);
                driverStatRow.BestStartPosition   = memberResultRows.Min(x => x.ResultRow.StartPosition);
                driverStatRow.WorstFinalPosition  = memberResultRows.Max(x => x.FinalPosition);
                driverStatRow.WorstFinishPosition = memberResultRows.Max(x => x.ResultRow.FinishPosition);
                driverStatRow.WorstStartPosition  = memberResultRows.Max(x => x.ResultRow.StartPosition);

                // Calculate start/end statistics
                var firstResult = memberResultRows.First();
                var lastResult  = memberResultRows.Last();
                driverStatRow.FirstResult             = firstResult;
                driverStatRow.LastResult              = lastResult;
                driverStatRow.FirstRace               = memberResultRows.Select(x => x.ScoredResult.Result.Session).OfType <RaceSessionEntity>().FirstOrDefault();
                driverStatRow.FirstRaceDate           = driverStatRow.FirstRace?.Date;
                driverStatRow.FirstRaceFinalPosition  = firstResult.FinalPosition;
                driverStatRow.FirstRaceFinishPosition = firstResult.ResultRow.FinishPosition;
                driverStatRow.FirstRaceStartPosition  = firstResult.ResultRow.StartPosition;
                driverStatRow.FirstSession            = memberResultRows.Select(x => x.ScoredResult.Result.Session).FirstOrDefault();
                driverStatRow.FirstSessionDate        = driverStatRow.FirstSession?.Date;
                driverStatRow.LastRace               = memberResultRows.Select(x => x.ScoredResult.Result.Session).OfType <RaceSessionEntity>().LastOrDefault();
                driverStatRow.LastRaceDate           = driverStatRow.LastRace?.Date;
                driverStatRow.LastRaceFinalPosition  = lastResult.FinalPosition;
                driverStatRow.LastRaceFinishPosition = lastResult.ResultRow.FinishPosition;
                driverStatRow.LastRaceStartPosition  = lastResult.ResultRow.StartPosition;
                driverStatRow.LastSession            = memberResultRows.Select(x => x.ScoredResult.Result.Session).LastOrDefault();
                driverStatRow.LastSessionDate        = driverStatRow.LastSession?.Date;
                driverStatRow.StartIRating           = firstResult.ResultRow.OldIRating;
                driverStatRow.EndIRating             = lastResult.ResultRow.NewIRating;
                driverStatRow.StartSRating           = firstResult.ResultRow.OldSafetyRating;
                driverStatRow.EndSRating             = lastResult.ResultRow.NewSafetyRating;
                driverStatRow.CurrentSeasonPosition  = memberStandingsRow?.Position ?? 0;
                driverStatRow.Titles = IsSeasonFinished && driverStatRow.CurrentSeasonPosition == 1 ? 1 : 0;

                // Calculate average statistics
                driverStatRow.AvgFinalPosition        = memberResultRows.Average(x => x.FinalPosition);
                driverStatRow.AvgFinishPosition       = memberResultRows.Average(x => x.ResultRow.FinishPosition);
                driverStatRow.AvgIncidentsPerKm       = ((double)driverStatRow.Incidents / driverStatRow.DrivenKm).GetZeroWhenInvalid();
                driverStatRow.AvgIncidentsPerLap      = ((double)driverStatRow.Incidents / driverStatRow.CompletedLaps).GetZeroWhenInvalid();
                driverStatRow.AvgIncidentsPerRace     = ((double)driverStatRow.Incidents / driverStatRow.Races).GetZeroWhenInvalid();
                driverStatRow.AvgIRating              = memberResultRows.Average(x => x.ResultRow.NewIRating);
                driverStatRow.AvgPenaltyPointsPerKm   = ((double)driverStatRow.PenaltyPoints / driverStatRow.DrivenKm).GetZeroWhenInvalid();
                driverStatRow.AvgPenaltyPointsPerLap  = ((double)driverStatRow.PenaltyPoints / driverStatRow.CompletedLaps).GetZeroWhenInvalid();
                driverStatRow.AvgPenaltyPointsPerRace = ((double)driverStatRow.PenaltyPoints / driverStatRow.Races).GetZeroWhenInvalid();
                driverStatRow.AvgPointsPerRace        = ((double)driverStatRow.TotalPoints / driverStatRow.Races).GetZeroWhenInvalid();
                driverStatRow.AvgSRating              = memberResultRows.Average(x => x.ResultRow.NewSafetyRating);
                driverStatRow.AvgStartPosition        = memberResultRows.Average(x => x.ResultRow.StartPosition);
            }

            // Remove rows of drivers that are not in the current statistic set anymore
            removeDriverStatisticRows.ForEach(x => DriverStatistic.Remove(x));
        }
Example #3
0
        /// <summary>
        /// Calculate statistic data based on the current data set.
        /// <para>Make sure either lazy-loading is enabled on the context or run <see cref="LoadRequiredDataAsync(LeagueDbContext, bool)"/> before execution.</para>
        /// </summary>
        /// <param name="dbContext">Database context from EntityFramework</param>
        public override void Calculate(LeagueDbContext dbContext)
        {
            // Fix penalty points sign
            foreach (var statistic in StatisticSets.OfType <ImportedStatisticSetEntity>())
            {
                statistic.DriverStatistic.Where(x => x.PenaltyPoints < 0).ForEach(x => x.PenaltyPoints *= -1);
            }

            // Get all statistic rows and group them by member
            var seasonStatisticRows = StatisticSets.SelectMany(x => x.DriverStatistic).GroupBy(x => x.Member);

            List <DriverStatisticRowEntity> removeDriverStatisticRows = DriverStatistic.ToList();

            foreach (var memberStatisticRows in seasonStatisticRows)
            {
                var member = memberStatisticRows.Key;
                DriverStatisticRowEntity driverStatRow;
                if (DriverStatistic.Any(x => x.Member == member))
                {
                    driverStatRow = DriverStatistic.SingleOrDefault(x => x.Member == member);
                    driverStatRow.ResetStatistic();
                    removeDriverStatisticRows.Remove(driverStatRow);
                }
                else
                {
                    driverStatRow = new DriverStatisticRowEntity()
                    {
                        Member = member
                    };
                    DriverStatistic.Add(driverStatRow);
                }

                // Calculate accumulative statistics
                foreach (var statisticRow in memberStatisticRows)
                {
                    driverStatRow.CompletedLaps        += statisticRow.CompletedLaps;
                    driverStatRow.DrivenKm             += statisticRow.DrivenKm;
                    driverStatRow.FastestLaps          += statisticRow.FastestLaps;
                    driverStatRow.Incidents            += statisticRow.Incidents;
                    driverStatRow.LeadingKm            += statisticRow.LeadingKm;
                    driverStatRow.LeadingLaps          += statisticRow.LeadingLaps;
                    driverStatRow.PenaltyPoints        += statisticRow.PenaltyPoints;
                    driverStatRow.Poles                += statisticRow.Poles;
                    driverStatRow.Races                += statisticRow.Races;
                    driverStatRow.RacesCompleted       += statisticRow.RacesCompleted;
                    driverStatRow.RacesInPoints        += statisticRow.RacesInPoints;
                    driverStatRow.Top10                += statisticRow.Top10;
                    driverStatRow.Top15                += statisticRow.Top15;
                    driverStatRow.Top20                += statisticRow.Top20;
                    driverStatRow.Top25                += statisticRow.Top25;
                    driverStatRow.Top3                 += statisticRow.Top3;
                    driverStatRow.Top5                 += statisticRow.Top5;
                    driverStatRow.Wins                 += statisticRow.Wins;
                    driverStatRow.RacePoints           += statisticRow.RacePoints;
                    driverStatRow.TotalPoints          += statisticRow.TotalPoints;
                    driverStatRow.BonusPoints          += statisticRow.BonusPoints;
                    driverStatRow.HardChargerAwards    += statisticRow.HardChargerAwards;
                    driverStatRow.CleanestDriverAwards += statisticRow.CleanestDriverAwards;
                    driverStatRow.Titles               += statisticRow.Titles;
                }

                // Calculate min/max statistics
                driverStatRow.BestFinalPosition   = memberStatisticRows.Min(x => x.BestFinalPosition);
                driverStatRow.BestFinishPosition  = memberStatisticRows.Min(x => x.BestFinishPosition);
                driverStatRow.BestStartPosition   = memberStatisticRows.Min(x => x.BestStartPosition);
                driverStatRow.WorstFinalPosition  = memberStatisticRows.Max(x => x.WorstFinalPosition);
                driverStatRow.WorstFinishPosition = memberStatisticRows.Max(x => x.WorstFinishPosition);
                driverStatRow.WorstStartPosition  = memberStatisticRows.Max(x => x.WorstStartPosition);

                // Calculate start/end statistics
                var firstResultRow = memberStatisticRows.OrderBy(x => x.FirstRaceDate).FirstOrDefault();
                var lastResultRow  = memberStatisticRows.OrderBy(x => x.LastRaceDate).LastOrDefault();
                driverStatRow.FirstResult             = firstResultRow.FirstResult;
                driverStatRow.LastResult              = lastResultRow.LastResult;
                driverStatRow.FirstRace               = firstResultRow.FirstRace;
                driverStatRow.FirstRaceDate           = memberStatisticRows.Min(x => x.FirstRaceDate);
                driverStatRow.FirstRaceFinalPosition  = firstResultRow.FirstRaceFinalPosition;
                driverStatRow.FirstRaceFinishPosition = firstResultRow.FirstRaceFinishPosition;
                driverStatRow.FirstRaceStartPosition  = firstResultRow.FirstRaceStartPosition;
                driverStatRow.FirstSession            = memberStatisticRows.Select(x => x.FirstSession).Where(x => x != null).OrderBy(x => x.Date).FirstOrDefault();
                driverStatRow.FirstSessionDate        = memberStatisticRows.Min(x => x.FirstSessionDate);
                driverStatRow.LastRace               = lastResultRow.LastRace;
                driverStatRow.LastRaceDate           = memberStatisticRows.Max(x => x.LastRaceDate);
                driverStatRow.LastRaceFinalPosition  = lastResultRow.LastRaceFinalPosition;
                driverStatRow.LastRaceFinishPosition = lastResultRow.LastRaceFinishPosition;
                driverStatRow.LastRaceStartPosition  = lastResultRow.LastRaceStartPosition;
                driverStatRow.LastSession            = memberStatisticRows.Select(x => x.LastSession).Where(x => x != null).LastOrDefault();
                driverStatRow.LastSessionDate        = memberStatisticRows.Max(x => x.LastSessionDate);
                driverStatRow.StartIRating           = firstResultRow.StartIRating;
                driverStatRow.EndIRating             = lastResultRow.EndIRating;
                driverStatRow.StartSRating           = firstResultRow.StartSRating;
                driverStatRow.EndSRating             = lastResultRow.EndSRating;
                driverStatRow.CurrentSeasonPosition  = lastResultRow.CurrentSeasonPosition;

                // Calculate average statistics
                driverStatRow.AvgFinalPosition        = memberStatisticRows.WeightedAverage(x => x.AvgFinalPosition, x => x.Races);
                driverStatRow.AvgFinishPosition       = memberStatisticRows.WeightedAverage(x => x.AvgFinishPosition, x => x.Races);
                driverStatRow.AvgIncidentsPerKm       = (driverStatRow.Incidents / driverStatRow.DrivenKm).GetZeroWhenInvalid();
                driverStatRow.AvgIncidentsPerLap      = ((double)driverStatRow.Incidents / driverStatRow.CompletedLaps).GetZeroWhenInvalid();
                driverStatRow.AvgIncidentsPerRace     = ((double)driverStatRow.Incidents / driverStatRow.Races).GetZeroWhenInvalid();
                driverStatRow.AvgIRating              = memberStatisticRows.WeightedAverage(x => x.AvgIRating, x => x.Races);
                driverStatRow.AvgPenaltyPointsPerKm   = (driverStatRow.PenaltyPoints / driverStatRow.DrivenKm).GetZeroWhenInvalid();
                driverStatRow.AvgPenaltyPointsPerLap  = ((double)driverStatRow.PenaltyPoints / driverStatRow.CompletedLaps).GetZeroWhenInvalid();
                driverStatRow.AvgPenaltyPointsPerRace = ((double)driverStatRow.PenaltyPoints / driverStatRow.Races).GetZeroWhenInvalid();
                driverStatRow.AvgPointsPerRace        = ((double)driverStatRow.TotalPoints / driverStatRow.Races).GetZeroWhenInvalid();
                driverStatRow.AvgSRating              = memberStatisticRows.WeightedAverage(x => x.AvgSRating, x => x.Races);
                driverStatRow.AvgStartPosition        = memberStatisticRows.WeightedAverage(x => x.AvgStartPosition, x => x.Races);
            }

            // Calculate current champ
            var seasonStatisticSets   = StatisticSets.OfType <SeasonStatisticSetEntity>().Where(x => x.IsSeasonFinished);
            var importedStatisticSets = StatisticSets.OfType <ImportedStatisticSetEntity>();
            var lastSeasonStatistic   = seasonStatisticSets.OrderBy(x => x.Season.SeasonEnd).LastOrDefault();
            var lastImportedStatistic = importedStatisticSets.OrderBy(x => x.LastDate).LastOrDefault();

            if (lastSeasonStatistic?.Season.SeasonEnd >= lastImportedStatistic?.LastDate)
            {
                CurrentChamp = lastSeasonStatistic?.DriverStatistic?.SingleOrDefault(x => x.CurrentSeasonPosition == 1)?.Member;
            }
            else
            {
                CurrentChamp = lastImportedStatistic?.DriverStatistic?.SingleOrDefault(x => x.CurrentSeasonPosition == 1)?.Member;
            }

            DriverStatistic.Remove(removeDriverStatisticRows);
        }