package controller;
import action.IUserActionProvider;
import action.UserAction;
import org.apache.log4j.Logger;
import streams.IStreamCommutator;
import util.ClassName;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class PlayersController {
private static final Logger logger = Logger.getLogger(ClassName.getCurrentClassName());
private static final String NETWORK_PROBLEM_EXCEPTION_MESSAGE = "Network problem";
private static final int NOT_PLAYING = -1;
private boolean isPlayerSwitchEnabled = true;
public interface Delegate {
public void callDelegate(Object object);
}
private final Map<UserAction, Delegate> actionMap = new HashMap<>();
private final IStreamCommutator commutator;
private final IUserActionProvider playersActionRetriever;
private final int totalPlayers;
private int currentPlayer = 0;
public PlayersController(IUserActionProvider actionProvider, IStreamCommutator commutator, int firstPlayerIndex) {
if (actionProvider == null || commutator == null) {
throw new IllegalArgumentException();
}
logger.debug("creating player controller");
this.playersActionRetriever = actionProvider;
this.commutator = commutator;
this.totalPlayers = commutator.getIOStreamsCount();
setFirstPlayer(firstPlayerIndex);
logger.debug("player controller created");
}
public void disablePlayerSwitch() {
isPlayerSwitchEnabled = false;
}
private void setFirstPlayer(int firstPlayerIndex) {
if (((totalPlayers - 1) <= firstPlayerIndex) || (firstPlayerIndex < 0)) {
throw new IllegalArgumentException(
String.format("player index is %d, total players %d", firstPlayerIndex, totalPlayers));
} else {
logger.debug("Setting first player to " + firstPlayerIndex);
currentPlayer = firstPlayerIndex;
}
}
public void setActionDelegate(final UserAction action, final Delegate delegate) {
logger.debug("adding new action " + action);
actionMap.put(action, delegate);
}
public void switchNextPlayer() {
if (isPlayerSwitchEnabled) {
logger.debug("switching to the next player from " + currentPlayer);
currentPlayer++;
currentPlayer = (currentPlayer == totalPlayers) ? 0 : currentPlayer;
logger.debug("next player is " + currentPlayer);
} else {
logger.warn("can't switch player, players switch disabled");
}
}
public int getCurrentLocalPlayer() {
int playerIndex = currentPlayer;
logger.debug("looking for local player");
do {
if (!commutator.isRemoteIOStream(playerIndex)) {
logger.debug("player " + playerIndex + " is not remote");
return playerIndex;
} else {
logger.debug("player " + playerIndex + " is remote, looking for next player");
playerIndex = (playerIndex == 0) ? totalPlayers - 1 : playerIndex - 1;
}
} while (playerIndex != currentPlayer);
logger.warn("no local players");
return NOT_PLAYING;
}
public int getCurrentPlayer() {
return currentPlayer;
}
public void waitPlayerAction() throws IOException {
logger.debug("waiting for user input");
String line = getActionString();
final UserAction action = playersActionRetriever.getUserAction(line);
logger.debug("user input is qualified as " + action);
executeAction(line, action, currentPlayer);
}
private String getActionString() throws IOException {
String actionString = commutator.readLine(currentPlayer);
logger.debug("user input is " + actionString);
if (actionString == null) {
logger.warn("user input is null string");
throw new IOException(NETWORK_PROBLEM_EXCEPTION_MESSAGE);
}
return actionString;
}
private void executeAction(String line, UserAction action, int playerIndex) {
if (actionMap.containsKey(action)) {
logger.debug("executing associated with action " + action + "");
actionMap.get(action).callDelegate(playersActionRetriever.getLastUserActionData());
notifyRemotePlayer(line, action, playerIndex);
} else {
logger.warn("don't know what to do with action " + action);
}
}
private void notifyRemotePlayer(String line, UserAction action, int playerIndex) {
if (action != UserAction.BAD_INPUT) {
logger.debug("notifying remote players with action " + action + " and command " + line);
commutator.writeLineBroadcast(line, playerIndex);
} else {
logger.warn("user action is " + action + " so can't notify remote players");
}
}
}