%%
%% %CopyrightBegin%
%% 
%% Copyright Ericsson AB 1997-2024. All Rights Reserved.
%% 
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%%     http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%% 
%% %CopyrightEnd%
%%
-module(snmpa_agent_sup).
-moduledoc false.

-include("snmp_debug.hrl").

-behaviour(supervisor).

%% External exports
-export([start_link/0, start_link/1,
         start_master_agent/1,
         start_subagent/3, stop_subagent/1]).

%% Internal exports
-export([init/1]).

-define(SERVER, ?MODULE).
%% Always use plain ets for sub-agents
-ifdef(snmp_debug).
-define(DEFAULT_SA_OPTS, [{mib_storage, [{module, snmpa_mib_storage_ets}]}, 
			  {verbosity, trace}]).
-else.
-define(DEFAULT_SA_OPTS, [{mib_storage, [{module, snmpa_mib_storage_ets}]}]).
-endif.


%%%-----------------------------------------------------------------
%%% This is a supervisor for the agent processes (master and sub).
%%%-----------------------------------------------------------------
start_link() ->
    ?d("start_link -> entry", []),
    supervisor:start_link({local, ?SERVER}, ?MODULE, [[]]).

start_link(AgentSpec) ->
    ?d("start_link -> entry with"
	"~n   AgentSpec: ~p", [AgentSpec]),
    supervisor:start_link({local, ?SERVER}, ?MODULE, [[AgentSpec]]).

start_master_agent(MasterAgentSpec) ->
    supervisor:start_child(snmpa_agent_sup, MasterAgentSpec).

start_subagent(ParentAgent, Subtree, Mibs) ->
    ?d("start_subagent -> entry with"
	"~n   ParentAgent: ~p"
	"~n   Subtree:     ~p"
	"~n   Mibs:        ~p", [ParentAgent, Subtree, Mibs]),
    Children = supervisor:which_children(?SERVER),
    ?d("start_subagent -> Children: ~n~p", [Children]),
    Max = find_max(Children, 1),
    ?d("start_subagent -> Max: ~p", [Max]),
    [{_, Prio}] = ets:lookup(snmp_agent_table, priority),
    ?d("start_subagent -> Prio: ~p", [Prio]),
    Ref = make_ref(),
    ?d("start_subagent -> Ref: ~p", [Ref]),
    Options = [{priority, Prio}, 
	       {mibs,     Mibs}, 
	       {misc_sup, snmpa_misc_sup} | ?DEFAULT_SA_OPTS],
    Agent = {{sub_agent, Max},
	     {snmpa_agent, start_link,
	      [Prio, ParentAgent, Ref, Options]},
	     permanent, 2000, worker, [snmpa_agent]},
    case supervisor:start_child(?SERVER, Agent) of
	{ok, SA} -> 
	    ?d("start_subagent -> SA: ~p", [SA]),
	    snmpa_agent:register_subagent(ParentAgent, Subtree, SA),
	    {ok, SA};
	Error ->
	    ?d("start_subagent -> Error: ~p", [Error]),
	    Error
    end.

stop_subagent(SubAgentPid) ->
    case find_name(supervisor:which_children(?SERVER), SubAgentPid) of
	undefined -> 
	    no_such_child;
	Name ->
	    supervisor:terminate_child(?SERVER, Name),
	    supervisor:delete_child(?SERVER, Name),
	    ok
    end.

init([Children]) ->
    ?d("init -> entry with"
	"~n   Children: ~p", [Children]),
    %% 20 restarts in ten minutes.  If the agent crashes and restarts,
    %% it may very well crash again, because the management application
    %% tries to resend the very same request.  This depends on the resend
    %% strategy used by the management application.
    SupFlags = {one_for_one, 20, 600},
    {ok, {SupFlags, Children}}.


find_max([{{sub_agent, N}, _, _, _} | T], M) when N >= M -> find_max(T, N+1);
find_max([_|T], M) -> find_max(T, M);
find_max([], M) -> M.

find_name([{Name, Pid, _, _} | _T], Pid)-> Name;
find_name([_|T], Pid) -> find_name(T, Pid);
find_name([], _Pid) -> undefined.


% i(F) ->
%     i(F, []).

% i(F, A) ->
%     io:format("~p:~p: " ++ F ++ "~n", [node(),?MODULE|A]).
