%% @author Justin Sheehy <justin@basho.com>
%% @author Andy Gross <andy@basho.com>
%% @copyright 2007-2008 Basho Technologies
%%
%%    Licensed under the Apache License, Version 2.0 (the "License");
%%    you may not use this file except in compliance with the License.
%%    You may obtain a copy of the License at
%%
%%        http://www.apache.org/licenses/LICENSE-2.0
%%
%%    Unless required by applicable law or agreed to in writing, software
%%    distributed under the License is distributed on an "AS IS" BASIS,
%%    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%%    See the License for the specific language governing permissions and
%%    limitations under the License.

%% @doc Mochiweb interface for webmachine.
-module(webmachine_mochiweb).
-author('Justin Sheehy <justin@basho.com>').
-author('Andy Gross <andy@basho.com>').
-export([start/1, stop/0, loop/1]).

start(Options) ->
    {DispatchList, Options1} = get_option(dispatch, Options),
    {ErrorHandler0, Options2} = get_option(error_handler, Options1),
    {EnablePerfLog, Options3} = get_option(enable_perf_logger, Options2),
    ErrorHandler = 
	case ErrorHandler0 of 
	    undefined ->
		webmachine_error_handler;
	    EH -> EH
	end,
    {LogDir, Options4} = get_option(log_dir, Options3),
    webmachine_sup:start_logger(LogDir),
    case EnablePerfLog of
	true ->
	    application:set_env(webmachine, enable_perf_logger, true),
	    webmachine_sup:start_perf_logger(LogDir);
	_ ->
	    ignore
    end,
    application:set_env(webmachine, dispatch_list, DispatchList),
    application:set_env(webmachine, error_handler, ErrorHandler),
    mochiweb_http:start([{name, ?MODULE}, {loop, fun loop/1} | Options4]).

stop() ->
    mochiweb_http:stop(?MODULE).

loop(MochiReq) ->
    Req = webmachine:new_request(mochiweb, MochiReq),
    {ok, DispatchList} = application:get_env(webmachine, dispatch_list),
    Host = case host_headers(Req) of
               [H|_] -> H;
               [] -> []
           end,
    case webmachine_dispatcher:dispatch(Host, Req:path(), DispatchList) of
        {no_dispatch_match, _UnmatchedHost, _UnmatchedPathTokens} ->
            {ok, ErrorHandler} = application:get_env(webmachine, error_handler),
	    ErrorHTML = ErrorHandler:render_error(404, Req, {none, none, []}),
	    Req:append_to_response_body(ErrorHTML),
	    Req:send_response(404),
	    LogData = Req:log_data(),
	    LogModule = 
                case application:get_env(webmachine,webmachine_logger_module) of
		    {ok, Val} -> Val;
		    _ -> webmachine_logger
		end,
	    spawn(LogModule, log_access, [LogData]),
	    Req:stop();
        {Mod, ModOpts, HostTokens, Port, PathTokens, Bindings,
         AppRoot, StringPath} ->
            BootstrapResource = webmachine_resource:new(x,x,x,x),
            {ok, Resource} = BootstrapResource:wrap(Mod, ModOpts),
	    Req:load_dispatch_data(Bindings,HostTokens,Port,PathTokens,
                                   AppRoot,StringPath,Req),
	    Req:set_metadata('resource_module', Mod),
            webmachine_decision_core:handle_request(Req, Resource)
    end.

get_option(Option, Options) ->
    {proplists:get_value(Option, Options), proplists:delete(Option, Options)}.

host_headers(Req) ->
    [ V || V <- [Req:get_header_value(H)
                 || H <- ["x-forwarded-for",
                          "x-forwarded-host",
                          "x-forwarded-server",
                          "host"]],
           V /= undefined].
