defmodule Fermo.Live.Dependencies do
use GenServer
require Logger
@name :fermo_dependencies
@config Application.compile_env(:fermo, :config, Fermo.Config)
@i18n Application.compile_env(:fermo, :i18n, Fermo.I18n)
def start_link(opts) do
GenServer.start_link(__MODULE__, opts, name: @name)
end
@impl true
def init(app_module: app_module) do
{:ok} = @i18n.load()
config = load_config(app_module)
{:ok, %{config: config, app_module: app_module}}
end
def reinitialize() do
{:ok} = GenServer.call(@name, {:reinitialize})
end
def page_from_path(path) do
GenServer.call(@name, {:page_from_path, path})
end
def pages_by_dependency(value) do
GenServer.call(@name, {:pages_by_dependency, value})
end
def start_page(path) do
GenServer.call(@name, {:start_page, path})
end
def add_page_dependency(path, value) do
GenServer.call(@name, {:add_page_dependency, path, value})
end
@impl true
def handle_call({:reinitialize}, _from, %{app_module: app_module} = state) do
config = load_config(app_module)
{:reply, {:ok}, Map.put(state, :config, config)}
end
def handle_call({:page_from_path, path}, _from, state) do
page = Enum.find(state.config.pages, &(&1.path == path))
if page do
{:reply, {:ok, page}, state}
else
{:reply, {:error, :not_found}, state}
end
end
def handle_call({:pages_by_dependency, value}, _from, state) do
pages = Enum.filter(state.config.pages, fn page ->
Enum.member?(page.dependencies, value)
end)
{:reply, {:ok, pages}, state}
end
def handle_call({:start_page, path}, _from, state) do
state = state
|> update_page(path, &(reset_page_dependencies(&1)))
{:reply, {:ok}, state}
end
def handle_call({:add_page_dependency, path, value}, _from, state) do
state = update_page(state, path, fn page ->
dependencies = if Enum.member?(page.dependencies, value) do
page.dependencies
else
[value | page.dependencies]
end
Map.put(page, :dependencies, dependencies)
end)
{:reply, {:ok}, state}
end
defp load_config(app_module) do
Logger.info "Requesting #{app_module}.config... "
{:ok, config} = app_module.config()
Logger.info "Done!"
Logger.info "Running post config... "
config =
config
|> @config.post_config()
|> set_live_attributes()
Logger.info "Done!"
config
end
defp set_live_attributes(config) do
fermo_live = Application.get_env(:fermo, :live, [])
pages_live = Keyword.get(fermo_live, :pages, true)
pages = Enum.map(config.pages, fn page ->
page
|> Map.put(:live, pages_live)
|> reset_page_dependencies()
end)
config
|> put_in([:pages], pages)
end
defp reset_page_dependencies(page) do
template =
case page.template do
"/" <> rest -> rest
path -> path
end
Map.put(page, :dependencies, [template])
end
defp update_page(state, path, callback) do
pages = Enum.map(state.config.pages, fn page ->
if page.path == path do
callback.(page)
else
page
end
end)
put_in(state, [:config, :pages], pages)
end
end