package fr.aumgn.diamondrush.game;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.bukkit.World;
import org.bukkit.entity.Player;

import fr.aumgn.bukkitutils.util.Vector;
import fr.aumgn.diamondrush.Util;
import fr.aumgn.diamondrush.exception.NoSuchTeam;
import fr.aumgn.diamondrush.exception.NotEnoughTeams;
import fr.aumgn.diamondrush.exception.PlayerNotInGame;
import fr.aumgn.diamondrush.region.GameSpawn;

public class Game {

    private World world;
    private GameSpawn spawn;
    private Map<String, Team> teams;
    private Map<Player, Team> players;
    private Spectators spectators;
    private int turnCount;
    private GameStatistics statistics;

    public Game(Map<String, TeamColor> teamsMap, World world, Vector spawnPoint, int lives) {
        this.teams = new LinkedHashMap<String, Team>();

        lives = Math.max(4, lives);
        lives = Math.min(8, lives);
        for (Map.Entry<String, TeamColor> teamEntry : teamsMap.entrySet()) {
            Team team = new Team(teamEntry.getKey(),
                    teamEntry.getValue(), lives);
            teams.put(teamEntry.getKey(), team);
        }
        if (teams.keySet().size() < 2) {
            throw new NotEnoughTeams();
        }

        this.world = world;
        spawn = GameSpawn.newFromTeamsNumber(spawnPoint,
                teams.values().size());
        players = new HashMap<Player, Team>();
        spectators = new Spectators();
        turnCount = -1;
        statistics = new GameStatistics();
    }

    public World getWorld() {
        return world;
    }

    public GameSpawn getSpawn() {
        return spawn;
    }

    public Team getTeam(String name) {
        if (!teams.containsKey(name)) {
            throw new NoSuchTeam(name);
        }
        return teams.get(name);
    }

    public Team getTeam(Player player) {
        if (!players.containsKey(player)) {
            throw new PlayerNotInGame();
        }
        return players.get(player);
    }

    public Spectators getSpectators() {
        return spectators;
    }

    public int getTurnCount() {
        return turnCount;
    }

    public void incrementTurnCount() {
        ++turnCount;
    }

    public void sendMessage(String message) {
        for (Team team : getTeams()) {
            team.sendMessage(message);
        }
        for (Player spectator : spectators) {
            spectator.sendMessage(message);
        }
    }

    public boolean contains(Player player) {
        return players.containsKey(player);
    }

    public List<Team> getTeams() {
        return new ArrayList<Team>(teams.values());
    }

    public Team getTeamWithMinimumPlayers() {
        int minimum = Integer.MAX_VALUE;
        List<Team> roulette = null; 
        for (Team team : getTeams()) {
            int size = 0;
            for (Player player : team.getPlayers()) {
                if (player.isOnline()) {
                    size++;
                }
            }

            if (size < minimum) {
                minimum = size;
                roulette = new ArrayList<Team>();
                roulette.add(team);
            } else if (size == minimum) {
                roulette.add(team);
            } 
        }

        return Util.pickRandom(roulette);
    }

    public void addPlayer(Player player, Team team) {
        team.addPlayer(player);
        players.put(player, team);
    }

    public void removePlayer(Player player) {
        Team team = getTeam(player);
        team.removePlayer(player);
        players.remove(player);
    }

    public void removeTeam(Team team) {
        teams.remove(team.getName());
        for (Player player : team.getPlayers()) {
            players.remove(player);
        }
    }

    public GameStatistics getStatistics() {
        return statistics;
    }
}

@@ -75,32 +75,58 @@
 a.util.HashMap;%0A
+import java.util.HashSet;%0A
 import java.util
@@ -185,16 +185,38 @@
 til.Map;
+%0Aimport java.util.Set;
 %0A%0Aimport
@@ -661,16 +661,49 @@
  teams;%0A
+    private Set%3CString%3E players;%0A
     priv
@@ -723,32 +723,36 @@
 r, Team%3E players
+Team
 ;%0A    private Sp
@@ -1531,24 +1531,69 @@
    players =
+ new HashSet%3CString%3E();%0A        playersTeam =
  new HashMap
@@ -2083,26 +2083,33 @@
 contains
-Key
 (player
+.getName()
 )) %7B%0A   
@@ -2148,32 +2148,475 @@
 me();%0A        %7D%0A
+%0A        // Update playerTeams cache if needed.%0A        if (!playersTeam.containsKey(player)) %7B%0A            for (Map.Entry%3CPlayer, Team%3E entry : playersTeam.entrySet()) %7B%0A                if (entry.getKey().getName().equalsIgnoreCase(player.getName())) %7B%0A                    playersTeam.remove(entry.getKey());%0A                    playersTeam.put(player, entry.getValue());%0A                    break;%0A                %7D%0A            %7D%0A        %7D%0A%0A
         return p
@@ -2621,16 +2621,20 @@
  players
+Team
 .get(pla
@@ -3169,26 +3169,33 @@
 contains
-Key
 (player
+.getName()
 );%0A    %7D
@@ -4042,16 +4042,59 @@
 players.
+add(player.getName());%0A        playersTeam.
 put(play
@@ -4254,24 +4254,70 @@
 emove(player
+.getName());%0A        playersTeam.remove(player
 );%0A    %7D%0A%0A  
@@ -4471,24 +4471,74 @@
 emove(player
+.getName());%0A            playersTeam.remove(player
 );%0A        %7D

Fix player caching