anchor.diff:           list_parsers/0
           ]).
   
  -% Gen server hooks
  +%% Gen server hooks
   -export([init/1,
            handle_call/3,
            handle_cast/2,
  
positive.code: -spec apply_context_options([any()]) -> pass | fail.
  apply_context_options([_, _, _, _, undefined]) -> pass;
  apply_context_options([_, _, _, _, Context]) ->
    case application:get_env(erldns, context_options) of
      {ok, ContextOptions} ->
        ContextSet = sets:from_list(Context),
        Result = lists:append([
                               apply_context_match_empty_check(proplists:get_value(match_empty, ContextOptions), Context),
                               apply_context_list_check(sets:from_list(proplists:get_value(allow, ContextOptions)), ContextSet)
                              ]),
        case lists:any(fun(I) -> I =:= pass end, Result) of
          true -> pass;
          _ -> fail
        end;
      _ ->
        pass
    end.
  
  json_record_to_list(JsonRecord) ->
    [
     proplists:get_value(<<"name">>, JsonRecord),
     proplists:get_value(<<"type">>, JsonRecord),
     proplists:get_value(<<"ttl">>, JsonRecord),
     proplists:get_value(<<"data">>, JsonRecord),
     proplists:get_value(<<"context">>, JsonRecord)
    ].
  
  try_custom_parsers([_Name, _Type, _Ttl, _Rdata, _Context], []) ->
    {};
  try_custom_parsers(Data, [Parser|Rest]) ->
    case Parser:json_record_to_erlang(Data) of
      {} -> try_custom_parsers(Data, Rest);
      Record -> Record
    end.
  
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %% Internal converters
  
negative.code: %% @doc Start the parser processor.
  -spec start_link() -> any().
  start_link() ->
      gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
  
  %% @doc Takes a JSON zone and turns it into the tuple {Name, Sha, Records}.
  %%
  %% The default timeout for parsing is currently 30 seconds.
  -spec zone_to_erlang(binary()) -> [{binary(), binary(), [dns:rr()]}].
  zone_to_erlang(Zone) ->
      gen_server:call(?SERVER, {parse_zone, Zone}, ?PARSE_TIMEOUT).
  
  %% @doc Register a list of custom parser modules.
  -spec register_parsers([module()]) -> ok.
  register_parsers(Modules) ->
      erldns_log:info("Registering custom parsers: ~p", [Modules]),
      gen_server:call(?SERVER, {register_parsers, Modules}).
  
  %% @doc Regiaer a custom parser module.
  -spec register_parser(module()) -> ok.
  register_parser(Module) ->
      erldns_log:info("Registering custom parser: ~p", [Module]),
      gen_server:call(?SERVER, {register_parser, Module}).
  
  -spec list_parsers() -> [module()].
  list_parsers() ->
      gen_server:call(?SERVER, list_parsers).
  
  
  %% Gen server hooks
  init([]) ->
      {ok, #state{parsers = []}}.
  
  handle_call({parse_zone, Zone}, _From, State) ->
      {reply, json_to_erlang(Zone, State#state.parsers), State};
  
  handle_call({register_parsers, Modules}, _From, State) ->
      {reply, ok, State#state{parsers = State#state.parsers ++ Modules}};
  
  handle_call({register_parser, Module}, _From, State) ->
      {reply, ok, State#state{parsers = State#state.parsers ++ [Module]}};
  
  handle_call(list_parsers, _From, State) ->
      {reply, ok, State#state.parsers}.
  
  handle_cast(_, State) ->
      {noreply, State}.
  
  handle_info(_, State) ->
      {noreply, State}.
  
  terminate(_, _State) ->
      ok.
  
  code_change(_, State, _) ->
      {ok, State}.
  
  %% Internal API
  json_to_erlang(Zone, Parsers) ->
      json_to_erlang(Zone, Parsers, #partial_zone{}).
  
  json_to_erlang([], _Parsers, #partial_zone{name = Name,
                                             allow_notify = AllowNotify,
                                             allow_transfer = AllowTransfer,
                                             allow_update = AllowUpdate,
                                             also_notify = AlsoNotify,
                                             notify_source = NotifySource,
                                             records = Records,
                                             sha = Sha}) ->
      {Name, Sha, Records,  AllowNotify,
       AllowTransfer, AllowUpdate, AlsoNotify, NotifySource};
  json_to_erlang([Head | Tail], Parsers, #partial_zone{} = Zone) ->
  