package no.asgari.civilization.server.action;
import com.mongodb.DB;
import lombok.extern.log4j.Log4j;
import no.asgari.civilization.server.dto.TurnDTO;
import no.asgari.civilization.server.email.SendEmail;
import no.asgari.civilization.server.misc.CivUtil;
import no.asgari.civilization.server.misc.SecurityCheck;
import no.asgari.civilization.server.model.GameLog;
import no.asgari.civilization.server.model.PBF;
import no.asgari.civilization.server.model.PlayerTurn;
import no.asgari.civilization.server.model.Playerhand;
import org.mongojack.JacksonDBCollection;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import static java.util.stream.Collectors.toList;
@Log4j
public class TurnAction extends BaseAction {
private final JacksonDBCollection<PBF, String> pbfCollection;
public TurnAction(DB db) {
super(db);
this.pbfCollection = JacksonDBCollection.wrap(db.getCollection(PBF.COL_NAME), PBF.class, String.class);
}
public void updateSOT(String pbfId, String playerId, TurnDTO turnDTO) {
PBF pbf = findPBFById(pbfId);
Playerhand playerhand = getPlayerhandByPlayerId(playerId, pbf);
updateTurn(playerId, turnDTO, pbf, playerhand);
Thread thread = new Thread(() -> {
pbf.getPlayers()
.stream()
.filter(p -> !p.getUsername().equals(playerhand.getUsername()))
.filter(CivUtil::shouldSendEmailInGame)
.forEach(p -> SendEmail.sendMessage(p.getEmail(), "Start of turn updated", playerhand.getUsername() + " has updated start of turn with " +
"the following order\n:" + turnDTO.getOrder()
+ ".\n\nLogin to " + SendEmail.gamelink(pbfId) + " to see the order", playerhand.getPlayerId())
);
});
thread.start();
pbfCollection.updateById(pbfId, pbf);
super.createLog(pbfId, GameLog.LogType.SOT, playerId);
}
public void updateTrade(String pbfId, String playerId, TurnDTO turnDTO) {
PBF pbf = findPBFById(pbfId);
Playerhand playerhand = getPlayerhandByPlayerId(playerId, pbf);
updateTurn(playerId, turnDTO, pbf, playerhand);
Thread thread = new Thread(() -> {
pbf.getPlayers()
.stream()
.filter(p -> !p.getUsername().equals(playerhand.getUsername()))
.filter(CivUtil::shouldSendEmailInGame)
.forEach(p -> SendEmail.sendMessage(p.getEmail(), "Trade updated", playerhand.getUsername() + " has updated trade with " +
"the following order:\n" + turnDTO.getOrder()
+ ".\n\nLogin to " + SendEmail.gamelink(pbfId) + " to see the order", playerhand.getPlayerId())
);
});
thread.start();
pbfCollection.updateById(pbfId, pbf);
super.createLog(pbfId, GameLog.LogType.TRADE, playerId);
}
public void updateCM(String pbfId, String playerId, TurnDTO turnDTO) {
PBF pbf = findPBFById(pbfId);
Playerhand playerhand = getPlayerhandByPlayerId(playerId, pbf);
updateTurn(playerId, turnDTO, pbf, playerhand);
Thread thread = new Thread(() -> {
pbf.getPlayers()
.stream()
.filter(p -> !p.getUsername().equals(playerhand.getUsername()))
.filter(CivUtil::shouldSendEmailInGame)
.forEach(p -> {
SendEmail.sendMessage(p.getEmail(), "City management updated", playerhand.getUsername() + " has updated city management with " +
"the following order:\n" + turnDTO.getOrder()
+ ".\n\nLogin to " + SendEmail.gamelink(pbfId) + " to see the order", playerhand.getPlayerId());
}
);
});
thread.start();
pbfCollection.updateById(pbfId, pbf);
super.createLog(pbfId, GameLog.LogType.CM, playerId);
}
public void updateMovement(String pbfId, String playerId, TurnDTO turnDTO) {
PBF pbf = findPBFById(pbfId);
Playerhand playerhand = getPlayerhandByPlayerId(playerId, pbf);
updateTurn(playerId, turnDTO, pbf, playerhand);
Thread thread = new Thread(() -> {
pbf.getPlayers()
.stream()
.filter(p -> !p.getUsername().equals(playerhand.getUsername()))
.filter(CivUtil::shouldSendEmailInGame)
.forEach(
p -> SendEmail.sendMessage(p.getEmail(), "Movement updated", playerhand.getUsername() + " has updated movement with " +
"the following order:\n" + turnDTO.getOrder()
+ ".\n\nLogin to " + SendEmail.gamelink(pbfId) + " to see the order", playerhand.getPlayerId())
);
});
thread.start();
pbfCollection.updateById(pbfId, pbf);
super.createLog(pbfId, GameLog.LogType.MOVEMENT, playerId);
}
public void updateResearch(String pbfId, String playerId, TurnDTO turnDTO) {
PBF pbf = findPBFById(pbfId);
Playerhand playerhand = getPlayerhandByPlayerId(playerId, pbf);
updateTurn(playerId, turnDTO, pbf, playerhand);
Thread thread = new Thread(() -> {
pbf.getPlayers()
.stream()
.filter(p -> !p.getUsername().equals(playerhand.getUsername()))
.filter(CivUtil::shouldSendEmailInGame)
.forEach(p -> SendEmail.sendMessage(p.getEmail(), "Research updated", playerhand.getUsername() + " has updated research with " +
"the following order:\n" + turnDTO.getOrder()
+ ".\n\nLogin to " + SendEmail.gamelink(pbfId) + " to see the order", playerhand.getPlayerId())
);
});
thread.start();
pbfCollection.updateById(pbfId, pbf);
super.createLog(pbfId, GameLog.LogType.RESEARCH, playerId);
}
/**
* Each player can add a new turn so they can start new to write new orders
*/
public void addNewTurn(String pbfId, String playerId, int turnNumber) {
PBF pbf = findPBFById(pbfId);
Playerhand playerhand = getPlayerhandByPlayerId(playerId, pbf);
Optional<PlayerTurn> turnOptional = playerhand.getPlayerTurns().stream()
.filter(p -> p.getTurnNumber() == turnNumber)
.findAny();
if (!turnOptional.isPresent()) {
playerhand.getPlayerTurns().add(new PlayerTurn(playerhand.getUsername(), turnNumber));
}
}
private PlayerTurn getPlayerTurn(TurnDTO turnDTO, Set<PlayerTurn> playerturns, String username) {
PlayerTurn playerTurn = playerturns.stream()
.filter(t -> t.getTurnNumber() == turnDTO.getTurnNumber())
.findFirst()
.orElse(new PlayerTurn(username, turnDTO.getTurnNumber()));
playerTurn.setUsername(username);
return playerTurn;
}
public List<PlayerTurn> getAllPublicTurns(String pbfId) {
PBF pbf = findPBFById(pbfId);
return pbf.getPublicTurns().values().stream()
.sorted()
.map(p -> {
//Remove the last order in the history
p.getSotHistory().remove(p.getSot());
p.getTradeHistory().remove(p.getTrade());
p.getCmHistory().remove(p.getCm());
p.getMovementHistory().remove(p.getMovement());
p.getResearchHistory().remove(p.getResearch());
return p;
})
.collect(toList());
}
public Set<PlayerTurn> getPlayersTurns(String pbfId, String playerId) {
PBF pbf = findPBFById(pbfId);
Playerhand playerhand = getPlayerhandByPlayerId(playerId, pbf);
Set<PlayerTurn> playerTurns = playerhand.getPlayerTurns();
if (playerTurns.isEmpty()) {
playerhand.getPlayerTurns().add(new PlayerTurn(playerhand.getUsername(), 1));
pbfCollection.updateById(pbfId, pbf);
}
return playerTurns;
}
private void updateTurn(String playerId, TurnDTO turnDTO, PBF pbf, Playerhand playerhand) {
if (!SecurityCheck.hasUserAccess(pbf, playerId)) {
log.error("User with id " + playerId + " has no access to pbf " + pbf.getName());
throw new WebApplicationException(Response.Status.FORBIDDEN);
}
Set<PlayerTurn> playerturns = playerhand.getPlayerTurns();
PlayerTurn playerTurn = updatePrivatePlayerturn(turnDTO, playerhand, playerturns);
addTurnInPBF(pbf, playerTurn);
}
private void addTurnInPBF(PBF pbf, PlayerTurn playerTurn) {
// Cant get map serialization to work in jackson
//final TurnKey turnKey = new TurnKey(playerTurn.getTurnNumber(), playerTurn.getUsername());
pbf.getPublicTurns().put(playerTurn.getTurnNumber() + playerTurn.getUsername(), playerTurn);
pbfCollection.updateById(pbf.getId(), pbf);
}
private PlayerTurn updatePrivatePlayerturn(TurnDTO turnDTO, Playerhand playerhand, Set<PlayerTurn> playerturns) {
PlayerTurn pt = getPlayerTurn(turnDTO, playerturns, playerhand.getUsername());
if ("SOT".equalsIgnoreCase(turnDTO.getPhase())) {
pt.setSot(turnDTO.getOrder());
pt.getSotHistory().add(turnDTO.getOrder());
} else if ("Trade".equalsIgnoreCase(turnDTO.getPhase())) {
pt.setTrade(turnDTO.getOrder());
pt.getTradeHistory().add(turnDTO.getOrder());
} else if ("CM".equalsIgnoreCase(turnDTO.getPhase())) {
pt.setCm(turnDTO.getOrder());
pt.getCmHistory().add(turnDTO.getOrder());
} else if ("Movement".equalsIgnoreCase(turnDTO.getPhase())) {
pt.setMovement(turnDTO.getOrder());
pt.getMovementHistory().add(turnDTO.getOrder());
} else if ("Research".equalsIgnoreCase(turnDTO.getPhase())) {
pt.setResearch(turnDTO.getOrder());
pt.getResearchHistory().add(turnDTO.getOrder());
}
playerhand.getPlayerTurns().add(pt);
return pt;
}
public void lockOrUnlockTurn(String pbfId, String playerId, TurnDTO turnDTO) {
PBF pbf = findPBFById(pbfId);
Playerhand playerhand = getPlayerhandByPlayerId(playerId, pbf);
PlayerTurn playerTurn = playerhand.getPlayerTurns().stream()
.filter(p -> p.getTurnNumber() == turnDTO.getTurnNumber())
.findFirst()
.orElseThrow(PlayerAction::cannotFindItem);
playerTurn.setDisabled(turnDTO.isLocked());
String message = turnDTO.isLocked() ? " has locked in turn " + turnDTO.getTurnNumber() : " has re-opened turn " + turnDTO.getTurnNumber();
createCommonPublicLog(message, pbfId, playerId);
pbfCollection.updateById(pbfId, pbf);
}
}