public SeasonStandingsDTO GetStandingsFromSeason(long seasonId, long?sessionId = null)
        {
            // get season entity; get latest season if id == 0
            SeasonEntity season;

            if (seasonId == 0)
            {
                season = DbContext.Set <SeasonEntity>().ToList().OrderByDescending(x => x.SeasonStart).FirstOrDefault();
            }
            else
            {
                season = DbContext.Set <SeasonEntity>().Find(seasonId);
            }

            if (season == null)
            {
                return(new SeasonStandingsDTO()
                {
                    SeasonId = seasonId
                });
            }

            // get standings from ModelDataProvider
            var scoringTables     = season.ScoringTables;
            var modelDataProvider = new ModelDataProvider(DbContext);

            StandingsDataDTO[] standings;
            if (sessionId == null)
            {
                standings = modelDataProvider.GetStandings(scoringTables.Select(x => x.ScoringTableId).ToArray());
            }
            else
            {
                var requestIds = scoringTables.Select(x => new long[] { x.ScoringTableId, sessionId.Value }).ToArray();
                standings = modelDataProvider.GetStandings(requestIds);
            }

            // construct DTO
            var seasonStandings = new SeasonStandingsDTO()
            {
                SeasonId  = season.SeasonId,
                Standings = standings
            };

            return(seasonStandings);
        }
        /// <summary>
        /// Get the results of a single session
        /// If <paramref name="sessionId"/> == 0 the lates session with attached result is used
        /// </summary>
        /// <param name="sessionId">Id of the session</param>
        /// <returns>Convenience DTO for all session results</returns>
        public SessionResultsDTO GetResultsFromSession(long sessionId, bool includeRawResults = false, ScoredResultDataDTO[] scoredResults = null)
        {
            var mapper = new DTOMapper(DbContext);

            // get session entity from database
            SessionBaseEntity session;

            if (sessionId == 0)
            {
                // if sessionId is 0 get latest session with result
                session = DbContext.Set <SessionBaseEntity>()
                          .Where(x => x.SessionResult != null)
                          .OrderByDescending(x => x.Date)
                          .FirstOrDefault();
            }
            else
            {
                // else get session from sessionId
                session = DbContext.Set <SessionBaseEntity>().Find(sessionId);
            }

            if (session == null)
            {
                return(new SessionResultsDTO()
                {
                    SessionId = sessionId
                });
            }
            sessionId = session.SessionId;

            // get session race number
            int raceNr = 0;

            if (session.SessionType == iRLeagueManager.Enums.SessionType.Race)
            {
                var season         = session.Schedule.Season;
                var seasonSessions = season.Schedules.SelectMany(x => x.Sessions).Where(x => x.SessionType == iRLeagueManager.Enums.SessionType.Race).OrderBy(x => x.Date);
                raceNr = (seasonSessions.Select((x, i) => new { number = i + 1, item = x }).FirstOrDefault(x => x.item.SessionId == sessionId)?.number).GetValueOrDefault();
            }

            // get scoredResults using ModelDataProvider
            var                  modelDataProvider = new ModelDataProvider(DbContext);
            ResultDataDTO        rawResults        = null;
            SimSessionDetailsDTO sessionDetails    = null;

            if (session.SessionResult != null)
            {
                if (scoredResults == null)
                {
                    scoredResults = new ScoredResultDataDTO[0];
                    var ids = session.Scorings.Select(x => new KeyValuePair <long, long>(x.ScoringId, session.SessionId));
                    //scoredResults = session.Scorings.Select(x => modelDataProvider.GetScoredResult(sessionId, x.ScoringId)).ToArray();
                    scoredResults = GetScoredResults(ids);
                }

                // get rawResults if includeRawResults == true
                if (includeRawResults)
                {
                    rawResults = mapper.MapToResulDataDTO(session.SessionResult);
                }

                // get session details
                sessionDetails = mapper.MapToSimSessionDetailsDTO(session.SessionResult.IRSimSessionDetails);
            }

            // construct SessionResultsDTO
            var resultsDTO = new SessionResultsDTO()
            {
                Count          = scoredResults.Count(),
                ScheduleId     = session.ScheduleId,
                ScheduleName   = session.Schedule.Name,
                RaceNr         = raceNr,
                RawResults     = rawResults,
                ScoredResults  = scoredResults,
                SessionId      = sessionId,
                SessionDetails = sessionDetails,
                LocationId     = session.LocationId
            };

            return(resultsDTO);
        }
        /// <summary>
        /// Get all reviews belonging to a session, specified by its sessionId
        /// </summary>
        /// <param name="sessionId">Id of the session</param>
        /// <returns>DTO containing all reviews and summary data</returns>
        public SessionReviewsDTO GetReviewsFromSession(long sessionId, SessionBaseEntity preLoadedSession = null, IncidentReviewDataDTO[] preLoadedReviews = null)
        {
            // Load session from db
            SessionBaseEntity session;

            // if session id == 0 load latest session, else load specified session
            if (sessionId == 0 && preLoadedSession == null)
            {
                session = DbContext.Set <SessionBaseEntity>()
                          .Where(x => x.SessionResult != null)
                          .OrderByDescending(x => x.Date)
                          .FirstOrDefault();
            }
            else if (preLoadedSession == null)
            {
                session = DbContext.Set <SessionBaseEntity>().Find(sessionId);
            }
            else
            {
                session = preLoadedSession;
            }

            if (session == null)
            {
                return(new SessionReviewsDTO());
            }

            var mapper = new DTOMapper(DbContext);

            // get session race number
            int raceNr = 0;

            if (session.SessionType == iRLeagueManager.Enums.SessionType.Race)
            {
                var season         = session.Schedule.Season;
                var seasonSessions = season.Schedules.SelectMany(x => x.Sessions).Where(x => x.SessionType == iRLeagueManager.Enums.SessionType.Race).OrderBy(x => x.Date);
                raceNr = (seasonSessions.Select((x, i) => new { number = i + 1, item = x }).FirstOrDefault(x => x.item.SessionId == sessionId)?.number).GetValueOrDefault();
            }

            IncidentReviewDataDTO[] reviews = preLoadedReviews;
            if (preLoadedReviews == null)
            // get all reviews ids for this session and retrieve reviews data from ModelDataProvider
            {
                var reviewIds         = session.Reviews.Select(x => x.ReviewId);
                var modelDataProvider = new ModelDataProvider(DbContext);
                reviews = modelDataProvider.GetReviews(reviewIds.ToArray());
            }

            // get custom vote categories information from database
            var voteCatIds = reviews.Where(x => x.AcceptedReviewVotes?.Count() > 0).SelectMany(x => x.AcceptedReviewVotes.Select(y => y.VoteCategoryId)).Distinct();
            var voteCats   = DbContext.Set <VoteCategoryEntity>().Local.Where(x => voteCatIds.Contains(x.CatId)).ToList().Select(x => mapper.MapToVoteCategoryDTO(x));

            if (voteCats.Count() < voteCatIds.Count())
            {
                voteCats = DbContext.Set <VoteCategoryEntity>().Where(x => voteCatIds.Contains(x.CatId)).ToList().Select(x => mapper.MapToVoteCategoryDTO(x));
            }

            /* construct DTOs */
            // get all vote results that resulted in a penalty
            var penalties = reviews
                            .Where(x => x.AcceptedReviewVotes?.Count() > 0)
                            .SelectMany(x => x.AcceptedReviewVotes)
                            .Where(x => x.CatPenalty > 0 && x.MemberAtFaultId != null);
            // summarize penalites for each driver
            var driverPenalties = penalties
                                  .GroupBy(x => x.MemberAtFaultId)
                                  .Select(x => new MemberPenaltySummaryDTO()
            {
                MemberId  = x.Key.GetValueOrDefault(),
                Name      = DbContext.Set <LeagueMemberEntity>().Find(x.Key.GetValueOrDefault()).Fullname,
                Count     = x.Count(),
                Points    = x.Sum(y => y.CatPenalty),
                Penalties = x.ToArray()
            });
            // summarized penalties for all reviews
            var penaltySummary = new ReviewsPenaltySummaryDTO()
            {
                Count        = driverPenalties.Sum(x => x.Count),
                Points       = driverPenalties.Sum(x => x.Points),
                DrvPenalties = driverPenalties.ToArray()
            };
            // create review convencience DTO
            var reviewData = new SessionReviewsDTO()
            {
                Reviews   = reviews,
                Total     = reviews.Count(),
                Open      = reviews.Count(x => x.AcceptedReviewVotes == null || x.AcceptedReviewVotes.Count() == 0),
                Voted     = reviews.Count(x => x.Comments.Any(y => y.CommentReviewVotes.Count() > 0)),
                Closed    = reviews.Count(x => x.AcceptedReviewVotes?.Count() > 0),
                Penalties = penaltySummary,
                Results   = reviews
                            .Where(x => x.AcceptedReviewVotes?.Count() > 0)
                            .SelectMany(x => x.AcceptedReviewVotes)
                            .Where(x => x.VoteCategoryId != null)
                            .GroupBy(x => x.VoteCategoryId)
                            .Select(x => new CountValue <VoteCategoryDTO>()
                {
                    Count = x.Count(), Value = voteCats.SingleOrDefault(y => y.CatId == x.Key.Value)
                })
                            .ToArray(),
                SessionId = sessionId,
                RaceNr    = raceNr
            };

            /* END construct DTOs */

            return(reviewData);
        }