%%
%% %CopyrightBegin%
%% 
%% Copyright Ericsson AB 2007-2020. 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%
%%

%%
%%----------------------------------------------------------------------
%% Purpose: Utility module used by the codec suites when testing flex 
%%          configured text codec(s).
%%----------------------------------------------------------------------

-module(megaco_codec_flex_lib).

%% ----

-include("megaco_test_lib.hrl").

%% ----

-export([
	 init/1, 
	 finish/1,
	 scanner_conf/1,
	 start/0, 
	 stop/1
	 ]).

-export([
	 handler/1
	]).  


%% ----

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

init(Config) when is_list(Config) ->
    %% io:format("~w:init -> entry with"
    %% 	      "~n   Config: ~p"
    %% 	      "~n", [?MODULE, Config]),
    Flag = process_flag(trap_exit, true),    
    Res = (catch start()),
    %% io:format("~w:init -> start result"
    %% 	      "~n   Res: ~p"
    %% 	      "~n", [?MODULE, Res]),
    process_flag(trap_exit, Flag),
    case Res of
	{error, {failed_loading_flex_scanner_driver, Reason}} ->
	    skip(?F("Failed loading flex driver: ~p", [Reason]));
	{error, Reason} ->
	    skip(Reason);
	{ok, FlexConfig} ->
	    [{flex_scanner, FlexConfig} | Config]
    end.
    

finish(Config) when is_list(Config) ->
    case lists:keysearch(flex_scanner, 1, Config) of
	{value, {flex_scanner, {Pid, _Conf}}} ->
	    stop(Pid),
	    lists:keydelete(flex_scanner, 1, Config);
	false ->
	    Config
    end.
    

start() ->
    Pid = proc_lib:spawn(?MODULE, handler, [self()]),
    receive
	{flex_scanner_started, Pid, Conf} ->
	    {ok, {Pid, Conf}};
	{flex_scanner_error, {failed_loading_flex_scanner_driver, Reason}} ->
 	    ?LOG("start_flex_scanner -> failed loading flex scanner driver: "
 		 "~n   Reason: ~p~n", [Reason]),
	    {error, {failed_loading_flex_scanner_driver, Reason}};
	{flex_scanner_error, Reason} ->
 	    ?LOG("start_flex_scanner -> error: "
 		 "~n   Reason: ~p~n", [Reason]),
	    {error, {failed_loading_flex_scanner_driver, Reason}}
    after 10000 ->
	    exit(Pid, kill),
	    {error, {failed_starting_flex_scanner, timeout}}
    end.


scanner_conf(Config) when is_list(Config) ->
    case lists:keysearch(flex_scanner, 1, Config) of
	{value, {flex_scanner, {Pid, Conf}}} ->
	    case ping_flex_scanner(Pid) of
		ok ->
		    Conf;
		Else ->
		    skip({no_response_from_flex_scanner_handler, Else})
	    end;
	false ->
	    skip("Flex scanner driver not loaded")
    end.


ping_flex_scanner(Pid) ->
    Pid ! {ping, self()},
    receive
	{pong, Pid} ->
	    ok
    after 5000 ->
	    timeout
    end.


stop(Pid) ->
    Pid ! stop.


handler(Pid) ->
    SMP = erlang:system_info(smp_support), 
    case (catch megaco_flex_scanner:start(SMP)) of
	{ok, PortOrPorts} ->
	    Pid ! {flex_scanner_started, self(), {flex, PortOrPorts}},
	    handler(Pid, PortOrPorts);
	{error, {load_driver, {open_error, Reason}}} ->
	    Error = {failed_loading_flex_scanner_driver, Reason},
	    Pid ! {flex_scanner_error, Error},
	    exit(Error);
	{error, {load_driver, Reason}} ->
	    Error = {failed_loading_flex_scanner_driver, Reason},
	    Pid ! {flex_scanner_error, Error},
	    exit(Error);
	Else ->
	    Error = {unknown_result_from_start_flex_scanner, Else},
	    Pid ! {flex_scanner_error, Error},
	    exit(Error)
    end.

handler(Pid, PortOrPorts) ->
    receive
	{ping, Pinger} ->
	    Pinger ! {pong, self()},
	    handler(Pid, PortOrPorts);
	{'EXIT', Port, Reason} when (PortOrPorts =:= Port) ->
	    Pid ! {flex_scanner_exit, Reason},
	    exit({flex_scanner_exit, Reason});
	{'EXIT', Port, Reason} when is_port(Port) ->
	    case megaco_flex_scanner:is_scanner_port(Port, PortOrPorts) of
		true ->
		    Pid ! {flex_scanner_exit, Reason},
		    exit({flex_scanner_exit, Reason});
		false ->
		    io:format("flex scanner handler got port exit "
			      "from unknown:"
			      "~n   ~p: ~p", [Port, Reason]),
		    ok
	    end,
	    handler(Pid, PortOrPorts);
	stop ->
	    megaco_flex_scanner:stop(PortOrPorts),
	    exit(normal);
	Other ->
	    io:format("flex scanner handler got something:~n"
		      "~p", [Other]),
	    handler(Pid, PortOrPorts)
    end.
	    

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

skip(Reason) ->
    megaco_codec_test_lib:skip(Reason).

