--[[----------------------------------------------------------------------------

WFRxHttpServerUtils.lua

--------------------------------------------------------------------------------

ADOBE CONFIDENTIAL
------------------
Copyright 2019 Adobe
All Rights Reserved.

NOTICE: All information contained herein is, and remains
the property of Adobe and its suppliers, if any. The intellectual
and technical concepts contained herein are proprietary to Adobe
and its suppliers and are protected by all applicable intellectual
property laws, including trade secret and copyright laws.
Dissemination of this information or reproduction of this material
is strictly forbidden unless prior written permission is obtained
from Adobe.

------------------------------------------------------------------------------]]

local Rx = require "Rx"

--------------------------------------------------------------------------------

local WFRxHttpServerUtils = {}

--------------------------------------------------------------------------------

--[[ \brief Helper for starting an HTTP Server request.

	\param handlers A list of pattern, methodList, handler

		When the request is started, the handler list is searched for a matching pattern. This is done 
		using string.match, so if you need to match an entire string, it is recommended to use a restrictive 
		pattern for it. For example, if you only want to match '/', use the pattern '^/$.
		
	    When the pattern matches and the methodList contains the requested method, the handler function 
		will be called with these parameters:
        - path (string): The path of the request uri (that matches pathOrPattern)
        - info: a table with:
                - \c query (string): The query string (if present)
                - \c remoteAddr (string): The address of the requester
                - \c method (string): the HTTP Method
                - \c matches (array): if pathOrPattern contains capture expressions, the matches will be in this array
                - \c postData (string): The data passed into a POST request (if present)

        Upon return, the function must return an Observable. If the request cannot be served, an error
        should be returned by setting an explicit status code, for example:
		return Rx.Observable.just{ statusCode = 404, data = 'not found' }

        The Observable will be subjected to a :take( 1 ). Longer running observables are not supported, because they
        could hog the server for a long time.

	\param uri The request uri
	\param requestParams A table with:
            - \c query (string): The query string (if present)
            - \c remoteAddr (string): The address of the requester
            - \c method (string): the HTTP Method
            - \c postData (string): The data passed into a POST request (if present)
			- \c clientCert: If client  certificates are enabled, a table with:
				- \c (string) finger
				- \c (string) issuer
				- \c (string) subject
				- \c (string) serial
				- \c (WFCertificate) certificate
	\param ... The arguments passed into WFRxHttpServer.start

	\returns an Observable(table), where the table contains either:
		- statusCode and data
		- contentType and data
		- contentType and filePath
]]--

function WFRxHttpServerUtils.startRequest( handlers, uri, requestParams, ... )

	local obs = Rx.Observable.just{ statusCode = 404, data = 'not found' }

	for _, handlerInfo in ipairs( handlers ) do

		local path, methods, handler = unpack( handlerInfo )

		local matches = { string.match( uri, path ) }

		if next( matches ) then

			local methodSupported = false

			for _, m in ipairs( methods ) do
				if m == requestParams.method then
					methodSupported = true
					break
				end
			end

			if methodSupported then

				requestParams.matches = matches

				local success
				success, obs = pcall( handler, uri, requestParams, ... )

				if not success then
					obs = Rx.Observable.throw( 500, obs )
				end

				break

			end

		end
	end

	return obs:take( 1 )

end

return WFRxHttpServerUtils