lib/kalevala/character/controller.ex

defmodule Kalevala.Character.Controller do
  @moduledoc """
  Kalevala controllers are the current set of actions for the user

  For instance, you might have a LoginController that handles
  authentication, that then passes to a CommandController to start
  processing player commands after they signed in.
  """

  alias Kalevala.Character.Conn
  alias Kalevala.Character.Event

  @doc """
  Called when the controller is first switched to
  """
  @callback init(Conn.t()) :: Conn.t()

  @doc """
  Called when text is received from the player
  """
  @callback recv(Conn.t(), String.t()) :: Conn.t()

  @doc """
  Called when the connection receives an event (e.g. incoming GMCP)
  """
  @callback recv_event(Conn.t(), any()) :: Conn.t()

  @doc """
  Called when a `Kalevala.Character.Event` is sent to the foreman process
  """
  @callback event(Conn.t(), Event.t()) :: Conn.t()

  @doc """
  Called when a `Kalevala.Character.Event.Display` is sent to the foreman process
  """
  @callback display(Conn.t(), Event.t()) :: Conn.t()

  @doc """
  Marks the module as a controller and imports controller functions
  """
  defmacro __using__(_opts) do
    quote do
      @behaviour unquote(__MODULE__)

      import Kalevala.Character.Conn

      require Logger

      alias Kalevala.Character.Event

      @impl true
      def recv_event(conn, event) do
        Logger.debug("Received event - #{inspect(event)}")

        conn
      end

      @impl true
      def event(conn, event) do
        Logger.debug("Received event - #{inspect(event)}")

        conn
      end

      @impl true
      def display(conn, event) do
        conn
        |> Map.put(:options, event.options)
        |> Map.put(:output, event.output)
      end

      defoverridable display: 2, event: 2, recv_event: 2
    end
  end
end