function lobby.update_stats(map_id, mode, win, player_count, play_time)
   local stats = lobby.savedata.stats[map_id] or {}
   local server_stats = lobby.savedata.stats['server'] or {}
   stats.solo_play = stats.solo_play or 0
   stats.multi_play = stats.multi_play or 0
   stats.winner_traitor = stats.winner_traitor or 0
   stats.winner_team = stats.winner_team or 0
   stats.player_count = stats.player_count or 0
   stats.max_players = stats.max_players or 0
   stats.max_play_time = stats.max_play_time or 0
   stats.avg_play_time = stats.avg_play_time or 0
   server_stats.max_players = server_stats.max_players or 0
   server_stats.most_played = server_stats.most_played or 0
   server_stats.team_wins = server_stats.team_wins or 0
   server_stats.traitor_wins = server_stats.traitor_wins or 0
   server_stats.max_play_time = server_stats.max_play_time or 0
   if win == 'traitor' then
      stats.winner_traitor = stats.winner_traitor + 1
      if stats.winner_traitor > server_stats.traitor_wins then
         server_stats.traitor_wins = stats.winner_traitor
         server_stats.traitor_wins_id = map_id
      end
   elseif win == 'team' then
      stats.winner_team = stats.winner_team + 1
      if stats.winner_team > server_stats.team_wins then
         server_stats.team_wins = stats.winner_team
         server_stats.team_wins_id = map_id
      end
   end
   if player_count then --takes an integer as input
      local count = stats.multi_play
      local avg = stats.player_count
      local total = count * avg
      local player_count_avg = (total + player_count) / (count + 1)
      stats.player_count = player_count_avg
      if player_count > stats.max_players then
         stats.max_players = player_count
      end
      if player_count > server_stats.max_players then
         server_stats.max_players = player_count
         server_stats.max_players_id = map_id
      end
   end
   if mode == 'solo' then --Solo sessions played.
      stats.solo_play = stats.solo_play + 1
   elseif mode == 'player' then --Team sessions played.
      stats.multi_play = stats.multi_play + 1
      if stats.multi_play > server_stats.most_played then
         server_stats.most_played = stats.multi_play
         server_stats.most_played_id = map_id
      end
   end
   if play_time then
      local avg = stats.avg_play_time
      local count = stats.multi_play
      local total = count * avg
      local avg_play_time = (total + play_time) / (count + 1)
      stats.avg_play_time = avg_play_time
      if play_time > stats.max_play_time then
         stats.max_play_time = play_time
      end
      if play_time > server_stats.max_play_time then
         server_stats.max_play_time = play_time
         server_stats.max_play_time_id = map_id
      end
   end
   lobby.savedata.stats[map_id] = stats
   lobby.savedata.stats['server'] = server_stats
end

function lobby.retrieve_stats(map_id)
   local formspec = 'formspec_version[3]'..
   'size[16,9]'..
   'background[-1,-1;18,11;lobby_stats.png]'
   if lobby.savedata.stats[map_id] then
      local data = lobby.savedata.data[map_id]
      local map_name = data['map_name'] or map_id
      local stats = lobby.savedata.stats[map_id]
      local solo = stats.solo_play
      local player = stats.multi_play
      local traitor = stats.winner_traitor
      local team = stats.winner_team
      local avg_players = stats.player_count
      local avg_play_time = stats.avg_play_time or 0
      local max_play_time = stats.max_play_time or 0
      local max = stats.max_players or 0
      if avg_players > max then
         avg_players = max
      end
      local avg = string.format("%.2f", avg_players)
      avg_play_time = string.format("%.2f", avg_play_time)
      max_play_time = string.format("%.2f", max_play_time)
      formspec = formspec ..
         'label[.5,.5;Viewing stats for '..map_name..', ('..map_id..')]'..
         'textarea[.5,1;7.5,4;;;   This level has been played '..player..' times.'..
         ' On average '..avg..' players join a session. The most ever recorded was '..max..'!'..
         ' The average game lasts '..avg_play_time..' seconds. The longest game on record was '..max_play_time..' seconds!'..
         '   The traitor has won '..traitor..' games, whereas '..team..' have been team wins.\n'..
         '   This level has been visited by single players '..solo..' time(s).]'..
         'textarea[8.5,.5;7,4.5;;;   What does this all mean and why should you care?\n'..
         '   If you find that your level\'s wins strongly favor one party you might want to tweak the number of tasks,'..
         ' the granted XP, or the required XP. People are more likely to play your level when the chances of winning are fairly even.'..
         ' You may find that the wins don\'t add up to the times played, that is due to crashes. :(]'

   else
      formspec = formspec ..
         'formspec_version[3]'..
         'size[16,9]'..
         'background[-1,-1;18,11;lobby_stats.png]'..
         'label[.5,2;No data on this level yet! Get some friends and play a round.]'

   end
   formspec = formspec .. lobby.server_stats()
   return formspec
end

function lobby.server_stats()
   local stats = lobby.savedata.stats['server']
   local max_players = stats.max_players
   local max_id = stats.max_players_id
   local max_name = lobby.savedata.id_2_name[max_id] or 'undefined'
   local most_players = stats.most_played
   local most_id = stats.most_played_id
   local most_name = lobby.savedata.id_2_name[most_id] or 'undefined'
   local traitor_wins = stats.traitor_wins
   local traitor_id = stats.traitor_wins_id
   local traitor_name = lobby.savedata.id_2_name[traitor_id] or 'undefined'
   local team_wins = stats.team_wins
   local team_id = stats.team_wins_id
   local team_name = lobby.savedata.id_2_name[team_id] or 'undefined'
   local max_play_time = stats.max_play_time or 0
   local max_play_time_id = stats.max_play_time_id
   local max_play_time_name = lobby.savedata.id_2_name[max_play_time_id] or 'undefined'
   max_play_time = string.format("%.2f", max_play_time)
   local formspec =
      'textarea[.5,5.25;15,3.25;;;Serverwide Stats and Rankings:\n'..
      max_name..' has the highest player count of any level with '..max_players..' playing at once.\n'..
      most_name..' is the most played level, being played '..most_players..' times.\n'..
      'Traitors have won '..traitor_wins..' times on '..traitor_name..'.\n'..
      'Teams have won '..team_wins..' times on '..team_name..'.\n'..
      max_play_time_name..' has the longest play time on record at '..max_play_time..' seconds!]'

   return formspec
end

function lobby.stats_overview(name, max)
   local formspec =
      'formspec_version[3]'..
      'size[16,9]'..
      'background[-1,-1;18,11;lobby_stats.png]'..
      'label[.5,.5;Viewing stats for your maps with auto assigned IDs.]'..
      'tableoptions[background=#00000000;border=false;highlight_text=#000000;highlight=#6e9fca]'..
      'tablecolumns[text,width=16;text,align=right;text,align=right;text,align=right;text,align=right;text,align=right;text,align=right;text,align=right]'..
      'table[.5,1;15,7.5;stats;Map Name,Play Count,   Avg Players,   Avg Play Time,   Traitor Wins,   Team Wins,   Max Players,   Solo Visits,'
   for i = 1, max do
      local map_id = name..'_'..i
      local data = lobby.savedata.data[map_id]
      if data then
         local map_name = data['map_name'] or '[unnamed]'
         local stats = lobby.savedata.stats[map_id]
         if stats then
            local solo = stats.solo_play or 0
            local player = stats.multi_play or 0
            local traitor = stats.winner_traitor or 0
            local team = stats.winner_team or 0
            local avg_play_time = stats.avg_play_time or 0
            local avg_players = stats.player_count or 0
            local max = stats.max_players or 0
            avg_play_time = string.format("%.2f", avg_play_time)
            formspec = formspec ..
            map_name..','..player..','..avg_players..','..avg_play_time..','..traitor..','..team..','..max..','..solo..','
         end
      end
   end
   formspec = formspec ..']'
   return formspec
end

minetest.register_chatcommand('stats', {
   description = 'View stats on a level. Provide no name to see all your stats.',
   func = function(name, map_name)
      if lobby.savedata.name_2_id[map_name] then
         local map_id = lobby.savedata.name_2_id[map_name]
         if lobby.savedata.IDs[map_id] then
            local data = lobby.savedata.data[map_id]
            if data.owner_name == name or minetest.check_player_privs(name, {server = true}) then
               minetest.show_formspec(name, 'lobby:stats', lobby.retrieve_stats(map_id))
            end
         end
      else
         local i = 1
         local map_id = name..'_'..i
         while lobby.savedata.IDs[map_id] do
            i = i + 1
            map_id = name..'_'..i
         end
         minetest.show_formspec(name, 'lobby:stats_overview', lobby.stats_overview(name, i))
      end
   end
})
