3.0 KiB · text History 9c0fc16
defmodule LambentExWeb.DevicesLive.Places do
  use LambentExWeb, :live_view

  alias LambentEx.Places

  @pubsub_name LambentEx.PubSub

  @impl true
  def mount(_params, _session, socket) do
    Phoenix.PubSub.subscribe(@pubsub_name, "scan-82667777")
    Phoenix.PubSub.subscribe(@pubsub_name, "machines_idx")
    Phoenix.PubSub.subscribe(@pubsub_name, "links_idx")
    Phoenix.PubSub.subscribe(@pubsub_name, "places")

    {:ok,
     socket
     |> assign(:devices, %{})
     |> assign(:machines, %{})
     |> assign(:links, %{})
     |> assign(:defaults, Places.defaults())
     |> assign(:nonew, true)}
  end

  @impl true
  def handle_params(params, _url, socket) do
    {:noreply, apply_action(socket, socket.assigns.live_action, params)}
  end

  defp apply_action(socket, :index, _params) do
    socket
    |> assign(:page_link, "Devices")
    |> assign(:page_title, "Places")
    |> assign(:source, nil)
  end

  @impl true
  def handle_info({:devices_pub, devices}, socket) do
    {:noreply, socket |> assign(:devices, Map.merge(socket.assigns.devices, devices))}
  end

  @impl true
  def handle_info({:machines_pub, machine}, socket) do
    {:noreply,
     socket |> assign(:machines, Map.put(socket.assigns.machines, machine[:id], machine))}
  end

  @impl true
  def handle_info({:links_pub, link}, socket) do
    {:noreply, socket |> assign(:links, Map.put(socket.assigns.links, link[:name], link))}
  end

  @impl true
  def handle_info({:place_defaults, defaults}, socket) do
    {:noreply, socket |> assign(:defaults, defaults)}
  end

  @impl true
  def handle_info(_msg, socket), do: {:noreply, socket}

  @impl true
  def handle_event("default", %{"place" => place, "machine" => machine}, socket) do
    Places.set_default(place, blank_to_nil(machine))
    {:noreply, socket}
  end

  # adoption happens as devices turn up, which is no help for the ones already
  # sitting in a place when it gets its default
  @impl true
  def handle_event("adopt", %{"place" => place}, socket) do
    waiting = waiting(socket.assigns.devices, socket.assigns.links, place)
    Places.adopt_place(place)

    {:noreply, socket |> put_flash(:info, "Linking #{waiting} device(s) in #{place}...")}
  end

  defp blank_to_nil(""), do: nil
  defp blank_to_nil(machine), do: machine

  # functions

  defp places(devices, defaults) do
    devices
    |> Map.values()
    |> Enum.map(fn device -> device["place"] end)
    |> Enum.concat(Map.keys(defaults))
    |> Enum.reject(&is_nil/1)
    |> Enum.uniq()
    |> Enum.sort()
  end

  defp in_place(devices, place) do
    devices |> Enum.filter(fn {_mac, device} -> device["place"] == place end)
  end

  # what the select offers: whatever is running, by the name a link names it by
  defp machine_options(machines) do
    machines |> Map.values() |> Enum.map(fn m -> m[:name] end) |> Enum.uniq() |> Enum.sort()
  end

  defp driven?(links, mac) do
    links |> Map.values() |> Enum.any?(fn link -> link[:target] == mac end)
  end

  defp waiting(devices, links, place) do
    devices |> in_place(place) |> Enum.count(fn {mac, _d} -> not driven?(links, mac) end)
  end
end