%% -*- mode: erlang; erlang-indent-level: 4; indent-tabs-mode: nil -*-
%% @doc Exometer metrics
{mapping, "exometer.template.function.module", "exometer.defaults",
 [{default, "exometer_function"}]
}.
{mapping, "exometer.template.counter.module", "exometer.defaults",
 [{default, "exometer"}]
}.
{mapping, "exometer.template.fast_counter.module", "exometer.defaults",
 [{default, "exometer"}]
}.
{mapping, "exometer.template.histogram.module", "exometer.defaults",
[{default, "exometer_histogram"}]}.
{mapping, "exometer.template.spiral.module", "exometer.defaults",
[{default, "exometer_spiral"}]}.
{mapping, "exometer.template.duration.module", "exometer.defaults",
 [{default, "exometer_folsom"}]
}.
{mapping, "exometer.template.meter.module", "exometer.defaults",
 [{default, "exometer_folsom"}]
}.
{mapping, "exometer.template.gauge.module", "exometer.defaults",
 [{default, "exometer_folsom"}]
}.
{mapping, "exometer.template.$type.$option", "exometer.defaults",[]}.
{mapping, "exometer.template.$pattern.$type.$option", "exometer.defaults",[]}.

{mapping, "exometer.pattern.all", "exometer.defaults", [{default,"_"}]}.
{mapping, "exometer.pattern.$name", "exometer.defaults", []}.

{mapping, "exometer.probe.default.min_heap_size", "exometer.probe_defaults",
 [{datatype, integer},
  {default, "40000"}]
}.
{mapping, "exometer.probe.default.priority", "exometer.probe_defaults",
 [{datatype, {enum, [low,normal,high,max]}},
  {default, "normal"}]
}.
{mapping, "exometer.probe.default.min_vheap_size", "exometer.probe_defaults",
 [{datatype, integer},
  {default, 0}]
}.
{mapping, "exometer.probe.default.sensitive", "exometer.probe_defaults",
 [{datatype, {enum, [true, false]}},
  {default, false}]
}.
{mapping, "exometer.probe.default.scheduler", "exometer.probe_defaults",
 [{datatype, integer},
  {default, 0}]
}.

{mapping, "exometer.reporter.collectd", "exometer.reporters",
 [{datatype, atom}, {default, exometer_report_collectd}]}.
{mapping, "exometer.reporter.opt.collectd.module", "exometer.reporters",
 [{datatype, atom}, {default, exometer_report_collectd}]}.
{mapping, "exometer.reporter.opt.collectd.connect_timeout", "exometer.reporters",
 [{datatype, {duration, ms}}, {default, "5s"}]}.
{mapping, "exometer.reporter.opt.collectd.read_timeout", "exometer.reporters",
 [{datatype, {duration, ms}}, {default, "5s"}]}.
{mapping, "exometer.reporter.opt.collectd.reconnect_interval", "exometer.reporters",
 [{datatype, {duration, s}}, {default, "30s"}]}.
{mapping, "exometer.reporter.opt.collectd.refresh_interval", "exometer.reporters",
 [{datatype, {duration, s}}, {default, "10s"}]}.
{mapping, "exometer.reporter.opt.collectd.path", "exometer.reporters",
 [{datatype, string}, {default, "/var/run/collectd-unixsock"}]}.
{mapping, "exometer.reporter.opt.collectd.plugin_name", "exometer.reporters",
 [{datatype, string}, {default, "exometer"}]}.
{mapping, "exometer.reporter.opt.collectd.plugin_instance", "exometer.reporters",
 [{datatype, string}, {default, "auto"}]}.
{mapping, "exometer.reporter.opt.collectd.hostname", "exometer.reporters",
 [{datatype, string}, {default, "auto"}]}.


{mapping, "exometer.reporter.$name", "exometer.reporters", [{datatype, atom}]}.
{mapping, "exometer.reporter.opt.$name.$option", "exometer.reporters", []}.

{translation, "exometer.defaults",
 fun(Conf) ->
         Parse = fun(X) ->
                         case erl_scan:string(X) of
                             {ok,Toks,_} ->
                                 erl_parse:parse_term(
                                   Toks ++ [{dot,1}]);
                             ScanErr ->
                                 ScanErr
                         end
                 end,
	 MkVal = fun(X) ->
                         case Parse(X) of
                             {ok, Term} -> Term;
                             {error, _} -> X
                         end
		 end,
	 MkKey = fun("[" ++ _ = S) ->
                         case Parse(S) of
                             {ok, Term} -> Term;
                             {error, R} -> error({parse_error, R})
                         end;
		    (S) ->
			 L = string:tokens(S, "."),
			 lists:map(fun(K) ->
					   try list_to_integer(K)
					   catch
					       error:_ ->
						   list_to_atom(K)
					   end
				   end, L)
		 end,
         Pats = [{P, MkKey(V)}
                 || {["exometer","pattern", P], V} <- Conf],
         Templ = [{"all", list_to_atom(Type), {list_to_atom(Opt), MkVal(V)} }
                  || {["exometer","template",Type,Opt], V} <- Conf] ++
             [{P, list_to_atom(Type), {list_to_atom(Opt), MkVal(V)} }
              || {["exometer","template",P,Type,Opt], V} <- Conf],
         Grouped = lists:foldl(
                     fun({P,T,O}, D) ->
                             orddict:append({P,T}, O, D)
                     end, orddict:new(), Templ),
         lists:map(
           fun({ {P,T}, Opts }) ->
                   case lists:keyfind(P,1,Pats) of
                       {_, Pat} ->
                           {Pat, T, Opts};
                       false ->
                           if P == "all" ->
                                   {['_'], T, Opts};
                              true ->
                                   error({unknown_exometer_pattern,P})
                           end
                   end
           end, orddict:to_list(Grouped))
 end}.

{translation, "exometer.probe_defaults",
 fun(Conf) ->
         [{list_to_atom(K), V}
          || {["exometer","probe","default",K], V} <- Conf]
 end
}.


{translation, "exometer.reporters",
 fun(Conf) ->
         Parse = fun(X) ->
                         case erl_scan:string(X) of
                             {ok,Toks,_} ->
                                 erl_parse:parse_term(
                                   Toks ++ [{dot,1}]);
                             ScanErr ->
                                 ScanErr
                         end
                 end,
	 MkVal = fun(A) when is_atom(A) -> A;
                    (I) when is_integer(I) -> I;
                    (X) ->
                         case Parse(X) of
                             {ok, Term} -> Term;
                             {error, _} -> X
                         end
		 end,
	 MkKey = fun("[" ++ _ = S) ->
                         case Parse(S) of
                             {ok, Term} -> Term;
                             {error, R} -> error({parse_error, R})
                         end;
		    (S) ->
			 L = string:tokens(S, "."),
			 lists:map(fun(K) ->
					   try list_to_integer(K)
					   catch
					       error:_ ->
						   list_to_atom(K)
					   end
				   end, L)
		 end,
         Reporters = (catch [{R, RegName}
                      || {["exometer", "reporter", R], RegName} <- Conf]),
         Rep = fun(R) -> case lists:keyfind(R,1,Reporters) of
                             false -> '';
                             {_, N} -> N
                         end
               end,
         Opts = [{Rep(R), {list_to_atom(K), MkVal(V)}}
                 || {["exometer","reporter","opt",R,K], V} <- Conf],
         Maps = [{Rep(R), MA, V}
                 || {["exometer","reporter","map",R,MA], V} <- Conf],
         Types = [{Rep(R), TA, V}
                 || {["exometer","reporter","type",R,TA], V} <- Conf],
         Dict0 = orddict:from_list([{N,[]} || {_,N} <- Reporters]),
         TypeMap = lists:foldl(
                     fun({'',_,_}, D) -> D;
                        ({N, A, Metric}, D) ->
                             case [T || {N1,A1,T} <- Types, N==N1, A==A1] of
                                 [] -> D;
                                 [Type] ->
                                     Key = MkKey(Metric),
                                     orddict:append(N, {Key,Type}, D)
                             end
                     end, Dict0, Maps),
         Dict1 = lists:foldl(
                   fun({'',_}, D) -> D;
                      ({R,Opt}, D) ->
                           orddict:append(R, Opt, D)
                   end, Dict0, Opts),
         orddict:fold(fun(N,L,D) ->
                              case orddict:is_key(N,D) of
                                  true ->
                                      orddict:append(N,{type_map,L},D);
                                  false ->
                                      D
                              end
                      end, Dict1, TypeMap)
 end
}.

%% exometer.report.collectd.module = exometer_report_collectd
%% exometer.report.collectd.option.reconnect_interval = 10
%% exometer.report.collectd.entry.a.b.2
%% exometer.report.module.exometer_report_collectd.reconnect_interval = 10
%% exometer.report.module.
%% {mapping, "exometer.report.module.collectd", "exometer.report",
%%  [{default, "exometer_report_collectd"}]
%% }.
%% {mapping, "exometer.report.module.$mod", "exometer.report",[]}.
%% {mapping, "exometer.report.module.option.$mod.$opt", "exometer.report",[]}.
%% {mapping, "exometer.report.sub.$mod.$entry", "exometer.report",[]}.
%% {mapping, "exometer.report.sub.point.$mod.$entry.$point", "exometer.report",[]}.
%% {mapping, "exometer.report.sub.option.$mod.$entry.$opt", "exometer.report",[]}.
%% {mapping, "exometer.report.sub.interval.$mod.$entry", "exometer.report", []}.

%% {translation, "exometer.report",
%%  fun(Conf) ->
%%          io:fwrite(user, "exometer.schema translation, exometer.report~n"
%%                    "Conf = ~p~n", [Conf]),
%% 	 K = fun(L) -> ["exometer", "report"] ++ L end,
%%          Parse = fun(X) ->
%%                          case erl_scan:string(X) of
%%                              {ok,Toks,_} ->
%%                                  erl_parse:parse_term(
%%                                    Toks ++ [{dot,1}]);
%%                              ScanErr ->
%%                                  ScanErr
%%                          end
%%                  end,
%% 	 MkVal = fun(X) ->
%%                          case Parse(X) of
%%                              {ok, Term} -> Term;
%%                              {error, _} -> X
%%                          end
%% 		 end,
%% 	 OptInt = fun(X) -> try list_to_integer(X)
%% 			    catch error:_ -> X end
%% 		  end,
%% 	 MkKey = fun("[" ++ _ = S) ->
%%                          case Parse(S) of
%%                              {ok, Term} -> Term;
%%                              {error, R} -> error({parse_error, R})
%%                          end;
%% 		    (S) ->
%% 			 L = string:tokens(S, "."),
%% 			 lists:map(fun(K) ->
%% 					   try list_to_integer(K)
%% 					   catch
%% 					       error:_ ->
%% 						   list_to_atom(K)
%% 					   end
%% 				   end, L)
%% 		 end,
%% 	 try
%% 	     ModDefs = [{A,list_to_atom(M)}
%% 			|| {["exometer","report","module",A], M} <- Conf],
%% 	     Subs = [{A, proplists:get_value(A,ModDefs), E, MkKey(K)}
%% 		     || {["exometer","report","sub",A,E], K} <- Conf,
%% 			lists:keymember(A, 1, ModDefs)],
%% 	     Modules = lists:map(
%% 			 fun({Alias, Mod}) ->
%% 				 Opts = [{list_to_atom(K), OptInt(V)}
%% 					 || {["exometer","report","module","option",
%% 					      Alias, K], V} <- Conf],
%% 				 {Mod, Opts}
%% 			 end, ModDefs),
%%              Subscribers =
%%                  lists:map(
%%                    fun({Alias,Mod,E,Entry}) ->
%%                            Point = case [MkVal(V)
%%                                          || {["exometer","report","sub",
%%                                               "point",Alias,E,P], V} <- Conf] of
%%                                        [P|_] -> P;
%%                                        []    -> default
%%                                    end,
%%                            Interval =
%%                                case [MkVal(V)
%%                                      || {["exometer","report","sub",
%%                                           "interval",Alias,E], V} <- Conf] of
%%                                    [I|_] -> I;
%%                                    [] -> 1000
%%                                end,
%%                            {Mod, Entry, Point, Interval}
%%                    end, Subs),
%% 	     [{modules, Modules},
%% 	      {subscribers, Subscribers}]
%% 	 catch
%% 	     error:R -> [{error, R}]
%% 	 end
%%  end}.

