private void CalculateWinsAndLosses(HearthStatsDbContext context, Expression<Func<GameResult, bool>> filter)
        {
            var games = context.Games;
            float total = games.Where(filter).Count();
            float winsC = games.Where(filter).Count(x => x.Victory && !x.GoFirst);
            float lossesC = games.Where(filter).Count(x => !x.Victory && !x.GoFirst);
            float winsNC = games.Where(filter).Count(x => x.Victory && x.GoFirst);
            float lossesNC = games.Where(filter).Count(x => !x.Victory && x.GoFirst);
            var wins = winsC + winsNC;
            var losses = lossesC + lossesNC;

            WinsAndLosses.Clear();
            Wins.Clear();
            Losses.Clear();
            WithCoin.Clear();
            WithoutCoin.Clear();
            if (total <= 0)
            {
                WinsAndLosses.Add(new StatModel("Wins", 0));
                WinsAndLosses.Add(new StatModel("Losses", 0));
                Wins.Add(new StatModel("Coin", 0));
                Wins.Add(new StatModel("No coin", 0));
                Losses.Add(new StatModel("Coin", 0));
                Losses.Add(new StatModel("No coin", 0));
                WithCoin.Add(new StatModel("Losses", 0));
                WithCoin.Add(new StatModel("Losses", 0));
                WithoutCoin.Add(new StatModel("Losses", 0));
                WithoutCoin.Add(new StatModel("Losses", 0));

                return;
            }

            WinsAndLosses.Add(new StatModel(string.Format("Wins: {0}", wins), wins / total * 100));
            WinsAndLosses.Add(new StatModel(string.Format("Losses: {0}", losses), losses / total * 100));

            Wins.Add(new StatModel(string.Format("Coin: {0}", winsC), winsC / wins * 100));
            Wins.Add(new StatModel(string.Format("No coin: {0}", winsNC), winsNC / wins * 100));

            Losses.Add(new StatModel(string.Format("Coin: {0}", lossesC), lossesC / losses * 100));
            Losses.Add(new StatModel(string.Format("No coin: {0}", lossesNC), lossesNC / losses * 100));

            WithCoin.Add(new StatModel(string.Format("Wins: {0}", winsC), winsC / (winsC + lossesC) * 100));
            WithCoin.Add(new StatModel(string.Format("Losses: {0}", lossesC), lossesC / (winsC + lossesC) * 100));

            WithoutCoin.Add(new StatModel(string.Format("Wins: {0}", winsNC), winsNC / (winsNC + lossesNC) * 100));
            WithoutCoin.Add(new StatModel(string.Format("Losses: {0}", lossesNC), lossesNC / (winsNC + lossesNC) * 100));
        }
        private void GetStatsSince(HearthStatsDbContext context, DateTime start, out decimal numGames, out decimal numWon, out decimal numLoss)
        {
            GameMode gameMode;
            var filterGameMode = Enum.TryParse(LatestGamesViewModel.FilterGameMode, out gameMode);
            var heroId = Guid.Empty;
            var filterHero = LatestGamesViewModel.FilterHero != null && !String.IsNullOrEmpty(LatestGamesViewModel.FilterHero.Key);
            if (filterHero)
            {
                heroId = LatestGamesViewModel.FilterHero.Id;
            }
            var oppHeroId = Guid.Empty;
            var filterOppHero = LatestGamesViewModel.FilterOpponentHero != null && !String.IsNullOrEmpty(LatestGamesViewModel.FilterOpponentHero.Key);
            if (filterOppHero)
            {
                oppHeroId = LatestGamesViewModel.FilterOpponentHero.Id;
            }
            var deckId = Guid.Empty;
            var filterDeck = LatestGamesViewModel.FilterDeck != null && !String.IsNullOrEmpty(LatestGamesViewModel.FilterDeck.Key);
            if (filterDeck)
            {
                deckId = LatestGamesViewModel.FilterDeck.Id;
            }

            numGames = context.Games.Count(
                x => x.Started > start
                     && (!filterGameMode || (filterGameMode && x.GameMode == gameMode))
                     && (!filterHero || (filterHero && x.Hero.Id == heroId))
                     && (!filterOppHero || (filterOppHero && x.OpponentHero.Id == oppHeroId))
                     && (!filterDeck || (filterDeck && x.Deck.Id == deckId)));
            numWon = context.Games.Count(
                x => x.Started > start && x.Victory
                     && (!filterGameMode || (filterGameMode && x.GameMode == gameMode))
                     && (!filterHero || (filterHero && x.Hero.Id == heroId))
                     && (!filterOppHero || (filterOppHero && x.OpponentHero.Id == oppHeroId))
                     && (!filterDeck || (filterDeck && x.Deck.Id == deckId)));
            numLoss = context.Games.Count(
                x => x.Started > start && !x.Victory
                     && (!filterGameMode || (filterGameMode && x.GameMode == gameMode))
                     && (!filterHero || (filterHero && x.Hero.Id == heroId))
                     && (!filterOppHero || (filterOppHero && x.OpponentHero.Id == oppHeroId))
                     && (!filterDeck || (filterDeck && x.Deck.Id == deckId)));
        }
        private void CalculateHeroesPlayed(HearthStatsDbContext context, Expression<Func<GameResult, bool>> filter)
        {
            var games = context.Games;

            heroesPlayed.Clear();
            opponentHeroesPlayed.Clear();
            var total = games.Where(filter).Count();
            if (total == 0)
            {
                return;
            }
            var heroestats = games
                .Where(filter)
                .GroupBy(x => x.Hero)
                .Where(x => x.Any())
                .Select(
                    x => new
                        {
                            x.Key,
                            x.Key.ClassName,
                            Count = x.Count()
                        }).ToList();

            var oppheroestats = games
                .Where(filter)
                .GroupBy(x => x.OpponentHero)
                .Where(x => x.Any())
                .Select(
                    x => new
                        {
                            x.Key,
                            x.Key.ClassName,
                            Count = x.Count()
                        }).ToList();

            heroesPlayed.IsNotifying = false;
            foreach (var hero in heroestats)
            {
                // float count = games.Where(filter).Count(x => x.Hero != null && x.Hero.Key == hero.Key);
                if (hero.Count > 0)
                {
                    heroesPlayed.Add(new StatModel(string.Format("{0}: {1}", hero.ClassName, hero.Count), (float)hero.Count / total * 100, hero.Key.GetBrush()));
                }
            }
            heroesPlayed.IsNotifying = true;
            heroesPlayed.Refresh();

            opponentHeroesPlayed.IsNotifying = false;
            foreach (var hero in oppheroestats)
            {
                //count = games.Where(filter).Count(x => x.OpponentHero != null && x.OpponentHero.Key == hero.Key);
                if (hero.Count > 0)
                {
                    opponentHeroesPlayed.Add(new StatModel(string.Format("{0}: {1}", hero.ClassName, hero.Count), (float)hero.Count / total * 100, hero.Key.GetBrush()));
                }
            }
            opponentHeroesPlayed.IsNotifying = true;
            opponentHeroesPlayed.Refresh();
        }
        private void CalculateWinrate(HearthStatsDbContext context, List<GameResult> allGames)
        {
            var weekGroups = allGames
                .Select(
                    g => new
                        {
                            Game = g, g.Started.Year,
                            Week =
                                CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(g.Started, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday),
                            g.Started.Date
                        })
                // .GroupBy(x => new { x.Date })
                // .OrderBy(x => x.Key.Date)
                .GroupBy(x => new { x.Year, x.Week })
                .OrderBy(x => x.Key.Year).ThenBy(x => x.Key.Week)
                .Select(
                    (g, i) => new
                        {
                            WeekGroup = g,
                            WeekNum = i + 1, g.Key.Year,
                            CalendarWeek = g.Key.Week,
                            //Date = g.Key.Date,
                            Wins = g.Sum(x => x.Game.Victory ? 1 : 0),
                            Losses = g.Sum(x => x.Game.Victory ? 0 : 1),
                            Total = g.Count()
                        });
            var dayGroups = allGames
                .Select(
                    g => new
                        {
                            Game = g, g.Started.Date
                        })
                // .GroupBy(x => new { x.Date })
                // .OrderBy(x => x.Key.Date)
                .GroupBy(x => x.Date)
                .OrderBy(x => x.Key)
                .Select(
                    (g, i) => new
                        {
                            WeekGroup = g, g.Key.Date,
                            Wins = g.Sum(x => x.Game.Victory ? 1 : 0),
                            Losses = g.Sum(x => x.Game.Victory ? 0 : 1),
                            Total = g.Count()
                        });
            var winrateDataPoints = new List<DateValue>();
            var winrateAvgDataPoints = new List<DateValue>();
            foreach (var weekGroup in weekGroups)
            {
                winrateDataPoints.Add(new DateValue(FirstDateOfWeek(weekGroup.Year, weekGroup.CalendarWeek), weekGroup.Wins / (double)weekGroup.Total));
            }
            foreach (var dayGroup in dayGroups)
            {
                winrateAvgDataPoints.Add(new DateValue(dayGroup.Date, dayGroup.Wins / (double)dayGroup.Total));
            }

            PlotModel.Series.Add(
                new LineSeries
                    {
                        Title = "Win ratio per week",
                        ItemsSource = winrateDataPoints,
                        MarkerStroke = OxyColors.Black,
                        MarkerType = MarkerType.Circle,
                        DataFieldX = "Date",
                        DataFieldY = "Value",
                        Smooth = true
                    });

            PlotModel.Series.Add(
                new LineSeries
                    {
                        Title = "Moving average over 7 days",
                        ItemsSource = MovingAverage(winrateAvgDataPoints, 7),
                        MarkerStroke = OxyColors.Black,
                        MarkerType = MarkerType.Circle,
                        DataFieldX = "Date",
                        DataFieldY = "Value",
                        Smooth = true
                    });
        }
        private void CalculateRatios(HearthStatsDbContext context)
        {
            var now = DateTime.Now;
            var start = new DateTime(now.Year, now.Month, now.Day, 0, 0, 0);
            decimal numGames;
            decimal numWon;
            decimal numLoss;
            GetStatsSince(context, start, out numGames, out numWon, out numLoss);

            if (numGames > 0)
            {
                TodayRatioWin = Math.Round((numWon / numGames) * 100, 0);
                TodayRatioLoss = Math.Round((numLoss / numGames) * 100, 0);
            }
            else
            {
                TodayRatioWin = 0;
                TodayRatioLoss = 0;
            }

            start = now.StartOfWeek(DayOfWeek.Monday);
            GetStatsSince(context, start, out numGames, out numWon, out numLoss);
            if (numGames > 0)
            {
                ThisWeekRatioWin = Math.Round((numWon / numGames) * 100, 0);
                ThisWeekRatioLoss = Math.Round((numLoss / numGames) * 100, 0);
            }
            else
            {
                ThisWeekRatioWin = 0;
                ThisWeekRatioLoss = 0;
            }

            start = new DateTime(now.Year, now.Month, 1, 0, 0, 0);
            GetStatsSince(context, start, out numGames, out numWon, out numLoss);
            if (numGames > 0)
            {
                ThisMonthRatioWin = Math.Round((numWon / numGames) * 100, 0);
                ThisMonthRatioLoss = Math.Round((numLoss / numGames) * 100, 0);
            }
            else
            {
                ThisMonthRatioWin = 0;
                ThisMonthRatioLoss = 0;
            }

            start = new DateTime(now.Year, now.Month, now.Day, 0, 0, 0);
            start = start.AddDays(-7);
            GetStatsSince(context, start, out numGames, out numWon, out numLoss);
            if (numGames > 0)
            {
                Last7DaysRatioWin = Math.Round((numWon / numGames) * 100, 0);
                Last7DaysRatioLoss = Math.Round((numLoss / numGames) * 100, 0);
            }
            else
            {
                Last7DaysRatioWin = 0;
                Last7DaysRatioLoss = 0;
            }

            start = new DateTime(now.Year, now.Month, now.Day, 0, 0, 0);
            start = start.AddDays(-30);
            GetStatsSince(context, start, out numGames, out numWon, out numLoss);
            if (numGames > 0)
            {
                Last30DaysRatioWin = Math.Round((numWon / numGames) * 100, 0);
                Last30DaysRatioLoss = Math.Round((numLoss / numGames) * 100, 0);
            }
            else
            {
                Last30DaysRatioWin = 0;
                Last30DaysRatioLoss = 0;
            }
        }
 private void CalculateHeroesWinrate(HearthStatsDbContext context, List<GameResult> allGames)
 {
     var heroGroups = allGames.GroupBy(x => x.Hero);
     foreach (var heroGroup in heroGroups)
     {
         var weekGroups = heroGroup
             .Select(
                 g => new
                     {
                         Game = g, g.Started.Year,
                         Week =
                             CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(g.Started, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday),
                         g.Started.Date
                     })
             // .GroupBy(x => new { x.Date })
             // .OrderBy(x => x.Key.Date)
             .GroupBy(x => new { x.Year, x.Week })
             .OrderBy(x => x.Key.Year).ThenBy(x => x.Key.Week)
             .Select(
                 (g, i) => new
                     {
                         WeekGroup = g,
                         WeekNum = i + 1, g.Key.Year,
                         CalendarWeek = g.Key.Week,
                         //Date = g.Key.Date,
                         Wins = g.Sum(x => x.Game.Victory ? 1 : 0),
                         Losses = g.Sum(x => x.Game.Victory ? 0 : 1),
                         Total = g.Count()
                     });
         var winrateDataPoints = new List<DateValue>();
         foreach (var weekGroup in weekGroups)
         {
             winrateDataPoints.Add(
                 new DateValue(FirstDateOfWeek(weekGroup.Year, weekGroup.CalendarWeek), weekGroup.Wins / (double)weekGroup.Total));
             // winrateDataPoints.Add(new DateValue(weekGroup.Date, weekGroup.Wins / (double)weekGroup.Total));
         }
         var color = heroGroup.Key.GetColor();
         PlotModel.Series.Add(
             new LineSeries
                 {
                     Title = heroGroup.Key.ClassName,
                     ItemsSource = winrateDataPoints,
                     MarkerStroke = OxyColors.Black,
                     MarkerType = MarkerType.Circle,
                     DataFieldX = "Date",
                     DataFieldY = "Value",
                     Smooth = true,
                     Color = OxyColor.FromArgb(color.A, color.R, color.G, color.B)
                 });
     }
 }
        private void CalculateWinsAndLosses(HearthStatsDbContext context, Expression<Func<ArenaSession, bool>> filter)
        {
            var arenas = context.ArenaSessions.Where(filter);
            if (!arenas.Any())
            {
                this.WinsAndLosses.Add(new StatModel("Wins", 0));
                this.WinsAndLosses.Add(new StatModel("Losses", 0));
                return;                
            }

            float total = arenas.Sum(a => a.Wins + a.Losses);
            float wins = arenas.Sum(a => a.Wins);
            float losses = arenas.Sum(a => a.Losses);
            this.WinsAndLosses.Clear();
            if (total <= 0)
            {
                this.WinsAndLosses.Add(new StatModel("Wins", 0));
                this.WinsAndLosses.Add(new StatModel("Losses", 0));
                return;
            }

            this.WinsAndLosses.Add(new StatModel(string.Format("Wins: {0}", wins), wins / total * 100));
            this.WinsAndLosses.Add(new StatModel(string.Format("Losses: {0}", losses), losses / total * 100));
        }
        private void CalculateHeroesPlayed(HearthStatsDbContext context, Expression<Func<ArenaSession, bool>> filter)
        {
            var arenas = context.ArenaSessions.Where(filter);
            this.heroesPlayed.IsNotifying = false;
            this.heroesPlayed.Clear();

            int total = arenas.Count();
            if (total == 0)
            {
                return;
            }

            var heroestats = arenas.GroupBy(x => x.Hero).Where(x => x.Any()).Select(
                x => new
                         {
                             x.Key,
                             x.Key.ClassName,
                             Count = x.Count()
                         }).ToList();

            foreach (var hero in heroestats)
            {
                if (hero.Count > 0)
                {
                    this.heroesPlayed.Add(new StatModel(string.Format("{0}: {1}", hero.ClassName, hero.Count), (float)hero.Count / total * 100, hero.Key.GetBrush()));
                }
            }

            this.heroesPlayed.IsNotifying = true;
            this.heroesPlayed.Refresh();
        }
        private void CalculateWinRatios(HearthStatsDbContext context, Expression<Func<ArenaSession, bool>> filter)
        {
            var arenas = context.ArenaSessions.Where(filter);
            // float total = results.Sum(a => a.Games.Count);
            float wins2 = arenas.Count(a => a.Wins <= 2);
            float wins3 = arenas.Count(a => a.Wins == 3);
            float wins4 = arenas.Count(a => a.Wins >= 4 && a.Wins <= 6);
            float wins7 = arenas.Count(a => a.Wins >= 7 && a.Wins <= 11);
            float wins12 = arenas.Count(a => a.Wins == 12);

            WinRatios.IsNotifying = false;
            WinRatios.Clear();
            WinRatios.Add(new StatModel("0-2", wins2));
            WinRatios.Add(new StatModel("3", wins3));
            WinRatios.Add(new StatModel("4-6", wins4));
            WinRatios.Add(new StatModel("7-11", wins7));
            WinRatios.Add(new StatModel("12", wins12));
            WinRatios.IsNotifying = true;
            WinRatios.Refresh();
        }
        private void InitializeDatabase()
        {
            // Only seed when needed
            var dataDir = (string)AppDomain.CurrentDomain.GetData("DataDirectory");
            var seedFile = Path.Combine(dataDir, "db.seed");
            var currentSeed = 0;
            if (File.Exists(seedFile))
            {
                int.TryParse(File.ReadAllText(seedFile), out currentSeed);
            }
            if (currentSeed < Configuration.SeedVersion)
            {
                using (var context = new HearthStatsDbContext())
                {
                    new DbInitializer().InitializeDatabase(context);
                }

                File.WriteAllText(seedFile, Configuration.SeedVersion.ToString(CultureInfo.InvariantCulture));
            }
            else
            {
                using (var context = new HearthStatsDbContext())
                {
                    var settings = context.Settings.FirstOrDefault();
                }
            }
        }