-module(tfte_server).

-behaviour(gen_statem).


%%% INCLUDES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

-include_lib("kernel/include/logger.hrl").


%%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% API functions
-export([start_link/0]).
-export([context_ready/1]).
-export([context_event/1]).
-export([topology_ready/1]).
-export([topology_event/1]).

% Behaviour gen_statem functions
-export([init/1]).
-export([callback_mode/0]).
-export([handle_event/4]).
-export([terminate/3]).
-export([code_change/4]).


%%% Records %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

-record(data, {
}).


%%% MACROS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


%%% API FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

start_link() ->
    gen_statem:start_link(?MODULE, [], []).

context_ready(Context) ->
    gen_statem:cast(?MODULE, {context_ready, Context}).

context_event(Event) ->
    gen_statem:cast(?MODULE, {context_event, Event}).

topology_ready(Topology) ->
    gen_statem:cast(?MODULE, {topology_ready, Topology}).

topology_event(Event) ->
    gen_statem:cast(?MODULE, {topology_event, Event}).


%%% BEHAVIOUR gen_statem FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

init([]) ->
    ?LOG_INFO("Starting server...", []),
    {ok, wait_context, #data{}}.

callback_mode() -> [handle_event_function, state_enter].

%-- WAIT_CONTEXT STATE ---------------------------------------------------------
handle_event(enter, _, wait_context, _Data) ->
    keep_state_and_data;
handle_event(cast, {context_ready, _Context}, wait_contex, Data) ->
    ?LOG_DEBUG("Teraflow context initialized: ~p", [_Context]),
    tfte_topology:context_updated(),
    {next_state, ready, Data};
%-- READY STATE ----------------------------------------------------------------
handle_event(enter, _, ready, _Data) ->
    keep_state_and_data;
handle_event(cast, {context_ready, _Context}, ready, _Data) ->
    ?LOG_DEBUG("Teraflow context updated: ~p", [_Context]),
    tfte_topology:context_updated(),
    keep_state_and_data;
handle_event(cast, {context_event, _Event}, ready, _Data) ->
    ?LOG_DEBUG("Teraflow context event: ~p", [_Event]),
    keep_state_and_data;
handle_event(cast, {topology_ready, _Topology}, ready, _Data) ->
    ?LOG_DEBUG("Teraflow topology updated: ~p", [_Topology]),
    keep_state_and_data;
handle_event(cast, {topology_event, _Event}, ready, _Data) ->
    ?LOG_DEBUG("Teraflow topology event: ~p", [_Event]),
    keep_state_and_data;
%-- ANY STATE ------------------------------------------------------------------
handle_event(EventType, EventContent, State, Data) ->
    ?LOG_WARNING(Data, "Unexpected ~w event in state ~w: ~w",
                 [EventType, State, EventContent]),
    keep_state_and_data.

terminate(Reason, _State, _Data) ->
    ?LOG_INFO("Server terminated: ~p", [Reason]),
    ok.

code_change(_OldVsn, OldState, OldData, _Extra) ->
    {ok, OldState, OldData}.


%%% INTERNAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
