%%%-------------------------------------------------------------------
%% @doc
  = =    = =
  Libp2p2 Proxy Envelope API
%% @end
%%%-------------------------------------------------------------------
-module(libp2p_proxy_envelope).

-export([
    decode/1,
    encode/1,
    create/2,
    id/1,
    data/1
]).

-include("pb/libp2p_proxy_pb.hrl").

-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.

-type proxy_envelope() :: #libp2p_proxy_envelope_pb{}.

-export_type([proxy_envelope/0]).

%%--------------------------------------------------------------------
%% @doc
%% Decode proxy_envelope binary to record
%% @end
%%--------------------------------------------------------------------
-spec decode(binary()) -> proxy_envelope().
decode(Bin) when is_binary(Bin) ->
    libp2p_proxy_pb:decode_msg(Bin, libp2p_proxy_envelope_pb).

%%--------------------------------------------------------------------
%% @doc
%% Encode proxy_envelope record to binary
%% @end
%%--------------------------------------------------------------------
-spec encode(proxy_envelope()) -> binary().
encode(#libp2p_proxy_envelope_pb{}=Env) ->
    libp2p_proxy_pb:encode_msg(Env).

%%--------------------------------------------------------------------
%% @doc
%% Create an envelope
%% @end
%%--------------------------------------------------------------------
-spec create(binary(), libp2p_proxy_req:proxy_req()
                       | libp2p_proxy_resp:proxy_resp()
                       | libp2p_proxy_dial_back:proxy_dial_back()
                       | libp2p_proxy_error:proxy_error()
                       | libp2p_proxy_overload:proxy_overload()) -> proxy_envelope().
create(ID, #libp2p_proxy_req_pb{}=Data) ->
    #libp2p_proxy_envelope_pb{
        id=ID,
        data={req, Data}
    };
create(ID, #libp2p_proxy_resp_pb{}=Data) ->
    #libp2p_proxy_envelope_pb{
        id=ID,
        data={resp, Data}
    };
create(ID, #libp2p_proxy_dial_back_pb{}=Data) ->
    #libp2p_proxy_envelope_pb{
        id=ID,
        data={dial_back, Data}
    };
create(ID, #libp2p_proxy_error_pb{}=Data) ->
    #libp2p_proxy_envelope_pb{
        id=ID,
        data={error, Data}
    };
create(ID, #libp2p_proxy_overload_pb{}=Data) ->
    #libp2p_proxy_envelope_pb{
        id=ID,
        data={overload, Data}
    }.

%%--------------------------------------------------------------------
%% @doc
%% Getter
%% @end
%%--------------------------------------------------------------------
-spec id(proxy_envelope()) -> binary().
id(Env) ->
    Env#libp2p_proxy_envelope_pb.id.

%%--------------------------------------------------------------------
%% @doc
%% Getter
%% @end
%%--------------------------------------------------------------------
-spec data(proxy_envelope()) -> {req, libp2p_proxy_req:proxy_req()}
                                | {resp, libp2p_proxy_resp:proxy_resp()}
                                | {dial_back, libp2p_proxy_dial_back:proxy_dial_back()}
                                | {error, libp2p_proxy_error:proxy_error()}
                                | {overload, libp2p_proxy_overload:proxy_overload()}.
data(Env) ->
    Env#libp2p_proxy_envelope_pb.data.

%% ------------------------------------------------------------------
%% Internal Function Definitions
%% ------------------------------------------------------------------

%% ------------------------------------------------------------------
  EUNIT Tests
%% ------------------------------------------------------------------
-ifdef(TEST).

decode_encode_test() ->
    Req = libp2p_proxy_req:create("456"),
    EnvEncoded = encode(create(<<"123">>, Req)),
    EnvDecoded = decode(EnvEncoded),

    ?assertEqual(<<"123">>, id(EnvDecoded)),
    ?assertEqual({req, Req}, data(EnvDecoded)).

get_test() ->
    Req = libp2p_proxy_req:create("456"),
    Env = create(<<"123">>, Req),

    ?assertEqual(<<"123">>, id(Env)),
    ?assertEqual({req, Req}, data(Env)).

-endif.

-------------------------------------------------------------------
 @doc
 @end
-------------------------------------------------------------------
--------------------------------------------------------------------
 @doc
 Decode proxy_envelope binary to record
 @end
--------------------------------------------------------------------
--------------------------------------------------------------------
 @doc
 Encode proxy_envelope record to binary
 @end
--------------------------------------------------------------------
--------------------------------------------------------------------
 @doc
 Create an envelope
 @end
--------------------------------------------------------------------
--------------------------------------------------------------------
 @doc
 Getter
 @end
--------------------------------------------------------------------
--------------------------------------------------------------------
 @doc
 Getter
 @end
--------------------------------------------------------------------
 ------------------------------------------------------------------
 Internal Function Definitions
 ------------------------------------------------------------------
 ------------------------------------------------------------------
 ------------------------------------------------------------------
  = =    = =
  Libp2p2 Proxy Envelope API
-module(libp2p_proxy_envelope).

-export([
    decode/1,
    encode/1,
    create/2,
    id/1,
    data/1
]).

-include("pb/libp2p_proxy_pb.hrl").

-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.

-type proxy_envelope() :: #libp2p_proxy_envelope_pb{}.

-export_type([proxy_envelope/0]).

-spec decode(binary()) -> proxy_envelope().
decode(Bin) when is_binary(Bin) ->
    libp2p_proxy_pb:decode_msg(Bin, libp2p_proxy_envelope_pb).

-spec encode(proxy_envelope()) -> binary().
encode(#libp2p_proxy_envelope_pb{}=Env) ->
    libp2p_proxy_pb:encode_msg(Env).

-spec create(binary(), libp2p_proxy_req:proxy_req()
                       | libp2p_proxy_resp:proxy_resp()
                       | libp2p_proxy_dial_back:proxy_dial_back()
                       | libp2p_proxy_error:proxy_error()
                       | libp2p_proxy_overload:proxy_overload()) -> proxy_envelope().
create(ID, #libp2p_proxy_req_pb{}=Data) ->
    #libp2p_proxy_envelope_pb{
        id=ID,
        data={req, Data}
    };
create(ID, #libp2p_proxy_resp_pb{}=Data) ->
    #libp2p_proxy_envelope_pb{
        id=ID,
        data={resp, Data}
    };
create(ID, #libp2p_proxy_dial_back_pb{}=Data) ->
    #libp2p_proxy_envelope_pb{
        id=ID,
        data={dial_back, Data}
    };
create(ID, #libp2p_proxy_error_pb{}=Data) ->
    #libp2p_proxy_envelope_pb{
        id=ID,
        data={error, Data}
    };
create(ID, #libp2p_proxy_overload_pb{}=Data) ->
    #libp2p_proxy_envelope_pb{
        id=ID,
        data={overload, Data}
    }.

-spec id(proxy_envelope()) -> binary().
id(Env) ->
    Env#libp2p_proxy_envelope_pb.id.

-spec data(proxy_envelope()) -> {req, libp2p_proxy_req:proxy_req()}
                                | {resp, libp2p_proxy_resp:proxy_resp()}
                                | {dial_back, libp2p_proxy_dial_back:proxy_dial_back()}
                                | {error, libp2p_proxy_error:proxy_error()}
                                | {overload, libp2p_proxy_overload:proxy_overload()}.
data(Env) ->
    Env#libp2p_proxy_envelope_pb.data.


  EUNIT Tests
-ifdef(TEST).

decode_encode_test() ->
    Req = libp2p_proxy_req:create("456"),
    EnvEncoded = encode(create(<<"123">>, Req)),
    EnvDecoded = decode(EnvEncoded),

    ?assertEqual(<<"123">>, id(EnvDecoded)),
    ?assertEqual({req, Req}, data(EnvDecoded)).

get_test() ->
    Req = libp2p_proxy_req:create("456"),
    Env = create(<<"123">>, Req),

    ?assertEqual(<<"123">>, id(Env)),
    ?assertEqual({req, Req}, data(Env)).

-endif.
