{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}

{-|
 
 This module defines several instances needed to use 'LIO' as the
 underlying monad with "Web.Simple", the simple web framework.
 Additionally, we provide some middleware for executing apps in a safe
 manner.

 "LIO.Web.Simple.TCB" defines several functions that can be used to
 execute 'LIO' web applications with the Warp server.

-}
module LIO.Web.Simple (
    -- * Utilities for parsing request
    body, parseForm
    -- * Middleware
  , browserLabelGuard
  , removeRequestHeaders
  , removeResponseHeaders 
    -- * LIO applications
  , SimpleLIOApplication, SimpleLIOMiddleware
  , LIOController
    -- * Relevant modules
  , module Web.Simple.Responses
  , module Web.Simple.Templates
  , module Web.Simple.Controller.Trans
  ) where

import safe LIO
import LIO.TCB (ioTCB)
import LIO.Web.Simple.TCB

import safe Web.Simple hiding (request, body, parseForm)
import safe Web.Simple.Responses
import safe Web.Simple.Controller.Trans
import safe Web.Simple.Templates

import Network.Wai.Parse

import Data.Conduit
import qualified Data.Conduit.List as CL

import qualified Data.ByteString as S
import qualified Data.ByteString.Lazy as L
import safe qualified Data.ByteString.Lazy.Char8 as L8


-- | Controller with 'LIO' as the underlying monad.
type LIOController l s = ControllerT s (LIO l)

-- | Parses a HTML form from the request body. It returns a list of 'Param's as
-- well as a list of 'File's, which are pairs mapping the name of a /file/ form
-- field to a 'FileInfo' pointing to a temporary file with the contents of the
-- upload.
--
-- Currently only tursted code can read the file.
parseForm :: Label l
  => LIOController l r ([Param], [(S.ByteString, FileInfo L.ByteString)])
parseForm = do
  req <- request
  liftLIO . ioTCB $ parseRequestBody lbsBackEnd req

-- | Parses a HTML form from the request body. It returns a list of 'Param's as
-- well as a list of 'File's, which are pairs mapping the name of a /file/ form
-- field to a 'FileInfo' pointing to a temporary file with the contents of the

-- | Reads and returns the body of the HTTP request.
--
-- Note: @body@ function consumes the body from a Source IO
-- Bytestring.  Since the 'Request' constructor is exposed by
-- "Network.Wai.Internal", it's important to disallow construction of
-- such values when considering untrusted code.
body :: Label l => LIOController l r L8.ByteString
body = do
  req <- request
  liftLIO . ioTCB $ L8.fromChunks `fmap` (requestBody req $$ CL.consume)

instance Label l => MonadLIO l (ControllerT r (LIO l)) where
  liftLIO act = ControllerT $ \st _ ->
      liftLIO act >>= \r -> return (Right r, st)