Advertisement
jazzmonster

iso4217.erl

Dec 3rd, 2017
464
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Erlang 7.60 KB | None | 0 0
  1. -module(iso4217).
  2.  
  3. -export([
  4.   start_link/0,
  5.   stop/1,
  6.   convert/1,
  7.   convert_to_chars/1,
  8.   convert_to_number/1,
  9.   get_ccy/1
  10. ]).
  11.  
  12. %% Gen_server behaviour
  13. -behaviour(gen_server).
  14. -export([
  15.   init/1,
  16.   handle_call/3,
  17.   handle_cast/2,
  18.   handle_info/2,
  19.   terminate/2,
  20.   code_change/3
  21. ]).
  22.  
  23. -include_lib("xmerl/include/xmerl.hrl").
  24.  
  25. -define(MODULE_NAME,                 ?MODULE).
  26. -define(SERVER,                      ?MODULE).
  27.  
  28. -define(ISO4217_NUMBER_PRIMARY,      iso4217).
  29. %% {CcyNbr, Ccy, CcyNm, CcyMnrUnts, [CtryNm]}
  30. -define(ISO4217_CHARS_PRIMARY, iso4217_index).
  31. %% {Ccy, CcyNbr, CcyNm, CcyMnrUnts, [CtryNm]}
  32.  
  33. %%%===================================================================
  34. %%% API
  35. %%%===================================================================
  36.  
  37. -spec start_link() -> {ok, pid()}.
  38. start_link() ->
  39.   gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
  40.  
  41. -spec stop(atom()) -> ok.
  42. stop(New_storage) ->
  43.   gen_server:cast(?SERVER, {stop, New_storage}).
  44.  
  45.  
  46. -spec convert(#{ccy_nbr := integer()}) -> #{ccy => string()}
  47.           ;  (#{ccy := string()}) -> #{ccy_nbr => integer()}
  48.           ;  (integer() | string()) -> #{ccy => string()} | #{ccy_nbr => integer()}.
  49. convert(CcyCode) when is_map(CcyCode) ->
  50.   gen_server:call(?SERVER, {convert_ccy_code, CcyCode});
  51. convert(CcyCode) when is_integer(CcyCode) ->
  52.   gen_server:call(?SERVER, {convert_ccy_code, #{ccy_nbr => CcyCode}});
  53. convert(CcyCode) when is_list(CcyCode) ->
  54.   gen_server:call(?SERVER, {convert_ccy_code, #{ccy => CcyCode}}).
  55.  
  56. -spec convert_to_chars(#{ccy_nbr := integer()} | integer()) -> #{ccy => string()}.
  57. convert_to_chars(#{ccy_nbr := CcyNbr}) ->
  58.   gen_server:call(?SERVER, {convert_ccy_code, #{ccy_nbr => CcyNbr}});
  59. convert_to_chars(CcyNbr) ->
  60.   gen_server:call(?SERVER, {convert_ccy_code, #{ccy_nbr => CcyNbr}}).
  61.  
  62. -spec convert_to_number(#{ccy := string()} | string()) -> #{ccy_nbr => integer()}.
  63. convert_to_number(#{ccy := Ccy}) ->
  64.   gen_server:call(?SERVER, {convert_ccy_code, #{ccy => Ccy}});
  65. convert_to_number(Ccy) ->
  66.   gen_server:call(?SERVER, {convert_ccy_code, #{ccy => Ccy}}).
  67.  
  68. -spec get_ccy(#{ccy_nbr := integer()} |
  69.               integer() |
  70.               #{ccy := string()} |
  71.               string()) ->
  72.                 #{ccy => string(),
  73.                   ccy_nbr => integer(),
  74.                   ccy_nm => string(),
  75.                   ccy_mnr_unts => integer() | string(),
  76.                   countries_list => [string()]}.
  77. get_ccy(#{ccy_nbr := CcyNbr}) ->
  78.   gen_server:call(?SERVER, {get_ccy, #{ccy_nbr => CcyNbr}});
  79. get_ccy(#{ccy := Ccy}) ->
  80.   gen_server:call(?SERVER, {get_ccy, #{ccy => Ccy}});
  81. get_ccy(CcyNbr) when is_integer(CcyNbr) ->
  82.   gen_server:call(?SERVER, {get_ccy, #{ccy_nbr => CcyNbr}});
  83. get_ccy(Ccy) when is_list(Ccy) ->
  84.   gen_server:call(?SERVER, {get_ccy, #{ccy => Ccy}}).
  85.  
  86. %%%===================================================================
  87. %%% Gen_server callbacks
  88. %%%===================================================================
  89.  
  90. init([]) ->
  91.   ?ISO4217_NUMBER_PRIMARY = ets:new(?ISO4217_NUMBER_PRIMARY, [public, named_table]),
  92.   ?ISO4217_CHARS_PRIMARY = ets:new(?ISO4217_CHARS_PRIMARY, [public, named_table]),
  93.  
  94.   {Document, _Misc} = xmerl_scan:file("xml/iso4217/list_one.xml"),
  95.   Content = Document#xmlElement.content,
  96.   CcyTbl = getCcyTbl(Content),
  97.   CcyTblContent = CcyTbl#xmlElement.content,
  98.  
  99.   lists:map(fun(Elem) ->
  100.     case is_record(Elem, xmlElement) of
  101.       true when Elem#xmlElement.name == 'CcyNtry' ->
  102.         CcyNtryContent = Elem#xmlElement.content,
  103.         insertCcyNtry(CcyNtryContent);
  104.       _ ->
  105.         ok
  106.     end
  107.   end, CcyTblContent),
  108.   {ok, null}.
  109.  
  110. handle_call({convert_ccy_code, #{ccy_nbr := CcyNbr}}, _, State) ->
  111.   Reply = case ets:lookup(?ISO4217_NUMBER_PRIMARY, CcyNbr) of
  112.     [] ->
  113.       {error, wrong_currency_number};
  114.     [{_, Ccy, _, _, _}] ->
  115.       #{ccy => Ccy}
  116.   end,
  117.   {reply, Reply, State};
  118.  
  119. handle_call({convert_ccy_code, #{ccy := Ccy}}, _, State) ->
  120.   Reply = case ets:lookup(?ISO4217_CHARS_PRIMARY, Ccy) of
  121.     [] ->
  122.       {error, wrong_currency_code};
  123.     [{_, CcyNbr, _, _, _}] ->
  124.       #{ccy_nbr => CcyNbr}
  125.   end,
  126.   {reply, Reply, State};
  127.  
  128. handle_call({get_ccy, #{ccy_nbr := CcyNbr}}, _, State) ->
  129.   Reply = case ets:lookup(?ISO4217_NUMBER_PRIMARY, CcyNbr) of
  130.     [] ->
  131.       {error, wrong_currency_number};
  132.     [{CcyNbr, Ccy, CcyNm, CcyMnrUnts, CtrysList}] ->
  133.       #{ccy => Ccy,
  134.         ccy_nbr => CcyNbr,
  135.         ccy_nm => CcyNm,
  136.         ccy_mnr_unts => CcyMnrUnts,
  137.         countries_list => CtrysList}
  138.   end,
  139.   {reply, Reply, State};
  140.  
  141. handle_call({get_ccy, #{ccy := Ccy}}, _, State) ->
  142.   Reply = case ets:lookup(?ISO4217_CHARS_PRIMARY, Ccy) of
  143.     [] ->
  144.       {error, wrong_currency_code};
  145.     [{Ccy, CcyNbr, CcyNm, CcyMnrUnts, CtrysList}] ->
  146.       #{ccy => Ccy,
  147.         ccy_nbr => CcyNbr,
  148.         ccy_nm => CcyNm,
  149.         ccy_mnr_unts => CcyMnrUnts,
  150.         countries_list => CtrysList}
  151.   end,
  152.   {reply, Reply, State};
  153.  
  154. handle_call(_, _, State) -> {reply, ignored, State}.
  155.  
  156.  
  157. handle_cast({stop, _New_storage}, State) ->
  158.   {stop, normal, State};
  159.  
  160. handle_cast(_, State) -> {noreply, State}.
  161.  
  162.  
  163. handle_info(_, State) -> {noreply, State}.
  164.  
  165.  
  166. terminate(_Reason, _State) ->
  167.   ok.
  168.  
  169.  
  170. code_change(_OldVsn, State, _Extra) ->
  171.   {ok, State}.
  172.  
  173.  
  174. %%%===================================================================
  175. %%% Internal functions
  176. %%%===================================================================
  177.  
  178.  
  179. getCcyTbl(Content) ->
  180.   [CcyTbl | Tail] = lists:filter(fun(Elem) ->
  181.     case is_record(Elem, xmlElement) of
  182.       true when Elem#xmlElement.name == 'CcyTbl' ->
  183.         lists:any(fun({PName, _}) -> PName == 'ISO_4217' end, Elem#xmlElement.parents);
  184.       _ -> false
  185.     end
  186.   end, Content),
  187.   if not(Tail == []) ->
  188.     io:format("Warning! You have more than one CcyTbl (ISO4217) in your xml file. Read first.");
  189.     true -> ok end,
  190.   CcyTbl.
  191.  
  192.  
  193. insertCcyNtry(CcyNtryContent) ->
  194.   CtryNm = getValue('CtryNm', CcyNtryContent),
  195.   CcyNm = getValue('CcyNm', CcyNtryContent),
  196.   Ccy = getValue('Ccy', CcyNtryContent),
  197.   CcyNbr = case getValue('CcyNbr', CcyNtryContent) of
  198.     Num when is_list(Num) ->
  199.       list_to_integer(Num);
  200.     Num ->
  201.       Num
  202.   end,
  203.   CcyMnrUnts = case getValue('CcyMnrUnts', CcyNtryContent) of
  204.     MnrUnts when is_list(MnrUnts) ->
  205.       try list_to_integer(MnrUnts) of
  206.         CcyMnrUntsRes ->
  207.           CcyMnrUntsRes
  208.       catch
  209.         error:badarg -> MnrUnts
  210.       end;
  211.     MnrUnts ->
  212.       MnrUnts
  213.   end,  
  214.   case lists:any(
  215.     fun(Val) -> Val == none end, [CtryNm, CcyNm, Ccy, CcyNbr, CcyMnrUnts]
  216.   ) of
  217.     true ->
  218.       io:format("Unexpected currency entry: ~p ~p ~p ~p ~p~n",
  219.         [CtryNm, CcyNm, Ccy, CcyNbr, CcyMnrUnts]);
  220.     false ->
  221.       case ets:lookup(?ISO4217_NUMBER_PRIMARY, CcyNbr) of
  222.         [] ->
  223.           ets:insert(?ISO4217_NUMBER_PRIMARY, {CcyNbr, Ccy, CcyNm, CcyMnrUnts, [CtryNm]}),
  224.           ets:insert(?ISO4217_CHARS_PRIMARY, {Ccy, CcyNbr, CcyNm, CcyMnrUnts, [CtryNm]});
  225.         [{CcyNbr, _, _, _, CtryNmList}] ->
  226.           ets:insert(?ISO4217_NUMBER_PRIMARY, {CcyNbr, Ccy, CcyNm, CcyMnrUnts, [CtryNm | CtryNmList]}),
  227.           ets:insert(?ISO4217_CHARS_PRIMARY, {Ccy, CcyNbr, CcyNm, CcyMnrUnts, [CtryNm | CtryNmList]})
  228.       end
  229.   end.
  230.  
  231. getValue(Nm, Content) ->
  232.   lists:foldl(fun(Elem, Acc) ->
  233.     case Acc of
  234.       none ->
  235.         case is_record(Elem, xmlElement) of
  236.           true when Elem#xmlElement.name == Nm ->
  237.             ElemContent = Elem#xmlElement.content,
  238.             [Text] = ElemContent,
  239.             Text#xmlText.value;
  240.           _ -> none
  241.         end;
  242.       Value ->
  243.         Value
  244.     end
  245.   end, none, Content).
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement