lib/storage/adapters/genserver_adapter/view_portal.ex

defmodule Sorcery.Storage.GenserverAdapter.ViewPortal do
  @moduledoc """
  Pure functions for pulling a list of entities out of a portal.
  """
  use Norm
  alias Sorcery.Specs.Primative, as: T
  alias Sorcery.Specs.Portals, as: PT
  alias Sorcery.Storage.GenserverAdapter.Specs, as: AdapterT



  #@contract view_portal(PT.portal(), AdapterT.client_state()) :: T.tablemap() 
  @doc """
  Given a portal, and the state, return a map of all the entities which satisfy all guards.
  """
  def view_portal(%{tk: tk, resolved_guards: guards} = _portal, state) do
    table = Map.get(state.db, tk, %{})
    Enum.reduce(table, %{}, fn {id, entity}, acc ->
      if satisfies_all_guards?(entity, guards) do
        Map.put(acc, id, entity)
      else
        acc
      end
    end)
  end
  #@contract view_portal(PT.portal_ref(), AdapterT.client_state()) :: T.tablemap() 
  def view_portal(ref, state) do
    [tk | _] = String.split(ref, ":")
    case state.presence.get_by_key("portals:#{tk}", ref) do
      %{metas: [portal]} -> view_portal(portal, state)
      [] -> %{}
    end
  end


  @contract get_portal_ids(PT.portal(), AdapterT.client_state()) :: coll_of(T.id_int)
  @doc """
  Get a set of ids for the entities found by a given portal.
  """
  def get_portal_ids(portal, state) do
    view_portal(portal, state) |> Map.keys() |> MapSet.new()
  end



  defp satisfies_guard?(entity, {:or, guards}) do
    Enum.any?(guards, fn guard -> satisfies_guard?(entity, guard) end)
  end
  # Otherwise, compiler says Kernel.in/2 is undefined. I don't know why. This is a fix for now.
  defp satisfies_guard?(entity, {:in, attr, guard_value}) do
    ent_val = Map.get(entity, attr)
    Kernel.in(ent_val, guard_value)
  end
  defp satisfies_guard?(entity, {fun_atom, attr, guard_value}) do
    fun = Function.capture(Kernel, fun_atom, 2)
    ent_val = Map.get(entity, attr)
    fun.(ent_val, guard_value)
  end

  defp satisfies_all_guards?(entity, guards) do
    Enum.all?(guards, fn guard -> satisfies_guard?(entity, guard) end)
  end


end