lib/examples/utils.ex

defmodule CPSolver.Examples.Utils do
  require Logger

  def notify_client_handler() do
    client = self()
    fn solution -> send(client, {:solution, solution}) end
  end

  def wait_for_solution(timeout, solution_checker_fun) do
    receive do
      {:solution, solution} ->
        solution
        |> Enum.map(fn {_ref, s} -> s end)
        |> then(fn sol -> solution_checker_fun.(sol) |> tap(fn res -> handle_checked(res) end) end)
    after
      timeout ->
        handle_timeout()
    end
    |> tap(fn _ -> flush_solutions() end)
  end

  def wait_for_solutions(expected, timeout, solution_checker_fun) do
    wait_for_solutions(expected, timeout, solution_checker_fun, 0)
  end

  def wait_for_solutions(0, _timeout, _solution_checker_fun, successes) do
    successes
  end

  def wait_for_solutions(num, timeout, solution_checker_fun, successes) do
    case wait_for_solution(timeout, solution_checker_fun) do
      {:error, :timeout} ->
        {:error, :timeout}

      true ->
        wait_for_solutions(num - 1, timeout, solution_checker_fun, successes + 1)
    end
  end

  defp handle_timeout() do
    Logger.error("Timed out :-(")
    {:error, :timeout}
  end

  defp handle_checked(solution_checked?) do
    (solution_checked? && Logger.notice("Solution checked!")) || Logger.error("Wrong solution!")
  end

  def flush_solutions() do
    receive do
      {:solution, _} -> flush_solutions()
    after
      0 -> :ok
    end
  end
end