/*
         * Do the rating calculation for each player the number of times specified
         */
        public async Task <Dictionary <int, Player> > DoCalculation(int count, Dictionary <int, Player> players, RatingRule rule, Dictionary <int, List <Result> > playerResults)
        {
            for (int i = 0; i < count; i++)
            {
                await LogStatus($"Running calculations - Iteration {i + 1}");

                foreach (var player in players.Values)
                {
                    // update progress counters
                    int        playerId = player.Id;                                                        //Get Player ID
                    ArrayList  results  = GetRatingResults(player, players, playerResults[playerId], rule); //Get the results of the player's matches
                    RatingInfo rating   = new RatingInfo();
                    if (results != null && results.Count > 0)                                               // skip player if they have no results
                    {
                        rating = CalculatePlayerUTR(player, results, players, rule);
                    }
                    else //No recent result case, this needs to be improved to place players in an inactive & currated state
                    {
                        rating.Rating      = (float)player.Stats.Rating;
                        rating.Reliability = 0;
                    }

                    player.Stats.ActualRating      = Math.Truncate(rating.Rating * 100) / 100; // store actual value, even for benchmarks
                    player.Stats.RatingReliability = rating.Reliability;
                    player.Stats.SubRating         = rating.SubRating;
                    player.Stats.Rating            = rating.Rating;
                    player.Stats.Reliability       = rating.Reliability;
                }
            }
            return(players);
        }
        public RatingInfo CalculatePlayerUTR(Player player, ArrayList results, Dictionary <int, Player> playerRepo, RatingRule rule)
        {
            RatingInfo playerUTR                       = new RatingInfo(); // store player's UTR and reliability
            ArrayList  resultRatingInfoList            = new ArrayList();  // stores the RatingInfo for each match
            var        activeResultsIds                = new List <int>();
            float      SumRatingXReliability           = 0;
            float      SumReliabilityRating            = 0;
            float      SumReliabilityPlayerReliability = 0;
            //stores unique opponent IDs and number of times played
            Dictionary <int, int> opponentsMatchFrequency = CalculateMatchFrequencyReliability(player.Id, results);

            foreach (Result r in results)
            {
                // Calculate Dynamcic Rating and Match Result Reliability Factor for each match, store in list
                var ri = DoResultsCalculation(player, r, results, playerRepo, rule, opponentsMatchFrequency);
                resultRatingInfoList.Add(ri);
                if (ri.weightingFactors.MatchWeight >= rule.eligibleResultsWeightThreshold)
                {
                    activeResultsIds.Add(r.Id);
                }
            }
            // Store active results used in calculation
            player.Stats.ActiveSinglesResults = JsonConvert.SerializeObject(activeResultsIds.ToArray());
            foreach (RatingInfo ri in resultRatingInfoList)
            {
                SumRatingXReliability += ri.Rating * ri.Reliability; // For each match, Dynmic Ratch x Match Reliability
                SumReliabilityRating  += ri.Reliability;             // Sum of Match Reliabilities

                // divide by interpool coefficient so it doesn't skew player reliability
                SumReliabilityPlayerReliability += ri.Reliability / ri.weightingFactors.InterpoolCoeffecient;
            }
            float rating = (SumReliabilityRating == 0.0) ? 0 : (SumRatingXReliability / SumReliabilityRating);

            playerUTR.Rating      = (float)SmoothRating(rating); // Player rating is these number divided
            playerUTR.Rating      = (float)Math.Truncate(100 * playerUTR.Rating) / 100;
            playerUTR.Reliability = CalculatePlayerReliability(SumReliabilityPlayerReliability, rule);
            if (float.IsNaN(playerUTR.Rating))
            {
                System.Diagnostics.Debug.WriteLine(playerUTR.Rating);
            }
            if (player.IsTop700())
            {
                CalculatePlayerSubUTRs(resultRatingInfoList, playerUTR, player.Stats.Id);
            }
            return(playerUTR);
        }
        public RatingInfo DoResultsCalculation(Player playerInfo, Result r, ArrayList results, Dictionary <int, Player> playerRepo, RatingRule rule, Dictionary <int, int> matchFrequency)
        {
            RatingInfo ratingInfo = new RatingInfo
            {
                SurfaceType          = r.SurfaceType,
                Date                 = r.ResultDate,
                IsMastersOrGrandslam = r.IsMastersOrGrandslam
            };
            var opponent = playerRepo[GetOpponentId(playerInfo.Id, r)]; //info about opponent

            //var opponent = GetOpponent(playerInfo.Id, r, playerRepo);
            if (opponent.BenchmarkRating != null && opponent.BenchmarkRating > 0)
            {
                opponent.Stats.Rating = (double)opponent.BenchmarkRating;
            }
            ratingInfo.Rating = CalculateDynamicRating(playerInfo, opponent, r, playerRepo, rule);
            if (float.IsNaN(ratingInfo.Rating))
            {
                System.Diagnostics.Debug.WriteLine(ratingInfo.Rating);
            }

            ratingInfo.AgainstBenchmark = (opponent.Stats.IsBenchmark) ? true : false;
            float opponentFrequency = 0;

            try
            {
                opponentFrequency = (float)matchFrequency[opponent.Id]; // value from dictionary
            }
            catch (Exception e)
            {
                _logger.LogWarning(e, opponent.Id.ToString());
            }
            RatingInfo.WeightingFactors wf = CalculateMatchResultRelibilityFactor(playerInfo, r, opponent, opponentFrequency, ratingInfo.AgainstBenchmark, rule);
            ratingInfo.Reliability      = wf.MatchWeight; //reliability for match
            ratingInfo.weightingFactors = wf;
            return(ratingInfo);
        }
 public void CalculatePlayerSubUTRs(ArrayList resultRatingInfoList, RatingInfo ratingInfo, int playerRatingId)
 {
     ratingInfo.SubRating = new SubRating
     {
         PlayerRatingId = playerRatingId,
         ResultCount    = resultRatingInfoList.Count
     };
     ratingInfo.SubRating.HardCourt             = CalculatePlayerSurfaceUTR(resultRatingInfoList, SurfaceType.Hard, out int hardCount);
     ratingInfo.SubRating.HardCourtCount        = hardCount;
     ratingInfo.SubRating.ClayCourt             = CalculatePlayerSurfaceUTR(resultRatingInfoList, SurfaceType.Clay, out int clayCount);
     ratingInfo.SubRating.ClayCourtCount        = clayCount;
     ratingInfo.SubRating.GrassCourt            = CalculatePlayerSurfaceUTR(resultRatingInfoList, SurfaceType.Grass, out int grassCount);
     ratingInfo.SubRating.GrassCourtCount       = grassCount;
     ratingInfo.SubRating.SixWeek               = CalculatePlayerTimeUTR(DateTime.Now.AddDays(-42), resultRatingInfoList, out int sixCount);
     ratingInfo.SubRating.SixWeekCount          = sixCount;
     ratingInfo.SubRating.EightWeek             = CalculatePlayerTimeUTR(DateTime.Now.AddDays(-56), resultRatingInfoList, out int eightCount);
     ratingInfo.SubRating.EightWeekCount        = eightCount;
     ratingInfo.SubRating.OneMonth              = CalculatePlayerTimeUTR(DateTime.Now.AddMonths(-1), resultRatingInfoList, out int oneCount);
     ratingInfo.SubRating.OneMonthCount         = oneCount;
     ratingInfo.SubRating.ThreeMonth            = CalculatePlayerTimeUTR(DateTime.Now.AddMonths(-3), resultRatingInfoList, out int threeCount);
     ratingInfo.SubRating.ThreeMonthCount       = threeCount;
     ratingInfo.SubRating.GrandSlamMasters      = CalculateAtpMastersUTR(resultRatingInfoList, out int gmCount);
     ratingInfo.SubRating.GrandSlamMastersCount = gmCount;
 }