package com.apixandru.rummikub2;

import com.apixandru.games.rummikub.api.GameEventListener;
import com.apixandru.games.rummikub.api.GameOverReason;
import com.apixandru.rummikub.StateChangeListener;
import com.apixandru.rummikub.waiting.StartGameListener;
import com.apixandru.rummikub.waiting.WaitingRoomConfigurator;
import com.apixandru.rummikub.waiting.WaitingRoomListener;
import com.apixandru.rummikub2.game.GameConfigurerImpl;

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

/**
 * @author Alexandru-Constantin Bledea
 * @since April 10, 2016
 */
class RummikubImpl implements Rummikub<Integer>, GameEventListener, StartGameListener, WaitingRoomConfigurator {

    private final Map<String, StateChangeListener<Integer>> players = new HashMap<>();

    private final List<WaitingRoomListener> waitingRoomListeners = new ArrayList<>();

    private static boolean isEmpty(final String string) {
        return null == string || string.isEmpty();
    }

    @Override
    public void register(final String playerName, final StateChangeListener<Integer> listener) throws RummikubException {
        if (null == listener) {
            throw new RummikubException("Listener is missing.");
        }
        if (isEmpty(playerName)) {
            throw new RummikubException("Name is missing.");
        }
        if (players.containsKey(playerName)) {
            throw new RummikubException("Name already taken.");
        }
        addPlayer(playerName, listener);
    }

    private void addPlayer(final String playerName, final StateChangeListener<Integer> listener) {
        players.put(playerName, listener);
        broadcastPlayerJoined(playerName);
    }

    private void broadcastPlayerJoined(final String playerName) {
        waitingRoomListeners
                .forEach(waitingRoomListener -> waitingRoomListener.playerJoined(playerName));
    }

    private void goToWaitingRoom() {
        players.values()
                .forEach(listener -> listener.enteredWaitingRoom(this));
    }

    @Override
    public void newTurn(final String player) {

    }

    @Override
    public void gameOver(final String player, final GameOverReason reason) {
        goToWaitingRoom();
    }

    @Override
    public void startGame() {
        final GameConfigurerImpl gameConfigurer = new GameConfigurerImpl();
        gameConfigurer.addGameEventListener(this);
        players.values()
                .forEach(listener -> listener.enteredGame(gameConfigurer));
    }

    @Override
    public void registerListener(final WaitingRoomListener listener) {
        waitingRoomListeners.add(listener);
    }

    @Override
    public StartGameListener newStartGameListener() {
        return this;
    }

}

@@ -886,24 +886,66 @@
 yList%3C%3E();%0A%0A
+    private State state = State.WAITING;%0A%0A
     private 
@@ -986,24 +986,24 @@
 g string) %7B%0A
-
         retu
@@ -1184,16 +1184,216 @@
 ption %7B%0A
+        validateCanJoin(playerName, listener);%0A        addPlayer(playerName, listener);%0A    %7D%0A%0A    private void validateCanJoin(final String playerName, final StateChangeListener%3CInteger%3E listener) %7B%0A
         
@@ -1730,40 +1730,128 @@
     
-addPlayer(playerName, listener);
+if (State.WAITING != state) %7B%0A            throw new RummikubException(%22There is an ongoing game, try later.%22);%0A        %7D
 %0A   
@@ -2374,24 +2374,55 @@
 oom(this));%0A
+        state = State.WAITING;%0A
     %7D%0A%0A    @
@@ -2878,24 +2878,55 @@
 nfigurer));%0A
+        state = State.PLAYING;%0A
     %7D%0A%0A    @
@@ -3120,24 +3120,24 @@
 istener() %7B%0A
-
         retu
@@ -3152,10 +3152,67 @@
 %0A    %7D%0A%0A
+    private enum State %7B%0A        WAITING, PLAYING%0A    %7D%0A%0A
 %7D%0A

add state