public override bool Equals(object obj)
            {
                if (obj == null)
                {
                    return(false);
                }
                PlayerStatsJson objAsPlayerStatsJson = obj as PlayerStatsJson;

                if (objAsPlayerStatsJson == null)
                {
                    return(false);
                }
                return(this.AverageMatchesPerDay == objAsPlayerStatsJson.AverageMatchesPerDay &&
                       this.AverageScoreboardPercent == objAsPlayerStatsJson.AverageScoreboardPercent &&
                       this.FavoriteGameMode == objAsPlayerStatsJson.FavoriteGameMode &&
                       this.FavoriteServer == objAsPlayerStatsJson.FavoriteServer &&
                       this.KillToDeathRatio == objAsPlayerStatsJson.KillToDeathRatio &&
                       this.LastMatchPlayed == objAsPlayerStatsJson.LastMatchPlayed &&
                       this.MaximumMatchesPerDay == objAsPlayerStatsJson.MaximumMatchesPerDay &&
                       this.TotalMatchesPlayed == objAsPlayerStatsJson.TotalMatchesPlayed &&
                       this.TotalMatchesWon == objAsPlayerStatsJson.TotalMatchesWon &&
                       this.UniqueServers == objAsPlayerStatsJson.UniqueServers);
            }
        /// <summary>
        /// Returns <see cref="ApiResponse"/> with string representation of <see cref="PlayerStatsJson"/> in body.
        /// </summary>
        /// <param name="name"></param>
        /// <returns><see cref="ApiResponse"/> with string representation of <see cref="PlayerStatsJson"/> in body.</returns>
        public ApiResponse GetStats(string name)
        {
            using (var context = new GameStatsDbDataContext())
            {
                var currPlayer = context.Players.Where(pl => pl.name == name).FirstOrDefault();
                if (currPlayer == null)
                {
                    return(new ApiResponse(HttpStatusCode.NotFound));
                }

                int currPlayerId = currPlayer.id;

                PlayerStatsJson playerStats = new PlayerStatsJson();

                /*totalMatchesPlayed*/
                playerStats.TotalMatchesPlayed =
                    context.PlayersInMatches
                    .Where(m => m.player_id == currPlayerId)
                    .Count();

                /*totalMatchesWon*/
                playerStats.TotalMatchesWon =
                    context.Matches
                    .Where(m => m.winner_id == currPlayerId)
                    .Count();

                // join player's row in match with info about match
                var playerMatches =
                    (from playerInMatch in context.PlayersInMatches
                     where playerInMatch.player_id == currPlayerId
                     join match in context.Matches
                     on playerInMatch.match_id equals match.id
                     select new
                {
                    matchInfo = match,
                    playerInfo = playerInMatch
                });

                // group by server_id, then count it
                // use it in follow queries
                var orderedUniqueServers =
                    (from p in playerMatches
                     group p.matchInfo.server_id by p.matchInfo.server_id into serverGroup
                     orderby serverGroup.Count() descending
                     select serverGroup);

                /*favoriteServer*/
                // take top1 server endpoint
                int top1serverId = orderedUniqueServers.First().Key;
                playerStats.FavoriteServer =
                    context.Servers
                    .Where(s => s.id == top1serverId)        // top1 server
                    .First()
                    .endpoint;

                /*uniqueServers*/
                // count all unqiue servers
                playerStats.UniqueServers =
                    orderedUniqueServers.Count();

                /*favoriteGM*/
                int favGMid =
                    (from p in playerMatches
                     group p.matchInfo by p.matchInfo.gm_id into gmGroup
                     orderby gmGroup.Count() descending
                     select gmGroup)
                    .First().Key;
                playerStats.FavoriteGameMode =
                    context.GameModes
                    .Where(gm => gm.id == favGMid)
                    .First().name;

                /*averageScoreboardPercent*/

                playerStats.AverageScoreboardPercent =
                    (from p in playerMatches
                     let players_count = p.matchInfo.players_count
                                         select(players_count == 1 ?
                                                100 :
                                                (players_count - p.playerInfo.player_rank)
                                                * 100.0
                                                / (players_count - 1)
                                                )
                    )
                    .Average();

                /*matchesPerDay*/
                var matchesPerDays =
                    (from p in playerMatches
                     group p.matchInfo by p.matchInfo.timestamp_day into matchGroup
                     //group by constant to use 2 aggregates
                     group matchGroup by 1 into matchGroup
                     select new
                {
                    maximum = matchGroup.Max
                                  (m => m.Count()),
                    average = matchGroup.Average
                                  (m => m.Count())
                }).First();
                /*maximumMatchesPerDay*/
                playerStats.MaximumMatchesPerDay =
                    matchesPerDays.maximum;
                /*averageMatchesPerDay*/
                playerStats.AverageMatchesPerDay =
                    matchesPerDays.average;

                /*lastMatchPlayed*/
                playerStats.LastMatchPlayed =
                    (from p in playerMatches
                     orderby p.matchInfo.timestamp descending
                     select p.matchInfo.timestamp)
                    .First();
                // add "Z" to date
                playerStats.LastMatchPlayed = DateTime.SpecifyKind(playerStats.LastMatchPlayed, DateTimeKind.Utc);

                /*killToDeathRatio*/
                playerStats.KillToDeathRatio =
                    (from p in playerMatches
                     //group by constant to use 2 aggregates
                     group p.playerInfo by 1 into gr
                     select(double) gr.Sum(x => x.kills) /
                     gr.Sum(x => x.deaths))
                    .First();

                return(new ApiResponse(
                           body: JsonConvert.SerializeObject(playerStats)));
            }
        }