private void prepareHeadToHeadTab(out List<PlayerStatsRow> teamPMSRList, out List<PlayerStatsRow> oppPMSRList)
        {
            var iown = _curTeam;
            var iopp = _curOpp;

            var dtHTHBS = new DataTable();
            dtHTHBS.Columns.Add("Date");
            dtHTHBS.Columns.Add("Home-Away");
            dtHTHBS.Columns.Add("Result");
            dtHTHBS.Columns.Add("Score");
            dtHTHBS.Columns.Add("GameID");

            var ts = new TeamStats(_curTeam);
            var tsopp = new TeamStats(_curOpp);

            _db = new SQLiteDatabase(MainWindow.CurrentDB);

            if (_dtHTH.Rows.Count > 1)
            {
                _dtHTH.Rows.RemoveAt(_dtHTH.Rows.Count - 1);
            }

            var bsHist = MainWindow.BSHist;

            var bseList =
                bsHist.Where(
                    bse =>
                    (bse.BS.Team1ID == _curTeam && bse.BS.Team2ID == _curOpp)
                    || (bse.BS.Team1ID == _curOpp && bse.BS.Team2ID == _curTeam)).ToList();

            if (rbHTHStatsAnyone.IsChecked.GetValueOrDefault())
            {
                ts = _tst[iown];
                ts.CalcAvg();

                tsopp = _tst[iopp];
                tsopp.CalcAvg();
            }
            else
            {
                foreach (var bse in bseList)
                {
                    TeamStats.AddTeamStatsFromBoxScore(bse.BS, ref ts, ref tsopp, true);
                }
            }

            //ts.CalcMetrics(tsopp);
            //tsopp.CalcMetrics(ts);
            var ls = new TeamStats();
            ls.AddTeamStats(ts, Span.SeasonAndPlayoffsToSeason);
            ls.AddTeamStats(tsopp, Span.SeasonAndPlayoffsToSeason);
            var keys = _pst.Keys.ToList();
            teamPMSRList = new List<PlayerStatsRow>();
            oppPMSRList = new List<PlayerStatsRow>();
            foreach (var key in keys)
            {
                if (_pst[key].TeamF == ts.ID)
                {
                    teamPMSRList.Add(new PlayerStatsRow(_pst[key]));
                }
                else if (_pst[key].TeamF == tsopp.ID)
                {
                    oppPMSRList.Add(new PlayerStatsRow(_pst[key]));
                }
            }

            foreach (var bse in bseList)
            {
                int t1PTS = bse.BS.PTS1;
                int t2PTS = bse.BS.PTS2;
                var bsr = dtHTHBS.NewRow();
                bsr["Date"] = bse.BS.GameDate.ToString().Split(' ')[0];
                if (bse.BS.Team1ID.Equals(_curTeam))
                {
                    bsr["Home-Away"] = "Away";

                    if (t1PTS > t2PTS)
                    {
                        bsr["Result"] = "W";
                    }
                    else
                    {
                        bsr["Result"] = "L";
                    }
                }
                else
                {
                    bsr["Home-Away"] = "Home";

                    if (t2PTS > t1PTS)
                    {
                        bsr["Result"] = "W";
                    }
                    else
                    {
                        bsr["Result"] = "L";
                    }
                }

                bsr["Score"] = bse.BS.PTS1 + "-" + bse.BS.PTS2;
                bsr["GameID"] = bse.BS.ID.ToString();

                dtHTHBS.Rows.Add(bsr);
            }

            _dtHTH.Clear();

            var dr = _dtHTH.NewRow();

            createDataRowFromTeamStats(ts, ref dr, "Averages");

            _dtHTH.Rows.Add(dr);

            dr = _dtHTH.NewRow();

            createDataRowFromTeamStats(tsopp, ref dr, "Opp Avg");

            _dtHTH.Rows.Add(dr);

            dr = _dtHTH.NewRow();

            createDataRowFromTeamStats(ts, ref dr, "Playoffs", true);

            _dtHTH.Rows.Add(dr);

            dr = _dtHTH.NewRow();

            createDataRowFromTeamStats(tsopp, ref dr, "Opp Pl Avg", true);

            _dtHTH.Rows.Add(dr);

            _dvHTH = new DataView(_dtHTH) { AllowNew = false, AllowEdit = false };

            dgvHTHStats.DataContext = _dvHTH;

            var dvHTHBS = new DataView(dtHTHBS) { AllowNew = false, AllowEdit = false };

            dgvHTHBoxScores.DataContext = dvHTHBS;
        }
        /// <summary>Calculates the league PerGame.</summary>
        /// <param name="tst">The team stats dictionary.</param>
        /// <param name="statRange">The stat range.</param>
        /// <returns></returns>
        public static TeamStats CalculateLeagueAverages(Dictionary<int, TeamStats> tst, Span statRange)
        {
            var ls = new TeamStats(-1, "League");
            var teamCount = countTeams(tst, statRange);
            for (var i = 0; i < tst.Count; i++)
            {
                ls.AddTeamStats(tst[i], statRange);
            }
            ls.CalcMetrics(ls, (statRange == Span.Playoffs));

            ls.Record[0] /= teamCount;
            ls.Record[1] /= teamCount;
            ls.PlRecord[0] /= teamCount;
            ls.PlRecord[1] /= teamCount;
            ls.PerGame[TAbbrPG.Weff] /= teamCount;
            ls.PlPerGame[TAbbrPG.Weff] /= teamCount;

            return ls;
        }
        /// <summary>Calculates the yearly stats and updates the yearly stats tab.</summary>
        private void updateYearlyStats()
        {
            _dtYea.Clear();

            var currentDB = MainWindow.CurrentDB;
            _curSeason = MainWindow.CurSeason;
            _maxSeason = SQLiteIO.GetMaxSeason(currentDB);

            var ts = _tst[_curTeam];
            var tsAllSeasons = new TeamStats(-1, "All Seasons");
            var tsAllPlayoffs = new TeamStats(-1, "All Playoffs");
            var tsAll = new TeamStats(-1, "All Games");
            tsAllSeasons.AddTeamStats(ts, Span.Season);
            tsAllPlayoffs.AddTeamStats(ts, Span.Playoffs);
            tsAll.AddTeamStats(ts, Span.SeasonAndPlayoffsToSeason);

            var drcur = _dtYea.NewRow();
            var drcurPl = _dtYea.NewRow();
            createDataRowFromTeamStats(ts, ref drcur, "Season " + MainWindow.GetSeasonName(_curSeason));

            var playedInPlayoffs = false;
            if (ts.PlRecord[0] + ts.PlRecord[1] > 0)
            {
                createDataRowFromTeamStats(ts, ref drcurPl, "Playoffs " + MainWindow.GetSeasonName(_curSeason), true);
                playedInPlayoffs = true;
            }

            //
            var qr = string.Format(@"SELECT * FROM PastTeamStats WHERE TeamID = {0} ORDER BY ""SOrder""", ts.ID);
            var dt = _db.GetDataTable(qr);
            foreach (DataRow dr in dt.Rows)
            {
                var dr4 = _dtYea.NewRow();
                ts = new TeamStats();
                if (ParseCell.GetBoolean(dr, "isPlayoff"))
                {
                    SQLiteIO.GetTeamStatsFromDataRow(ref ts, dr, true);
                    createDataRowFromTeamStats(ts, ref dr4, "Playoffs " + ParseCell.GetString(dr, "SeasonName"), true);
                    tsAllPlayoffs.AddTeamStats(ts, Span.Playoffs);
                    tsAll.AddTeamStats(ts, Span.Playoffs);
                }
                else
                {
                    SQLiteIO.GetTeamStatsFromDataRow(ref ts, dr, false);
                    createDataRowFromTeamStats(ts, ref dr4, "Season " + ParseCell.GetString(dr, "SeasonName"), false);
                    tsAllSeasons.AddTeamStats(ts, Span.Season);
                    tsAll.AddTeamStats(ts, Span.Season);
                }
                _dtYea.Rows.Add(dr4);
            }
            //

            for (var j = 1; j <= _maxSeason; j++)
            {
                if (j != _curSeason)
                {
                    TeamStats tsopp;
                    SQLiteIO.GetTeamStatsFromDatabase(MainWindow.CurrentDB, _curTeam, j, out ts, out tsopp);
                    var dr3 = _dtYea.NewRow();
                    var dr3Pl = _dtYea.NewRow();
                    createDataRowFromTeamStats(ts, ref dr3, "Season " + MainWindow.GetSeasonName(j));

                    _dtYea.Rows.Add(dr3);
                    if (ts.PlRecord[0] + ts.PlRecord[1] > 0)
                    {
                        createDataRowFromTeamStats(ts, ref dr3Pl, "Playoffs " + MainWindow.GetSeasonName(j), true);
                        _dtYea.Rows.Add(dr3Pl);
                    }

                    tsAllSeasons.AddTeamStats(ts, Span.Season);
                    tsAllPlayoffs.AddTeamStats(ts, Span.Playoffs);
                    tsAll.AddTeamStats(ts, Span.SeasonAndPlayoffsToSeason);
                }
                else
                {
                    _dtYea.Rows.Add(drcur);
                    if (playedInPlayoffs)
                    {
                        _dtYea.Rows.Add(drcurPl);
                    }
                }
            }

            _dtYea.Rows.Add(_dtYea.NewRow());

            drcur = _dtYea.NewRow();
            createDataRowFromTeamStats(tsAllSeasons, ref drcur, "All Seasons");
            _dtYea.Rows.Add(drcur);
            drcur = _dtYea.NewRow();
            createDataRowFromTeamStats(tsAllPlayoffs, ref drcur, "All Playoffs");
            _dtYea.Rows.Add(drcur);

            _dtYea.Rows.Add(_dtYea.NewRow());

            drcur = _dtYea.NewRow();
            createDataRowFromTeamStats(tsAll, ref drcur, "All Games");
            _dtYea.Rows.Add(drcur);

            var dvYea = new DataView(_dtYea) { AllowNew = false, AllowEdit = false };

            dgvYearly.DataContext = dvYea;
        }
        /// <summary>Updates the metric stats for the specified team's players.</summary>
        /// <param name="team">1 if the away team's players' metric stats should be updated; anything else for the home team.</param>
        private void updateMetric(int team)
        {
            var ts = new TeamStats(-1, team == 1 ? cmbTeam1.SelectedItem.ToString() : cmbTeam2.SelectedItem.ToString());
            var tsopp = new TeamStats(-1, team == 1 ? cmbTeam2.SelectedItem.ToString() : cmbTeam1.SelectedItem.ToString());

            tryParseBS();
            if (!MainWindow.TempBSE_BS.Done)
            {
                return;
            }

            var bs = MainWindow.TempBSE_BS;

            if (team == 1)
            {
                TeamStats.AddTeamStatsFromBoxScore(bs, ref ts, ref tsopp);
            }
            else
            {
                TeamStats.AddTeamStatsFromBoxScore(bs, ref tsopp, ref ts);
            }

            ts.CalcMetrics(tsopp);
            tsopp.CalcMetrics(ts);
            var ls = new TeamStats(-1);
            ls.AddTeamStats(ts, Span.SeasonAndPlayoffsToSeason);
            ls.AddTeamStats(tsopp, Span.SeasonAndPlayoffsToSeason);

            var pmsrList = new List<PlayerStatsRow>();

            var pbsList = team == 1 ? pbsAwayList : pbsHomeList;

            foreach (var pbs in pbsList)
            {
                if (pbs.PlayerID == -1)
                {
                    continue;
                }

                var ps = _pst[pbs.PlayerID].BinarySerializationClone();
                ps.ResetStats();
                ps.AddBoxScore(pbs, bs.IsPlayoff);
                ps.CalcMetrics(ts, tsopp, ls);
                pmsrList.Add(new PlayerStatsRow(ps));
            }

            pmsrList.Sort((pmsr1, pmsr2) => pmsr1.GmSc.CompareTo(pmsr2.GmSc));
            pmsrList.Reverse();

            var tsr = new TeamStatsRow(ts);

            if (team == 1)
            {
                _psrListAway = new List<PlayerStatsRow>(pmsrList);
                dgvAwayPlayerMetricStats.ItemsSource = _psrListAway;
                dgvAwayTeamMetricStats.ItemsSource = new[] { tsr };
            }
            else
            {
                _psrListHome = new List<PlayerStatsRow>(pmsrList);
                dgvHomePlayerMetricStats.ItemsSource = _psrListHome;
                dgvHomeTeamMetricStats.ItemsSource = new[] { tsr };
            }
        }
        /// <summary>Calculates the league PerGame.</summary>
        /// <param name="playerStats">The player stats.</param>
        /// <param name="teamStats">The team stats.</param>
        /// <returns></returns>
        public static PlayerStats CalculateLeagueAverages(
            Dictionary<int, PlayerStats> playerStats, Dictionary<int, TeamStats> teamStats)
        {
            var lps = new PlayerStats(new Player(-1, -1, "League", "Averages", Position.None, Position.None));
            foreach (var key in playerStats.Keys)
            {
                lps.AddPlayerStats(playerStats[key]);
            }

            var ls = new TeamStats(-2, "League");
            for (var i = 0; i < teamStats.Count; i++)
            {
                ls.AddTeamStats(teamStats[i], Span.Season);
                ls.AddTeamStats(teamStats[i], Span.Playoffs);
            }
            ls.CalcMetrics(ls);
            ls.CalcMetrics(ls, true);
            foreach (var name in PlayerStatsHelper.MetricsNames)
            {
                try
                {
                    lps.Metrics[name] =
                        playerStats.Where(ps => !Double.IsNaN(ps.Value.Metrics[name]) && !Double.IsInfinity(ps.Value.Metrics[name]))
                                   .Average(ps => ps.Value.Metrics[name]);
                }
                catch (InvalidOperationException)
                {
                    lps.Metrics[name] = Double.NaN;
                }
                try
                {
                    lps.PlMetrics[name] =
                        playerStats.Where(ps => !Double.IsNaN(ps.Value.PlMetrics[name]) && !Double.IsInfinity(ps.Value.Metrics[name]))
                                   .Average(ps => ps.Value.PlMetrics[name]);
                }
                catch (InvalidOperationException)
                {
                    lps.Metrics[name] = Double.NaN;
                }
            }

            var playerCount = (uint) playerStats.Count;
            for (var i = 0; i < lps.Totals.Length; i++)
            {
                lps.Totals[i] /= playerCount;
                lps.PlTotals[i] /= playerCount;
            }
            //ps.CalcAvg();
            return lps;
        }
        /// <summary>Calculates all metrics.</summary>
        /// <param name="playerStats">The player stats.</param>
        /// <param name="teamStats">The team stats.</param>
        /// <param name="oppStats">The opposing team stats.</param>
        /// <param name="leagueOv">
        ///     set to <c>true</c> if calling from the LeagueOverview window.
        /// </param>
        /// <param name="playoffs">
        ///     if set to <c>true</c>, the metrics will be calculated for the playoff stats.
        /// </param>
        /// <param name="teamsPerPlayer">
        ///     if set to <c>true</c>, the team stats dictionary is assumed to be per player.
        /// </param>
        public static void CalculateAllMetrics(
            ref Dictionary<int, PlayerStats> playerStats,
            Dictionary<int, TeamStats> teamStats,
            Dictionary<int, TeamStats> oppStats,
            bool leagueOv = false,
            bool playoffs = false,
            bool teamsPerPlayer = false)
        {
            var tCount = teamStats.Count;

            var ls = new TeamStats();
            var tKeys = teamStats.Keys.ToList();
            for (var i = 0; i < tCount; i++)
            {
                var key = tKeys[i];
                if (!playoffs)
                {
                    ls.AddTeamStats(teamStats[key], Span.Season);
                    teamStats[key].CalcMetrics(oppStats[key]);
                    oppStats[key].CalcMetrics(teamStats[key]);
                }
                else
                {
                    ls.AddTeamStats(teamStats[key], Span.Playoffs);
                    teamStats[key].CalcMetrics(oppStats[key], true);
                    oppStats[key].CalcMetrics(teamStats[key], true);
                }
            }
            ls.CalcMetrics(ls, playoffs);

            double lgAvgPER = 0;
            double plLgAvgPER = 0;
            double totalMins = 0;
            double plTotalMins = 0;

            foreach (var playerid in playerStats.Keys.ToList())
            {
                if (playerStats[playerid].TeamF == -1)
                {
                    continue;
                }

                var teamid = playerStats[playerid].TeamF;
                TeamStats ts;
                TeamStats tsopp;
                if (!teamsPerPlayer)
                {
                    ts = teamStats[teamid];
                    tsopp = oppStats[teamid];
                }
                else
                {
                    ts = teamStats[playerid];
                    tsopp = oppStats[playerid];
                }

                playerStats[playerid].CalcMetrics(ts, tsopp, ls, leagueOv, playoffs: playoffs);
                if (!playoffs)
                {
                    if (!(Double.IsNaN(playerStats[playerid].Metrics["aPER"]))
                        && !(Double.IsInfinity(playerStats[playerid].Metrics["aPER"])))
                    {
                        lgAvgPER += playerStats[playerid].Metrics["aPER"] * playerStats[playerid].Totals[PAbbrT.MINS];
                        totalMins += playerStats[playerid].Totals[PAbbrT.MINS];
                    }
                }
                else
                {
                    if (!(Double.IsNaN(playerStats[playerid].PlMetrics["aPER"]))
                        && !(Double.IsInfinity(playerStats[playerid].PlMetrics["aPER"])))
                    {
                        plLgAvgPER += playerStats[playerid].PlMetrics["aPER"] * playerStats[playerid].PlTotals[PAbbrT.MINS];
                        plTotalMins += playerStats[playerid].PlTotals[PAbbrT.MINS];
                    }
                }
            }
            if (!playoffs)
            {
                lgAvgPER /= totalMins;
            }
            else
            {
                plLgAvgPER /= plTotalMins;
            }

            foreach (var playerid in playerStats.Keys.ToList())
            {
                if (playerStats[playerid].TeamF == -1)
                {
                    continue;
                }

                if (!playoffs)
                {
                    playerStats[playerid].calcPER(lgAvgPER);
                }
                else
                {
                    playerStats[playerid].calcPER(plLgAvgPER, true);
                }
            }
        }
        /// <summary>
        ///     Calculates the league PerGame.
        /// </summary>
        /// <param name="playerStats">The player stats.</param>
        /// <param name="teamStats">The team stats.</param>
        /// <returns></returns>
        public static PlayerStats CalculateLeagueAverages(Dictionary<int, PlayerStats> playerStats,
                                                          Dictionary<int, TeamStats> teamStats)
        {
            var lps = new PlayerStats(new Player(-1, -1, "League", "Averages", Position.None, Position.None));
            foreach (int key in playerStats.Keys)
            {
                lps.AddPlayerStats(playerStats[key]);
            }

            var ls = new TeamStats(-2, "League");
            for (int i = 0; i < teamStats.Count; i++)
            {
                ls.AddTeamStats(teamStats[i], Span.Season);
                ls.AddTeamStats(teamStats[i], Span.Playoffs);
            }
            ls.CalcMetrics(ls);
            ls.CalcMetrics(ls, true);
            lps.CalcMetrics(ls, ls, ls, true);
            lps.CalcMetrics(ls, ls, ls, true, playoffs: true);

            var playerCount = (uint) playerStats.Count;
            for (int i = 0; i < lps.Totals.Length; i++)
            {
                lps.Totals[i] /= playerCount;
                lps.PlTotals[i] /= playerCount;
            }
            //ps.CalcAvg();
            return lps;
        }