-module(erweb).
-export([
	start/0,
	start/2
]).

-record(state, {
	sock,
	handler
}).

-record(request, {
	method,
	uri,
	headers = []
}).

start() ->
	spawn(fun() -> start(8124, fun(_) -> "Hello, world!" end) end).

start(Port, Handler) ->
	{ok, LSock} = gen_tcp:listen(Port, [binary, {active, false}, {backlog, 128}, {reuseaddr, true}]),
	loop(#state{ sock = LSock, handler = Handler }).

loop(State = #state{ sock = LSock, handler = Handler }) ->
	{ok, Sock} = gen_tcp:accept(LSock),
	inet:setopts(Sock, [binary, {packet, http}, {active, true}]),
	Pid = spawn(fun() -> process_connection(Sock, Handler) end),
	gen_tcp:controlling_process(Sock, Pid),
	loop(State).

process_connection(Sock, Handler) ->
	Data = receive_http_packet(Sock),
	gen_tcp:send(Sock, build_http_response(Handler(Data))),
	gen_tcp:close(Sock).

receive_http_packet(Sock) ->
	receive_http_packet(Sock, #request{}).

receive_http_packet(Sock, Request = #request{ headers = Headers}) ->
	receive
		{http, _, Data} ->
			case Data of
				{http_request, Method, {abs_path, URI}, _Version} ->
					receive_http_packet(Sock, Request#request{ method = Method, uri = URI });
				{http_header, _, Name, _, Value} ->
					receive_http_packet(Sock, Request#request{ headers = [{Name, Value} | Headers] });
				http_eoh ->
					Request
			end
	after 2000 ->
		{error, timeout}
	end.

build_http_response(Body) ->
	BinBody = iolist_to_binary(Body),
	iolist_to_binary([
		<<"HTTP/1.1 200 OK\r\n">>,
		<<"Content-Length:">>, integer_to_list(size(BinBody)), <<"\r\n">>,
		<<"\r\n">>,
		BinBody
	]).
