%% -*- coding: utf-8 -*-


%% @doc findfで使うユーティリティ関数群.


-module(findf_util).

-export([add_to_list/2, remove_from_list/2]).

-export([get_list_from_env/1, get_list_from_arg/2]).

-export([split/2]).

-compile(export_all).

%%% ============================================================
%%% リストへの、要素の追加と削除
%%% ===========================================================


%% @doc リストの先頭に要素を追加する.
%% ただし、すでに同じ要素があれば何もしない.
%% @spec(term(), list()) -> list()
add_to_list(Elm, List) ->
    case lists:member(Elm, List) of
      true -> List;
      false -> [Elm | List]
    end.

%% @doc リストから要素を取り除く.
%% 指定した要素がなければ何もしない.
%% @spec(term(), list()) -> list()
remove_from_list(Elm, List) -> lists:delete(Elm, List).

%%% ============================================================
%%% 環境変数/コマンドライン引数から、文字列リストを取得
%%% ============================================================


-define(WIN_DELM_CH, $;). % Windowsの区切り記号

-define(STD_DELM_CH, $:). % その他の標準的区切り記号

%% @doc 並びを単一文字列で表現するときの区切り記号、OSにより異なる.
%% @spec () -> string()
list_delm_ch() ->
    case os:type() of
      {win32, _} -> ?WIN_DELM_CH;
      _ -> ?STD_DELM_CH
    end.

%% @doc 引数で指定された名前の環境変数から
%% 文字列のリストを得る.
%% @spec (string()) -> [string()]
get_list_from_env(EnvName) ->
    case os:getenv(EnvName) of
      false -> [];
      EnvStr -> split(EnvStr, list_delm_ch())
    end.

%% @doc 引数で指定されたアプリケーション名、キー名をもとに、
%% コマンドライン引数から文字列のリストを得る.
%% @spec (string(), string()) -> [string()]
get_list_from_arg(AppName, KeyName) ->
    case init:get_argument(AppName) of
      error -> [];
      {ok, ListOfList} ->
	  lists:foldl(fun (List, Acc) -> gather_list(KeyName, List, Acc) end, [],
		      ListOfList)
    end.

%% @spec (KeyName::string(), KeyValues::[string()], [string()])
%%       -> [string()]
gather_list(KeyName, [KeyName | Values], Acc) ->
    Acc ++ split_and_merge_string_list(Values);
gather_list(_KeyName, _NoMatch, Acc) -> Acc.

%% @spec (StrList::[string()]) -> [string()]
split_and_merge_string_list([]) -> [];
split_and_merge_string_list([ValueStr | Rest]) ->
    List = split(ValueStr, list_delm_ch()), List ++ split_and_merge_string_list(Rest).

%%% ============================================================
%%% 文字列の分割
%%% ============================================================


%% @doc 文字列を、指定された区切り文字で分割する.
%% @spec (string(), char()) -> [string()]
split(Str, Ch) -> lists:reverse(split_rev(Str, Ch, "", [])).

%% @spec (string(), char(), string(), [string()]) -> [string()]
split_rev("", _Ch, Acc, Out) -> [lists:reverse(Acc) | Out];
split_rev([Ch | Rest], Ch, Acc, Out) ->
    split_rev(Rest, Ch, "", [lists:reverse(Acc) | Out]);
split_rev([OtherCh | Rest], Ch, Acc, Out) -> split_rev(Rest, Ch, [OtherCh | Acc], Out).