defmodule Perudex.NotifierServer do
@moduledoc """
This module is a GenServer to handle communication going to the players by defining an interface a module need to implements.
"""
use GenServer, restart: :transient
@callback start_game(GameServer.callback_arg(), Game.player_id(), [Game.player_id()]) :: any
@callback new_hand(GameServer.callback_arg(), Game.player_id(), Hand.t()) :: any
@callback last_move(
GameServer.callback_arg(),
Game.player_id(),
Game.player_id(),
Game.last_move()
) :: any
@callback move(GameServer.callback_arg(), Game.player_id(), Hand.t()) :: any
@callback reveal_players_hands(
GameServer.callback_arg(),
Game.player_id(),
[
{Game.player_id(), Perudex.Hand.t()}
],
{integer, integer}
) :: any
@callback unauthorized_move(GameServer.callback_arg(), Game.player_id()) :: any
@callback invalid_bid(GameServer.callback_arg(), Game.player_id()) :: any
@callback illegal_move(GameServer.callback_arg(), Game.player_id()) :: any
@callback winner(GameServer.callback_arg(), Game.player_id(), Game.player_id()) :: any
@callback loser(GameServer.callback_arg(), Game.player_id(), Game.player_id()) :: any
def start_link({game_id, player}),
do:
GenServer.start_link(__MODULE__, {game_id, player}, name: service_name(game_id, player.id))
@impl true
def init({game_id, player}), do: {:ok, %{game_id: game_id, player: player}}
@spec publish(any, any, Game.player_instruction()) :: :ok
def publish(game_id, player_id, instruction),
do: GenServer.cast(service_name(game_id, player_id), {:notify, instruction})
@impl true
def handle_cast({:notify, instruction}, state) do
{fun, args} = decode_instruction(instruction)
all_args = [state.player.callback_arg, state.player.id | args]
apply(state.player.callback_mod, fun, all_args)
{:noreply, state}
end
defp decode_instruction({:game_started, players}), do: {:start_game, [players]}
defp decode_instruction({:new_hand, hand}), do: {:new_hand, [hand]}
defp decode_instruction({:move, hand}), do: {:move, [hand]}
defp decode_instruction({:reveal_players_hands, hands, result}),
do: {:reveal_players_hands, [hands, result]}
defp decode_instruction(:unauthorized_move), do: {:unauthorized_move, []}
defp decode_instruction({:last_move, player_id, move_result}),
do: {:last_move, [player_id, move_result]}
defp decode_instruction(:invalid_bid), do: {:invalid_bid, []}
defp decode_instruction(:illegal_move), do: {:illegal_move, []}
defp decode_instruction({:winner, winner_id}), do: {:winner, [winner_id]}
defp decode_instruction({:loser, loser_id}), do: {:loser, [loser_id]}
defp service_name(game_id, player_id),
do: Perudex.service_name({__MODULE__, game_id, player_id})
end