defmodule NOP.Element.Premise do use GenServer use NOP.Element.LogicElement def start_link(premise_name, fbe, fbe_attr, operator, operand) do state = init_state(premise_name, fbe, fbe_attr, operator, operand) state = init_condition_list(state) state = reset_statistics_to_state(state) state = set_name(state, premise_name) #{:ok, pid} = GenServer.start_link(__MODULE__, state, name: String.to_atom(premise_name)) {:ok, pid} = GenServer.start_link(__MODULE__, state) #Link premise to FBE GenServer.cast(fbe, {:link_premise, fbe_attr, pid, :left, premise_name}) {:ok, pid} end def start_link(premise_name, fbe_left, fbe_left_attr, operator, fbe_right, fbe_right_attr) do state = init_state(premise_name, fbe_left, fbe_left_attr, operator, fbe_right, fbe_right_attr) state = init_condition_list(state) state = reset_statistics_to_state(state) #{:ok, pid} = GenServer.start_link(__MODULE__, state, name: String.to_atom(premise_name)) {:ok, pid} = GenServer.start_link(__MODULE__, state) #Link premise to FBE (left) GenServer.cast(fbe_left, {:link_premise, fbe_left_attr, pid, :left, premise_name}) #Link premise to FBE (right) GenServer.cast(fbe_right, {:link_premise, fbe_right_attr, pid, :right, premise_name}) {:ok, pid} end def init(state) do {:ok, state} end def handle_cast({:notify, side, _, fbe_attr, new_value, fbe_name}, state) do premise_name = get_name(state) Logger.debug("Premise #{premise_name} notified by modification of FBE attribute #{fbe_name}.#{fbe_attr} to value #{new_value} on the #{side} side") premise = get_premise_from_state(state) #beg_time = get_timestamp() #state = update_assert(state, side, premise, new_value) #end_time = get_timestamp() #state = add_statistics_to_state(state, diff_between_timestamp(beg_time, end_time)) {run_time, state} = :timer.tc( fn -> update_assert(state, side, premise, new_value) end ) state = add_statistics_to_state(state, div(run_time, 1000)) {:noreply, state} end defp init_state(premise_name, fbe_left, fbe_left_attr, operator, fbe_right, fbe_right_attr) do state = %{:name => premise_name} #Get initial value left_value = GenServer.call(fbe_left, {:get_attr, fbe_left_attr}, :infinity) right_value = GenServer.call(fbe_right, {:get_attr, fbe_right_attr}, :infinity) #Assert initial value based on attribute value result = assert_value(premise_name, left_value, operator, right_value) #Set the premise premise_attrs = premise_to_map(fbe_left, fbe_left_attr, left_value, operator, fbe_right, fbe_right_attr, right_value) #Update state state = set_premise_to_state(state, premise_attrs) set_result_to_state(state, result) end defp init_state(premise_name, fbe, fbe_attr, operator, operand) do state = %{:name => premise_name} #Get initial value attr_value = GenServer.call(fbe, {:get_attr, fbe_attr}) #Assert initial value based on attribute value result = assert_value(premise_name, attr_value, operator, operand) #Set the premise premise_attrs = premise_to_map(fbe, fbe_attr, attr_value, operator, operand) #Update state state = set_premise_to_state(state, premise_attrs) set_result_to_state(state, result) end defp premise_to_map(fbe, fbe_attr, last_value, operator, operand) do {fbe, fbe_attr, last_value, operator, operand} end defp premise_to_map(fbe_left, fbe_left_attr, left_value, operator, fbe_right, fbe_right_attr, right_value) do {fbe_left, fbe_left_attr, left_value, operator, fbe_right, fbe_right_attr, right_value} end # Operators ----------------------------- defp assert(left, :EQ, right) do left == right end defp assert(left, :NE, right) do left != right end defp assert(left, :GT, right) do left > right end defp assert(left, :GE, right) do left >= right end defp assert(left, :LT, right) do left < right end defp assert(left, :LE, right) do left <= right end defp assert(_, _, _) do false end # Operators ----------------------------- defp assert_value(premise_name, left_value, operator, right_value) do result = assert(left_value, operator, right_value) Logger.debug("Assert premise #{premise_name} (#{left_value} #{operator} #{right_value}) ? = #{result}") result end defp get_premise_from_state(state) do Map.get(state, :premise) end defp set_premise_to_state(state, premise_attrs) do Map.put(state, :premise, premise_attrs) end defp update_assert(state, :left, {fbe, fbe_attr, _, operator, operand}, new_value) do name = get_name(state) old_result = get_result_from_state(state) result = assert_value(name, new_value, operator, operand) if old_result != result do notify_conditions(state, result, name) end premise = premise_to_map(fbe, fbe_attr, new_value, operator, operand) state = set_premise_to_state(state, premise) set_result_to_state(state, result) end defp update_assert(state, :left, {fbe_left, fbe_left_attr, _, operator, fbe_right, fbe_right_attr, right_value}, new_value) do name = get_name(state) old_result = get_result_from_state(state) result = assert_value(name, new_value, operator, right_value) if old_result != result do notify_conditions(state, result, name) end premise = premise_to_map(fbe_left, fbe_left_attr, new_value, operator, fbe_right, fbe_right_attr, right_value) state = set_premise_to_state(state, premise) set_result_to_state(state, result) end defp update_assert(state, :right, {fbe_left, fbe_left_attr, left_value, operator, fbe_right, fbe_right_attr, _}, new_value) do name = get_name(state) old_result = get_result_from_state(state) result = assert_value(name, left_value, operator, new_value) if old_result != result do notify_conditions(state, result, name) end premise = premise_to_map(fbe_left, fbe_left_attr, left_value, operator, fbe_right, fbe_right_attr, new_value) state = set_premise_to_state(state, premise) set_result_to_state(state, result) end defp update_my_state(_state, _name, _element_name, _values, _old_result) do true end end