/*
* Copyright (c) 2015 Shervin Asgari
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package no.asgari.civilization.server.resource;
import com.codahale.metrics.annotation.Timed;
import com.google.common.base.Strings;
import com.mongodb.DB;
import io.dropwizard.auth.Auth;
import lombok.extern.log4j.Log4j;
import no.asgari.civilization.server.action.DrawAction;
import no.asgari.civilization.server.action.GameLogAction;
import no.asgari.civilization.server.action.PlayerAction;
import no.asgari.civilization.server.action.TurnAction;
import no.asgari.civilization.server.action.UndoAction;
import no.asgari.civilization.server.dto.AllTechsDTO;
import no.asgari.civilization.server.dto.ItemDTO;
import no.asgari.civilization.server.dto.MessageDTO;
import no.asgari.civilization.server.dto.TurnDTO;
import no.asgari.civilization.server.model.GameLog;
import no.asgari.civilization.server.model.Player;
import no.asgari.civilization.server.model.PlayerTurn;
import no.asgari.civilization.server.model.Playerhand;
import no.asgari.civilization.server.model.Tech;
import org.hibernate.validator.constraints.NotEmpty;
import javax.validation.Valid;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import java.util.List;
import java.util.Set;
/**
* Contains player specific resources
*/
@Path("player/{pbfId}")
@Produces(value = MediaType.APPLICATION_JSON)
@Consumes(value = MediaType.APPLICATION_JSON)
@Log4j
public class PlayerResource {
private final DB db;
private final PlayerAction playerAction;
private final UndoAction undoAction;
@Context
private UriInfo uriInfo;
public PlayerResource(DB db) {
this.db = db;
playerAction = new PlayerAction(db);
undoAction = new UndoAction(db);
}
/**
* Will choose a tech and update the player collection.
* <p>
* This method will also check if other players have chosen
*
* @param player
* @param pbfId
* @param techName
* @return
*/
@POST
@Path("/tech/choose")
@Timed
public Response chooseTech(@Auth Player player, @PathParam("pbfId") String pbfId, @NotEmpty @QueryParam("name") String techName) {
playerAction.chooseTech(pbfId, techName, player.getId());
return Response.noContent().build();
}
/**
* Will choose a social policy and update the player collection.
* <p>
* This method will also check if other players have chosen a flipside and throw exception
*
* @param player
* @param pbfId
* @param socialpolicy
* @return
*/
@POST
@Path("/socialpolicy/choose")
@Timed
public Response chooseSocialPolicy(@Auth Player player, @PathParam("pbfId") String pbfId, @NotEmpty @QueryParam("name") String socialpolicy) {
playerAction.chooseSocialPolicy(pbfId, socialpolicy, player.getId());
return Response.noContent().build();
}
/**
* Will remove the tech from the playerhand. Will not update the gamelog since the tech is only for private view
*
* @param player
* @param pbfId
* @param techName
* @return - 200 OK
*/
@DELETE
@Path("/tech/remove")
@Timed
public Response removeTech(@Auth Player player, @PathParam("pbfId") String pbfId, @NotEmpty @QueryParam("name") String techName) {
boolean removedTech = !Strings.isNullOrEmpty(techName) && playerAction.removeTech(pbfId, techName, player.getId());
if (removedTech)
return Response.ok().build();
return Response.status(Response.Status.BAD_REQUEST).build();
}
/**
* If logged in playerId is specified we will use that, otherwise we will use logged in player.
* This because a logged in player, might go into someone elses game
*
* @param playerId
* @return
*/
@GET
@Path("/tech/{playerId}")
public Response getChosenTechFromPlayer(@PathParam("pbfId") String pbfId, @PathParam("playerId") String playerId) {
Player pl = playerAction.getPlayerById(playerId);
if (pl == null) {
log.error("Didn't find player with id " + playerId);
return Response.status(Response.Status.BAD_REQUEST).build();
}
Set<Tech> playersTechs = playerAction.getPlayersTechs(pbfId, playerId);
return Response.ok().entity(playersTechs).build();
}
/**
* If logged in playerId is specified we will use that, otherwise we will use logged in player.
* This because a logged in player, might go into someone elses game
*
* @return
*/
@GET
@Path("/tech/all")
public List<AllTechsDTO> getChosenTechFromPlayer(@PathParam("pbfId") String pbfId) {
return playerAction.getTechsForAllPlayers(pbfId);
}
/**
* Will end the turn for a given player, and take the next player from the list and
* make that player current starting player.
*
* @param player
* @param pbfId
* @return
*/
@POST
@Path("/endturn")
@Timed
public Response endTurn(@Auth Player player, @PathParam("pbfId") String pbfId) {
boolean success = playerAction.endTurn(pbfId, player);
if (success) return Response.noContent().build();
return Response.serverError().build();
}
/**
* This method checks whether it is the players turn
*
* @param player
* @param pbfId
* @return
*/
@GET
@Path("/yourturn")
@Timed
public boolean isYourTurn(@Auth Player player, @PathParam("pbfId") String pbfId) {
return playerAction.isYourTurn(pbfId, player.getId());
}
@PUT
@Path("/item/reveal")
@Timed
public Response revealItem(@Auth Player player, @PathParam("pbfId") String pbfId, @Valid ItemDTO item) {
playerAction.revealItem(pbfId, player.getId(), item);
return Response.ok().build();
}
/**
* Reveals a tech
* <p>
* Will throw BAD_REQUEST if undo has already been performed
*
* @param player
* @param pbfId
* @param gameLogId
* @return 200 ok
*/
@PUT
@Path("/tech/reveal/{gameLogId}")
@Timed
public Response revealTech(@Auth Player player, @NotEmpty @PathParam("pbfId") String pbfId, @NotEmpty @PathParam("gameLogId") String gameLogId) {
GameLogAction gameLogAction = new GameLogAction(db);
GameLog gameLog = gameLogAction.findGameLogById(gameLogId);
playerAction.revealTech(gameLog, pbfId, player.getId());
return Response.ok().build();
}
//@DELETE doesn't work on angularjs with content-type
@POST
@Path("/item/discard")
@Timed
public Response discardItem(@Auth Player player, @PathParam("pbfId") String pbfId, @Valid ItemDTO item) {
playerAction.discardItem(pbfId, player.getId(), item);
return Response.ok().build();
}
@POST
@Path("/item/backtodeck")
@Timed
public Response itemBackToDeck(@Auth Player player, @PathParam("pbfId") String pbfId, @Valid ItemDTO item) {
undoAction.playerPutsItemBackInDeck(pbfId, player.getId(), item);
return Response.ok().build();
}
@POST
@Path("/trade")
@Timed
public Response tradeItemWithPlayer(@Auth Player player, @PathParam("pbfId") String pbfId, @Valid ItemDTO item) {
if (player.getId().equals(item.getOwnerId())) {
log.error("You cannot trade with your self");
return Response.status(Response.Status.FORBIDDEN).build();
}
boolean result = playerAction.tradeToPlayer(item, player.getId());
if (result) {
return Response.ok().build();
}
return Response.status(Response.Status.NOT_MODIFIED).build();
}
/**
* Will end a battle for one player
* Will set the isBattle = false
* <p>
* Both players need to call this method
*
* @param player
* @param pbfId
* @param numberOfunits
* @return
*/
@PUT
@Path("/battle/end")
@Timed
public Response endBattle(@Auth Player player, @NotEmpty @PathParam("pbfId") String pbfId, @NotEmpty @QueryParam("numOfUnits") int numberOfunits) {
DrawAction drawAction = new DrawAction(db);
drawAction.endBattle(pbfId, player.getId());
return Response.ok().build();
}
//TODO Perhaps no need for this. In this case we need to implement a new view with list of all votes
/**
* Returns a list of all undoes that a player needs to vote for
*
* @param player
* @param pbfId
* @return
*/
@GET
@Path("/undo")
@Timed
public Response getAllUndoThatNeedsVoteFromPlayer(@Auth Player player, @NotEmpty @PathParam("pbfId") String pbfId) {
UndoAction undoAction = new UndoAction(db);
undoAction.getPlayersActiveUndoes(pbfId, player.getUsername());
return Response.ok().build();
}
@GET
@Path("turn")
public Set<PlayerTurn> getPlayersturns(@Auth Player player, @NotEmpty @PathParam("pbfId") String pbfId) {
TurnAction turnAction = new TurnAction(db);
return turnAction.getPlayersTurns(pbfId, player.getId());
}
@PUT
@Path("/turn/update")
public Response updateTurn(@Auth Player player, @NotEmpty @PathParam("pbfId") String pbfId,
@Valid TurnDTO turn) {
TurnAction turnAction = new TurnAction(db);
if("SOT".equalsIgnoreCase(turn.getPhase())) {
turnAction.updateSOT(pbfId, player.getId(), turn);
} else if("Trade".equalsIgnoreCase(turn.getPhase())) {
turnAction.updateTrade(pbfId, player.getId(), turn);
} else if("CM".equalsIgnoreCase(turn.getPhase())) {
turnAction.updateCM(pbfId, player.getId(), turn);
} else if("Movement".equalsIgnoreCase(turn.getPhase())) {
turnAction.updateMovement(pbfId, player.getId(), turn);
} else if("Research".equalsIgnoreCase(turn.getPhase())) {
turnAction.updateResearch(pbfId, player.getId(), turn);
}
return Response.noContent().build();
}
@PUT
@Path("/turn/lock")
public Response lockOrUnlockTurn(@Auth Player player, @NotEmpty @PathParam("pbfId") String pbfId,
@Valid TurnDTO turn) {
TurnAction turnAction = new TurnAction(db);
turnAction.lockOrUnlockTurn(pbfId, player.getId(), turn);
return Response.noContent().build();
}
@GET
@Path("/note")
public MessageDTO getnote(@Auth Player player, @NotEmpty @PathParam("pbfId") String pbfId, MessageDTO messageDTO) {
Playerhand playerhand = playerAction.getPlayerhandByPlayerId(player.getId(), playerAction.findPBFById(pbfId));
return new MessageDTO(playerhand.getGamenote());
}
@PUT
@Path("/note/save")
public Response saveNote(@Auth Player player, @NotEmpty @PathParam("pbfId") String pbfId, MessageDTO messageDTO) {
playerAction.saveNote(pbfId, player.getId(), messageDTO);
return Response.ok().build();
}
}