lib/tello/client.ex

defmodule Tello.Client do
  @moduledoc """
  The Tello Client as a supervisor.
  """

  use Supervisor

  alias Tello.Controller
  alias Tello.StatusListener

  @type init_arg :: [
          controller: Controller.init_arg(),
          status_listener: StatusListener.init_arg()
        ]

  @doc """
  Start a client
  """
  @spec start_link([], init_arg()) :: :ignore | {:error, any} | {:ok, pid}
  def start_link([], init_arg) do
    uid = System.unique_integer()

    Supervisor.start_link(__MODULE__, [uid: uid, init_arg: init_arg],
      name: :"#{__MODULE__}.#{uid}"
    )
  end

  @doc false
  def init(uid: uid, init_arg: init_arg) do
    controller_arg = Keyword.get(init_arg, :controller)

    children = [
      {Controller, [uid: uid, arg: controller_arg]}
    ]

    children =
      case Keyword.get(init_arg, :status_listener) do
        nil ->
          children

        status_listener_arg ->
          children ++ [{StatusListener, [uid: uid, arg: status_listener_arg]}]
      end

    Supervisor.init(children, strategy: :one_for_one)
  end

  @doc false
  @spec pid_for(pid, Controller.t() | StatusListener.t()) :: pid | nil
  def pid_for(client, module) do
    client
    |> Supervisor.which_children()
    |> Enum.find_value(fn
      {^module, pid, :worker, _arg} ->
        pid

      _other ->
        nil
    end)
  end
end