defmodule NOP.Element.LogicElement do defmacro __using__([]) do quote do require Logger def handle_call(:evaluate, _from, state) do {:reply, get_result_from_state(state), state} end def handle_call(:get_name, _from, state) do {:reply, get_name(state), state} end def handle_cast({:link_condition, condition, element_name}, state) do Logger.debug("Linked logic element #{get_name(state)} to condition #{element_name}") state = link_to_condition(condition, state) {:noreply, state} end def handle_cast({:notify_condition, element_value, element_name}, state) do Logger.debug("Element #{get_name(state)} notified by element #{element_name} that its new assert is #{element_value}") state = update_element_value(state, element_name, element_value) {:noreply, state} end defp get_name(state) do Map.get(state, :name) end defp notify_conditions(state, new_result, name) do condition_list = get_condition_list_from_state(state) notify_conditions_int(condition_list, new_result, name) end defp notify_conditions_int([], _, _) do # End of list end defp notify_conditions_int([condition | condition_list], new_result, name) do GenServer.cast(condition, {:notify_condition, new_result, name}) notify_conditions_int(condition_list, new_result, name) end defp init_condition_list(state) do Map.put(state, :condition_list, []) end defp get_condition_list_from_state(state) do Map.get(state, :condition_list) end defp set_condtion_list_to_state(state, condition_list) do Map.put(state, :condition_list, condition_list) end defp link_to_condition(condition, state) do condition_list = get_condition_list_from_state(state) condition_list = condition_list ++ [condition] set_condtion_list_to_state(state, condition_list) end defp get_result_from_state(state) do Map.get(state, :result) end defp set_result_to_state(state, result) do Map.put(state, :result, result) end defp link_to_elements([element | elements], pid, element_name) do GenServer.cast(element, {:link_condition, pid , element_name}) link_to_elements(elements, pid, element_name) end defp link_to_elements([], _, _) do #Empty list -> Stop end def evaluate_elements(element_name, element_list) do values = %{} evaluate_elements_int(element_name, element_list, values) end def init_element_values(state, element_name, element_list) do values = evaluate_elements(element_name, element_list) set_values_to_state(state, values) end defp evaluate_elements_int(_, [], values) do values end defp evaluate_elements_int(element_name, [element | element_list], values) do result = GenServer.call(element, :evaluate, :infinity) name = GenServer.call(element, :get_name, :infinity) Logger.debug("Asserting value for logic element #{name} with intial value #{result}") evaluate_elements_int(element_name, element_list, Map.put(values, String.to_atom(name), result)) end defp get_values_from_state(state) do Map.get(state, :values) end defp set_values_to_state(state, values) do Map.put(state, :values, values) end defp update_element_value(state, element_name, element_value) do values = get_values_from_state(state) values = Map.put(values, String.to_atom(element_name), element_value) old_result = get_result_from_state(state) name = get_name(state) Logger.debug("Updating assert from element #{element_name} in element #{get_name(state)}") #update_my_state need to be defined! result = update_my_state(state, name, element_name, values, old_result) state = set_values_to_state(state, values) if result != old_result do notify_conditions(state, result, name) end set_result_to_state(state, result) end end end end