package org.royaldev.thehumanity.server.controllers;
import org.kitteh.irc.client.library.Client;
import org.kitteh.irc.client.library.element.Channel;
import org.royaldev.thehumanity.cards.packs.CAHCardPack;
import org.royaldev.thehumanity.cards.play.Play;
import org.royaldev.thehumanity.cards.types.WhiteCard;
import org.royaldev.thehumanity.game.HouseRule;
import org.royaldev.thehumanity.game.TheHumanityGame;
import org.royaldev.thehumanity.game.round.CAHRound.RoundState;
import org.royaldev.thehumanity.game.round.CurrentRound;
import org.royaldev.thehumanity.player.TheHumanityPlayer;
import org.royaldev.thehumanity.server.services.client.ClientService;
import org.royaldev.thehumanity.server.services.game.GameService;
import org.royaldev.thehumanity.server.services.server.ServerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import xyz.cardstock.cardstock.configuration.Server;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@Controller
public class GameController {
@Autowired
private ServerService serverService;
@Autowired
private ClientService clientService;
@Autowired
private GameService gameService;
@ResponseBody
@RequestMapping(value = "/api/game/{server}/{channel}", method = RequestMethod.GET, produces = APIHelper.PRODUCES)
public String apiViewGame(@PathVariable String server, @PathVariable String channel, final HttpServletResponse response) {
final Client client = this.clientService.getFromHostname(server);
final TheHumanityGame g = this.gameService.getFromChannelName(client, "#" + channel);
if (g == null) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return APIHelper.makeError("No such game.");
}
// TODO: Use toJSON()?
return APIHelper.makeJSON(jw -> {
jw
.object()
.key("channel")
.value(g.getChannel().getName())
.key("players")
.value(g.getPlayers().stream().map(p -> p.getUser().getNick()).collect(Collectors.toList()))
.key("historicPlayers")
.value(g.getHistoricPlayers().stream().map(p -> p.getUser().getNick()).collect(Collectors.toList()))
.key("host")
.value(g.getHost().getUser().getNick())
.key("scores")
.value(g.getHistoricPlayers().stream().collect(Collectors.toMap(p -> p.getUser().getNick(), TheHumanityPlayer::getScore)))
.key("houseRules")
.value(g.getHouseRules().stream().map(HouseRule::getFriendlyName).collect(Collectors.toList()))
.key("cardPacks")
.value(g.getDeck().getCardPacks().stream().map(CAHCardPack::getName).collect(Collectors.toList()))
.key("state")
.value(g.getState().getUniqueName())
.key("timestamps")
.object()
.key("started")
.value(g.getStartTime())
.endObject()
.key("currentRound");
final CurrentRound round = g.getCurrentRound();
if (round == null) {
jw.value(null);
} else {
final List<List<String>> plays = !round.getState().getUniqueName().equals(RoundState.WAITING_FOR_CZAR.name())
? null
: round.getPlays().stream()
.map(Play::getWhiteCards) // Convert each Play to a List<WhiteCard>
.map(
list -> list.stream() // Stream each WhiteCard
.map(WhiteCard::getText) // Convert each WhiteCard to its text form
.collect(Collectors.toList()) // Collect the Strings into a List<String>
) // Map the List<WhiteCard> to List<String>
.collect(Collectors.toList()); // Collect the lists into a List<List<String>>
// There is no need to shuffle, as these are only shown during the WAITING_FOR_CZAR stage, in which the
// plays are shuffled automatically. Keeping them unshuffled allows for index detection.
jw
.object()
.key("number")
.value(round.getNumber())
.key("czar")
.value(round.getCzar() == null ? null : round.getCzar().getUser().getNick())
.key("blackCard")
.value(round.getBlackCard())
.key("stage")
.value(round.getState())
.key("plays")
.value(round.getState().getUniqueName().equals(RoundState.WAITING_FOR_CZAR.name()) ? plays : new String[0])
.key("skippedPlayers")
.value(round.getSkippedPlayers().stream().map(p -> p.getUser().getNick()).collect(Collectors.toList()))
.endObject();
}
jw.endObject();
});
}
@ResponseBody
@RequestMapping(value = "/api/game/{server}/{channel}/{round}", method = RequestMethod.GET, produces = APIHelper.PRODUCES)
public String apiViewGameRound(@PathVariable String server, @PathVariable String channel, @PathVariable int round, final HttpServletResponse response) {
final Client client = this.clientService.getFromHostname(server);
final TheHumanityGame g = this.gameService.getFromChannelName(client, "#" + channel);
if (g == null) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return APIHelper.makeError("No such game");
}
try {
return g.getPreviousRounds().get(round - 1).toJSON();
} catch (final IndexOutOfBoundsException ex) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return APIHelper.makeError("No such round.");
}
}
@ResponseBody
@RequestMapping(value = "/api/games/{server}", method = RequestMethod.GET, produces = APIHelper.PRODUCES)
public String apiViewGames(@PathVariable String server, final HttpServletResponse response) {
final Client client = this.clientService.getFromHostname(server);
return APIHelper.makeObjectMapperJSON(response, om -> om.writeValueAsString(this.gameService.getAllForClient(client).stream().map(TheHumanityGame::getChannel).map(Channel::getName).collect(Collectors.toList())));
}
@RequestMapping(value = "/game/{server}/{channel}", method = RequestMethod.GET)
public String gameInChannel(@PathVariable String server, @PathVariable String channel, final Model model) {
final Client client = this.clientService.getFromHostname(server);
final TheHumanityGame g = this.gameService.getFromChannelName(client, "#" + channel);
if (g == null) {
return "redirect:/";
}
model.addAttribute("game", g);
return "games/game";
}
@RequestMapping(value = "/games", method = RequestMethod.GET)
public String viewGames(final Model model) {
final Map<Server, Set<TheHumanityGame>> games = this.clientService.getClients().stream()
.collect(Collectors.toMap(
client -> this.serverService.getServer(client),
client -> this.gameService.getAllForClient(client)
));
model.addAttribute("games", games);
return "games/index";
}
}