// Potential for de-duping this code
        public PentamindStandingsReportVm GetSeniorStandings(int?year)
        {
            var context         = DataEntitiesProvider.Provide();
            var currentOlympiad = (year.HasValue)
                ? context.Olympiad_Infoes.Where(x => x.StartDate.HasValue && x.StartDate.Value.Year == year.Value).First()
                : context.Olympiad_Infoes.First(x => x.Current);
            var lastDobForSenior = currentOlympiad.LastDateOfBirthForSenior();

            var vm = new PentamindStandingsReportVm();

            vm.OlympiadTitle = currentOlympiad.FullTitle();
            int pentaTotal        = currentOlympiad.PentaTotal.Value;
            int pentaLong         = currentOlympiad.PentaLong.Value;
            var longSessionEvents = currentOlympiad.Events.Where(x => x.No_Sessions > 1)
                                    .Select(x => x.Code)
                                    .ToList();

            var results = context.Entrants
                          .Where(x => x.OlympiadId == currentOlympiad.Id && !x.Absent && x.Rank.HasValue && x.Penta_Score.HasValue)
                          .Join(context.Contestants, e => e.Mind_Sport_ID, c => c.Mind_Sport_ID, (e, c) => new { e, c })
                          .Where(x => x.c.DateofBirth.HasValue && x.c.DateofBirth.Value <= lastDobForSenior)
                          .GroupBy(x => x.c.Mind_Sport_ID)
                          .ToList();

            var calc = new PentamindMetaScoreCalculator();

            var standings = new List <PentamindStandingsReportVm.ContestantStanding>();

            foreach (var r in results)
            {
                var standing = new PentamindStandingsReportVm.ContestantStanding()
                {
                    ContestantId    = r.Key,
                    Name            = r.First().c.FullName(),
                    Nationality     = r.First().c.Nationality,
                    IsInWomensPenta = false // irrelevant for Senior
                };

                standing.Scores = r.Select(x => new PentamindStandingsReportVm.EventScore()
                {
                    Code          = x.e.Event.Code,
                    GameCode      = x.e.Event.Game.Code,
                    Score         = (double)x.e.Penta_Score,
                    IsLongSession = longSessionEvents.Contains(x.e.Event.Code),
                    IsEuroGame    = (x.e.Event.Game.GameCategory.Id == 3)
                }).ToList();

                standing.Scores     = calc.SelectBestScores(standing.Scores, pentaLong, pentaTotal, currentOlympiad.StartDate.Value.Year);
                standing.TotalScore = standing.Scores.Sum(x => x.Score);
                standings.Add(standing);
            }

            vm.Standings = standings.OrderByDescending(x => x.TotalScore);
            return(vm);
        }
        public void PRG_HandlesCaseOfDominatedLongEvent1_Correctly()
        {
            var prg = new PentamindMetaScoreCalculator();

            // Will overlook the best long session (AAAA) in order to pick up big AAA1
            // - because we can get long events BBBB and CCCC
            var scores = new List <PentamindStandingsGenerator.PentamindStandingsReportVm.EventScore>()
            {
                new PentamindStandingsGenerator.PentamindStandingsReportVm.EventScore()
                {
                    Score = 10, GameCode = "AA", IsLongSession = true, Code = "AAAA"
                },
                new PentamindStandingsGenerator.PentamindStandingsReportVm.EventScore()
                {
                    Score = 9, GameCode = "BB", IsLongSession = true, Code = "BBBB"
                },
                new PentamindStandingsGenerator.PentamindStandingsReportVm.EventScore()
                {
                    Score = 8, GameCode = "CC", IsLongSession = true, Code = "CCCC"
                },
                new PentamindStandingsGenerator.PentamindStandingsReportVm.EventScore()
                {
                    Score = 100, GameCode = "AA", IsLongSession = false, Code = "AAA1"
                },
                new PentamindStandingsGenerator.PentamindStandingsReportVm.EventScore()
                {
                    Score = 10, GameCode = "DD", IsLongSession = false, Code = "DDDD"
                },
                new PentamindStandingsGenerator.PentamindStandingsReportVm.EventScore()
                {
                    Score = 10, GameCode = "EE", IsLongSession = false, Code = "EEEE"
                },
                new PentamindStandingsGenerator.PentamindStandingsReportVm.EventScore()
                {
                    Score = 10, GameCode = "FF", IsLongSession = false, Code = "FFFF"
                }
            };

            var score = prg.SelectBestScores(scores, 2, 5, 2015);

            Assert.AreEqual(5, score.Count());
            Assert.AreEqual(137, score.Sum(x => x.Score));
        }
        public void PRG_Prefers4WithLowerScoreOver4WithHigher()
        {
            var prg = new PentamindMetaScoreCalculator();

            // If you take either AA or BB for 100, you can't get five events with two big ones
            // so prefer the
            var scores = new List <PentamindStandingsGenerator.PentamindStandingsReportVm.EventScore>()
            {
                new PentamindStandingsGenerator.PentamindStandingsReportVm.EventScore()
                {
                    Score = 10, GameCode = "AA", IsLongSession = true, Code = "AAAA"
                },
                new PentamindStandingsGenerator.PentamindStandingsReportVm.EventScore()
                {
                    Score = 9, GameCode = "BB", IsLongSession = true, Code = "BBBB"
                },
                new PentamindStandingsGenerator.PentamindStandingsReportVm.EventScore()
                {
                    Score = 8, GameCode = "CC", IsLongSession = false, Code = "CCCC"
                },
                new PentamindStandingsGenerator.PentamindStandingsReportVm.EventScore()
                {
                    Score = 100, GameCode = "AA", IsLongSession = false, Code = "AAA1"
                },
                new PentamindStandingsGenerator.PentamindStandingsReportVm.EventScore()
                {
                    Score = 100, GameCode = "BB", IsLongSession = false, Code = "BBB1"
                },
                new PentamindStandingsGenerator.PentamindStandingsReportVm.EventScore()
                {
                    Score = 10, GameCode = "DD", IsLongSession = false, Code = "DDDD"
                },
                new PentamindStandingsGenerator.PentamindStandingsReportVm.EventScore()
                {
                    Score = 10, GameCode = "EE", IsLongSession = false, Code = "EEEE"
                }
            };

            var score = prg.SelectBestScores(scores, 2, 5, 2015);

            Assert.AreEqual(5, score.Count());
            Assert.AreEqual(47, score.Sum(x => x.Score));
        }
        public void PRG_HandlesCaseOfDominatedLongEvent2_Correctly()
        {
            var prg = new PentamindMetaScoreCalculator();

            var scores = new List <PentamindStandingsGenerator.PentamindStandingsReportVm.EventScore>()
            {
                new PentamindStandingsGenerator.PentamindStandingsReportVm.EventScore()
                {
                    Score = 10, GameCode = "AA", IsLongSession = true, Code = "AAAA"
                },
                new PentamindStandingsGenerator.PentamindStandingsReportVm.EventScore()
                {
                    Score = 9, GameCode = "BB", IsLongSession = true, Code = "BBBB"
                },
                new PentamindStandingsGenerator.PentamindStandingsReportVm.EventScore()
                {
                    Score = 8, GameCode = "CC", IsLongSession = true, Code = "CCCC"
                },
                new PentamindStandingsGenerator.PentamindStandingsReportVm.EventScore()
                {
                    Score = 100, GameCode = "BB", IsLongSession = false, Code = "BBB1"
                },
                new PentamindStandingsGenerator.PentamindStandingsReportVm.EventScore()
                {
                    Score = 10, GameCode = "DD", IsLongSession = false, Code = "DDDD"
                },
                new PentamindStandingsGenerator.PentamindStandingsReportVm.EventScore()
                {
                    Score = 10, GameCode = "EE", IsLongSession = false, Code = "EEEE"
                },
                new PentamindStandingsGenerator.PentamindStandingsReportVm.EventScore()
                {
                    Score = 10, GameCode = "FF", IsLongSession = false, Code = "FFFF"
                }
            };

            var score = prg.SelectBestScores(scores, 2, 5, 2015);

            Assert.AreEqual(5, score.Count());
            Assert.AreEqual(138, score.Sum(x => x.Score));
        }
        public PentamindStandingsReportVm GetStandings(int?year, DateTime?date = null)
        {
            DateTime?endOfDay = (date.HasValue) ? date.Value.AddDays(1) : (DateTime?)null;

            var context         = DataEntitiesProvider.Provide();
            var currentOlympiad = (year.HasValue)
                ? context.Olympiad_Infoes.Where(x => x.StartDate.HasValue && x.StartDate.Value.Year == year.Value).First()
                : context.Olympiad_Infoes.First(x => x.Current);

            var vm = new PentamindStandingsReportVm();

            vm.OlympiadTitle = currentOlympiad.FullTitle();
            int pentaTotal        = currentOlympiad.PentaTotal.Value;
            int pentaLong         = currentOlympiad.PentaLong.Value;
            var longSessionEvents = currentOlympiad.Events.Where(x => x.No_Sessions > 1)
                                    .Select(x => x.Code)
                                    .ToList();

            var results = context.Entrants
                          .Where(x => x.OlympiadId == currentOlympiad.Id && !x.Absent && x.Rank.HasValue && x.Penta_Score.HasValue)
                          .Join(context.Contestants, e => e.Mind_Sport_ID, c => c.Mind_Sport_ID, (e, c) => new { e, c })
                          .ToList() // TODO This was inserted for Etan's stuff - remove with the subsequent Where
                          .Where(ec => (endOfDay == null || ec.e.Event.End < endOfDay))
                          .GroupBy(x => x.c.Mind_Sport_ID)
                          .ToList();

            var excludedWomen = context.WomenNotInWomensPentaminds
                                .Where(x => x.OlympiadId == currentOlympiad.Id)
                                .Select(x => x.ContestantId);

            var calc = new PentamindMetaScoreCalculator();

            var standings = new List <PentamindStandingsReportVm.ContestantStanding>();

            foreach (var r in results)
            {
                var standing = new PentamindStandingsReportVm.ContestantStanding()
                {
                    ContestantId    = r.Key,
                    Name            = r.First().c.FullName(),
                    Nationality     = r.First().c.Nationality,
                    IsInWomensPenta = !r.First().c.Male&& !excludedWomen.Contains(r.First().c.Mind_Sport_ID),
                    IsJunior        = r.First().c.IsJuniorForOlympiad(currentOlympiad),
                    IsSenior        = r.First().c.IsSeniorForOlympiad(currentOlympiad)
                };

                standing.Scores = r.Select(x => new PentamindStandingsReportVm.EventScore()
                {
                    Code          = x.e.Event.Code,
                    GameCode      = x.e.Event.Game.Code,
                    Score         = (double)x.e.Penta_Score,
                    IsLongSession = longSessionEvents.Contains(x.e.Event.Code),
                    // TODO: 7 Wonders Duel is not considered a Eurogame even through the underlying Game is.
                    IsEuroGame = (x.e.Event.Game.GameCategory.Id == 3 && x.e.Event.Code != "WODU")
                }).ToList();

                standing.Scores     = calc.SelectBestScores(standing.Scores, pentaLong, pentaTotal, currentOlympiad.StartDate.Value.Year);
                standing.TotalScore = standing.Scores.Sum(x => x.Score);
                standing.IsValid    = (standing.Scores.Count() == pentaTotal);
                standings.Add(standing);
            }

            vm.Standings = standings.OrderByDescending(x => x.TotalScore);
            return(vm);
        }