package industries.sunshine.planningpoker.common import java.util.UUID import io.circe._ import scala.util.Random object Models { /** view of the single planning poker round * @param players * \- people who are currently playing * @param allowedCards- * the cards values that can be used by players * @param round * \- state of the selected cards of the players * @param canCloseRound * \- whether current player has access to button to finish the round */ final case class RoomStateView( roomName: String, players: List[Player], me: PlayerID, allowedCards: List[String], round: RoundStateView, canCloseRound: Boolean = false ) derives Codec.AsObject object RoomStateView { val empty = RoomStateView( "", List.empty, PlayerID(0), List.empty, RoundStateView.Voting(None, List.empty), false ) } enum RoundStateView derives Codec.AsObject: /** view state for round before votes are open player can know their vote and who of the other * players have voted */ case Voting( myCard: Option[String], alreadyVoted: List[PlayerID] ) /** view state for round after opening the votes */ case Viewing( votes: List[(PlayerID, String)] ) final case class PlayerID(id: Long) derives Codec.AsObject final case class Player(name: String, id: PlayerID) derives Codec.AsObject object Player { def create(name: String) = Player(name, PlayerID(Random.nextLong)) } final case class RoomID(name: String) derives Codec.AsObject final case class Room( id: RoomID, players: List[Player], owner: String, // TODO switch to nickname password: String, allowedCards: List[String], round: RoundState, playersPasswords: Map[String, String] = Map.empty, // nickname into password ) { def getViewFor(playerId: PlayerID): RoomStateView = { players .find(_.id == playerId) .fold(ifEmpty = RoomStateView.empty)((me: Player) => RoomStateView( id.name, players, me.id, allowedCards, round.toViewFor(playerId), me.name == owner ) ) } } // no need to send to the front end, no deed to derive codec, cool sealed trait RoundState { def toViewFor(player: PlayerID): RoundStateView def removePlayer(id: PlayerID): RoundState } object RoundState { final case class Voting(votes: Map[PlayerID, String]) extends RoundState { override def toViewFor(playerId: PlayerID): RoundStateView.Voting = RoundStateView.Voting( myCard = votes.get(playerId), alreadyVoted = votes.filterKeys(id => id != playerId).keys.toList ) override def removePlayer(id: PlayerID): RoundState.Voting = RoundState.Voting(votes.filterKeys(_ != id).toMap) } final case class Viewing(votes: Map[PlayerID, String]) extends RoundState { override def toViewFor(player: PlayerID): RoundStateView.Viewing = RoundStateView.Viewing(votes.toList) override def removePlayer(id: PlayerID): RoundState.Viewing = RoundState.Viewing(votes.filterKeys(_ != id).toMap) } } }