Current section
Files
Jump to
Current section
Files
lib/nop/element/fbe.ex
# ---
# Excerpted from "Programming Elixir ≥ 1.6",
# published by The Pragmatic Bookshelf.
# Copyrights apply to this code. It may not be used to create training material,
# courses, books, articles, and the like. Contact us if you are in doubt.
# We make no guarantees that this code is fit for any purpose.
# Visit http://www.pragmaticprogrammer.com/titles/elixir16 for more book information.
# ---
defmodule NOP.Element.FBE do
defmacro __using__([]) do
quote do
use GenServer
use NOP.Element.ElementBase
require Logger
def start_link(fbe_name) do
state = init_state(fbe_name)
state = reset_statistics_to_state(state)
state = set_name(state, fbe_name)
#GenServer.start_link(__MODULE__, state, name: String.to_atom(fbe_name))
GenServer.start_link(__MODULE__, state)
end
def init(state) do
{:ok, state}
end
def handle_call({:get_attr, attr_name}, _from, state) do
{:reply, get_attribute(get_attributes_from_state(state), attr_name), state}
end
def handle_call(:get_name, _from, state) do
{:reply, get_name(state), state}
end
def handle_cast({:set_attr, attr_name, attr_value}, state) do
fbe_attrs = get_attributes_from_state(state)
fbe_attrs = set_attribute(fbe_attrs, attr_name, attr_value, state)
#beg_time = get_timestamp()
#state = set_attributes_to_state(state, fbe_attrs)
# end_time = get_timestamp()
#state = add_statistics_to_state(state, diff_between_timestamp(beg_time,end_time))
{run_time, state} = :timer.tc(
fn ->
set_attributes_to_state(state, fbe_attrs)
end
)
state = add_statistics_to_state(state, div(run_time, 1000))
{:noreply, state}
end
def handle_cast({:link_premise, attr_name, premise, side, premise_name}, state) do
state = link_premise_to_attribute(state, attr_name, premise, side, premise_name)
{:noreply, state}
end
defp init_state(fbe_name) do
# int_attributes needs to be defined!
fbe_attrs = int_attributes()
%{:attributes => fbe_attrs, :links => %{}}
end
defp get_attributes_from_state(state) do
Map.get(state, :attributes)
end
defp set_attributes_to_state(state, fbe_attrs) do
Map.put(state, :attributes, fbe_attrs)
end
defp get_attribute(fbe_attrs, attr_name) do
Map.get(fbe_attrs, attr_name)
end
defp notify_premises_int([], _, _, _) do
# No premises to notify
end
defp notify_premises_int(nil, _, _, _) do
# No premises to notify
end
defp notify_premises_int([{premise, side} | premises], attr_name, attr_value, fbe_name) do
GenServer.cast(premise, {:notify, side, self(), attr_name, attr_value, fbe_name})
notify_premises_int(premises, attr_name, attr_value, fbe_name)
end
defp notify_premises(state, attr_name, attr_value, fbe_name) do
links = get_links(state)
premises = Map.get(links, attr_name)
notify_premises_int(premises, attr_name, attr_value, fbe_name)
end
defp set_attribute(fbe_attrs, attr_name, attr_value, state) do
# Get Old Value
old_value = get_attribute(fbe_attrs, attr_name)
if old_value != attr_value do
# Get Name
fbe_name = get_name(state)
Logger.debug(
"FBE attribute #{fbe_name}.#{attr_name} changed from #{old_value} to #{attr_value}"
)
notify_premises(state, attr_name, attr_value, fbe_name)
Map.put(fbe_attrs, attr_name, attr_value)
else
fbe_attrs
end
end
defp get_links(state) do
Map.get(state, :links)
end
defp set_links(state, links) do
Map.put(state, :links, links)
end
defp link_premise_to_attribute(state, attr_name, premise, side, premise_name) do
Logger.debug(
"FBE attribute #{get_name(state)}.#{attr_name} linked to premise #{premise_name} on #{
side
} side"
)
links = get_links(state)
premises = Map.get(links, attr_name)
premises =
if premises == nil do
[]
else
premises
end
premises = premises ++ [{premise, side}]
links = Map.put(links, attr_name, premises)
set_links(state, links)
end
end
end
end