%%%-----------------------------------------------------------------------------
%%% @copyright (C) 2010-2019, 2600Hz
%%% @doc Collect DTMF into an optional key for later retrieval.
%%%
%%%
Data options:
%%%
%%% - `max_digits'
%%% - Maximum digits to collect. Default is to collect one digit.
%%%
%%% - `max_digits'
%%% - How long to wait for first DTMF, in milliseconds
%%%
%%% - `terminator'
%%% - What DTMF stops collection (and aren't included). Possible values are [0-9*#]. Default is `#'.
%%%
%%% - `terminators'
%%% - What DTMFs stops collection (and aren't included). Possible values are [0-9*#]. Default is `#'.
%%%
%%% - `interdigit_timeout'
%%% - How long to wait for the next DTMF, in milliseconds
%%%
%%% - `collection_name'
%%% - The name of the collection to store collected numbers for later processing
%%%
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(cf_collect_dtmf).
-behaviour(gen_cf_action).
-include("callflow.hrl").
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.
-export([handle/2]).
%%------------------------------------------------------------------------------
%% @doc Entry point for this module
%% @end
%%------------------------------------------------------------------------------
-spec handle(kz_json:object(), kapps_call:call()) -> 'ok'.
handle(Data, Call) ->
kapps_call_command:answer(Call),
AlreadyCollected =
case kapps_call:get_dtmf_collection(Call) of
'undefined' -> <<>>;
<<_/binary>> = D -> D
end,
AlreadyCollected1 = truncate_after_terminator(AlreadyCollected, terminators(Data)),
maybe_collect_more_digits(Data, kapps_call:set_dtmf_collection('undefined', Call), AlreadyCollected1).
-spec maybe_collect_more_digits(kz_json:object(), kapps_call:call(), binary()) -> 'ok'.
maybe_collect_more_digits(Data, Call, AlreadyCollected) ->
AlreadyCollectedSize = byte_size(AlreadyCollected),
MaxDigits = max_digits(Data),
maybe_collect_more_digits(Data, Call, AlreadyCollected, AlreadyCollectedSize, MaxDigits),
cf_exe:continue(Call).
-spec maybe_collect_more_digits(kz_json:object(), kapps_call:call(), binary(), non_neg_integer(), pos_integer()) -> 'ok'.
maybe_collect_more_digits(Data, Call, AlreadyCollected, ACS, Max) when ACS >= Max ->
lager:debug("early DTMF met collection criteria, not collecting any more digits"),
<> = AlreadyCollected,
CollectionName = collection_name(Data),
cf_exe:set_call(kapps_call:set_dtmf_collection(Head, CollectionName, Call));
maybe_collect_more_digits(Data, Call, AlreadyCollected, ACS, Max) ->
collect_more_digits(Data, Call, AlreadyCollected, Max-ACS).
-spec collect_more_digits(kz_json:object(), kapps_call:call(), binary(), pos_integer()) -> 'ok'.
collect_more_digits(Data, Call, AlreadyCollected, MaxDigits) ->
case kapps_call_command:collect_digits(MaxDigits
,collect_timeout(Data)
,interdigit(Data)
,'undefined'
,terminators(Data)
,Call
)
of
{'ok', Ds} ->
CollectionName = collection_name(Data),
lager:debug("collected ~s~s for ~s", [AlreadyCollected, Ds, CollectionName]),
cf_exe:set_call(
kapps_call:set_dtmf_collection(<>, CollectionName, Call)
);
{'error', _E} ->
lager:debug("failed to collect DTMF: ~p", [_E])
end.
-spec truncate_after_terminator(binary(), kz_term:ne_binaries()) -> binary().
truncate_after_terminator(AlreadyCollected, Terminators) ->
hd(binary:split(AlreadyCollected, Terminators)).
-ifdef(TEST).
truncate_after_terminator_test_() ->
[?_assertEqual(<<"1234">>, truncate_after_terminator(<<"1234#456#789">>, [<<"#">>, <<"*">>]))
,?_assertEqual(<<"1234">>, truncate_after_terminator(<<"1234">>, [<<"#">>]))
,?_assertEqual(<<"123">>, truncate_after_terminator(<<"123#">>, [<<"#">>, <<"*">>]))
,?_assertEqual(<<"1">>, truncate_after_terminator(<<"1*2#3">>, [<<"#">>, <<"*">>]))
,?_assertEqual(<<>>, truncate_after_terminator(<<"#234">>, [<<"#">>]))
].
-endif.
-spec collection_name(kz_json:object()) -> kz_term:ne_binary().
collection_name(Data) ->
case kz_json:get_value(<<"collection_name">>, Data) of
<<_/binary>> = Name -> Name;
'undefined' -> <<"default">>
end.
-spec max_digits(kz_json:object()) -> pos_integer().
max_digits(Data) ->
case kz_json:get_integer_value(<<"max_digits">>, Data) of
'undefined' -> 1;
N when N > 0 -> N
end.
-spec collect_timeout(kz_json:object()) -> pos_integer().
collect_timeout(Data) ->
case kz_json:get_integer_value(<<"timeout">>, Data) of
'undefined' -> 5000;
N when N > 0 -> N
end.
-spec interdigit(kz_json:object()) -> pos_integer().
interdigit(Data) ->
case kz_json:get_integer_value(<<"interdigit_timeout">>, Data) of
'undefined' -> kapps_call_command:default_interdigit_timeout();
N when N > 0 -> N
end.
-spec terminators(kz_json:object()) -> kz_term:ne_binaries().
terminators(Data) ->
case kz_json:get_first_defined([<<"terminator">>, <<"terminators">>], Data) of
'undefined' -> [<<"#">>];
<<_/binary>> = T ->
'true' = lists:member(T, ?ANY_DIGIT),
[T];
[_|_] = Ts ->
'true' = lists:all(fun(T) -> lists:member(T, ?ANY_DIGIT) end, Ts),
lists:usort(Ts)
end.