{-# LANGUAGE DeriveAnyClass #-}
{-|
Module: IHP.Router.Types
Copyright: (c) digitally induced GmbH, 2020
-}
module IHP.Router.Types where

import Prelude
import Data.ByteString (ByteString)
import Control.Exception (Exception)
import Network.HTTP.Types.Method
import qualified Data.HashMap.Strict as HashMap
import Data.Attoparsec.ByteString.Char8 (Parser)
import Network.Wai (Application)
import IHP.Router.Trie (RouteTrie)

-- | A controller route entry. Three flavours:
--
-- * 'ControllerRouteMap' — the legacy 'AutoRoute' path: a pre-built HashMap
--   of full paths to handlers, plus a custom-routes fallback 'Parser'.
-- * 'ControllerRouteParser' — standalone custom 'Parser' (for helpers like
--   'IHP.RouterSupport.get', 'IHP.RouterSupport.post', 'IHP.RouterSupport.webSocketApp',
--   'IHP.RouterSupport.startPage', etc.).
-- * 'ControllerRouteTrie' — the new explicit-routes path: a pre-built trie
--   fragment carrying method-aware, capture-aware route entries. Used by
--   the @routes@ quasi-quoter.
--
-- 'IHP.RouterSupport.frontControllerToWAIApp' first merges all 'ControllerRouteTrie'
-- fragments into a single 'RouteTrie' and tries a fast, method-aware lookup against
-- it. On no match it falls back to the legacy 'ControllerRouteMap' HashMap scan
-- and, finally, to Attoparsec for the remaining custom parsers.
data ControllerRoute application
    = ControllerRouteMap
        !(HashMap.HashMap ByteString (application -> Application))
        (Parser Application)
        -- ^ Auto-route HashMap + custom routes fallback parser (lazy — only evaluated on HashMap miss)
    | ControllerRouteParser !(Parser Application)
        -- ^ Custom route parser (for get, post, webSocketApp, startPage, etc.)
    | ControllerRouteTrie !RouteTrie
        -- ^ Pre-built trie fragment from the @routes@ DSL. Method-aware; merged
        -- into the app-wide trie at startup.

data TypedAutoRouteError
    = BadType
        { TypedAutoRouteError -> ByteString
expectedType :: !ByteString
        , TypedAutoRouteError -> Maybe ByteString
value :: !(Maybe ByteString)
        , TypedAutoRouteError -> ByteString
field :: !ByteString
        }
    | TooFewArguments
    | NotMatched
    -- | Thrown when 'IHP.RouterSupport.parseUUIDArgument', 'IHP.RouterSupport.parseIntArgument', etc. get passed an invalid value
    --
    -- Let's say we have a @ShowProjectAction { id :: Id Project }@.
    --
    -- When opening @/ShowProject?projectId=ab55d579-80cd-4608-9a8f-c76dea6c2332@ everything is fine.
    -- But when opening @/ShowProject?projectId=not-an-uuid@ this exception will be thrown.
    | NoConstructorMatched
        { expectedType :: !ByteString
        , value :: !(Maybe ByteString)
        , field :: !ByteString
        }
    deriving (Int -> TypedAutoRouteError -> ShowS
[TypedAutoRouteError] -> ShowS
TypedAutoRouteError -> String
(Int -> TypedAutoRouteError -> ShowS)
-> (TypedAutoRouteError -> String)
-> ([TypedAutoRouteError] -> ShowS)
-> Show TypedAutoRouteError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> TypedAutoRouteError -> ShowS
showsPrec :: Int -> TypedAutoRouteError -> ShowS
$cshow :: TypedAutoRouteError -> String
show :: TypedAutoRouteError -> String
$cshowList :: [TypedAutoRouteError] -> ShowS
showList :: [TypedAutoRouteError] -> ShowS
Show, Show TypedAutoRouteError
Typeable TypedAutoRouteError
(Typeable TypedAutoRouteError, Show TypedAutoRouteError) =>
(TypedAutoRouteError -> SomeException)
-> (SomeException -> Maybe TypedAutoRouteError)
-> (TypedAutoRouteError -> String)
-> (TypedAutoRouteError -> Bool)
-> Exception TypedAutoRouteError
SomeException -> Maybe TypedAutoRouteError
TypedAutoRouteError -> Bool
TypedAutoRouteError -> String
TypedAutoRouteError -> SomeException
forall e.
(Typeable e, Show e) =>
(e -> SomeException)
-> (SomeException -> Maybe e)
-> (e -> String)
-> (e -> Bool)
-> Exception e
$ctoException :: TypedAutoRouteError -> SomeException
toException :: TypedAutoRouteError -> SomeException
$cfromException :: SomeException -> Maybe TypedAutoRouteError
fromException :: SomeException -> Maybe TypedAutoRouteError
$cdisplayException :: TypedAutoRouteError -> String
displayException :: TypedAutoRouteError -> String
$cbacktraceDesired :: TypedAutoRouteError -> Bool
backtraceDesired :: TypedAutoRouteError -> Bool
Exception)

-- | Thrown e.g. a @CreateProjectAction@ is called from a GET request
--
data UnexpectedMethodException
    = UnexpectedMethodException
    { UnexpectedMethodException -> [StdMethod]
allowedMethods :: [StdMethod]
    , UnexpectedMethodException -> StdMethod
method :: StdMethod
    }
    deriving (Int -> UnexpectedMethodException -> ShowS
[UnexpectedMethodException] -> ShowS
UnexpectedMethodException -> String
(Int -> UnexpectedMethodException -> ShowS)
-> (UnexpectedMethodException -> String)
-> ([UnexpectedMethodException] -> ShowS)
-> Show UnexpectedMethodException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> UnexpectedMethodException -> ShowS
showsPrec :: Int -> UnexpectedMethodException -> ShowS
$cshow :: UnexpectedMethodException -> String
show :: UnexpectedMethodException -> String
$cshowList :: [UnexpectedMethodException] -> ShowS
showList :: [UnexpectedMethodException] -> ShowS
Show, Show UnexpectedMethodException
Typeable UnexpectedMethodException
(Typeable UnexpectedMethodException,
 Show UnexpectedMethodException) =>
(UnexpectedMethodException -> SomeException)
-> (SomeException -> Maybe UnexpectedMethodException)
-> (UnexpectedMethodException -> String)
-> (UnexpectedMethodException -> Bool)
-> Exception UnexpectedMethodException
SomeException -> Maybe UnexpectedMethodException
UnexpectedMethodException -> Bool
UnexpectedMethodException -> String
UnexpectedMethodException -> SomeException
forall e.
(Typeable e, Show e) =>
(e -> SomeException)
-> (SomeException -> Maybe e)
-> (e -> String)
-> (e -> Bool)
-> Exception e
$ctoException :: UnexpectedMethodException -> SomeException
toException :: UnexpectedMethodException -> SomeException
$cfromException :: SomeException -> Maybe UnexpectedMethodException
fromException :: SomeException -> Maybe UnexpectedMethodException
$cdisplayException :: UnexpectedMethodException -> String
displayException :: UnexpectedMethodException -> String
$cbacktraceDesired :: UnexpectedMethodException -> Bool
backtraceDesired :: UnexpectedMethodException -> Bool
Exception)

-- | Thrown when the request uses an HTTP method that isn't part of the
-- standard set (GET, POST, PUT, DELETE, HEAD, OPTIONS, PATCH, CONNECT, TRACE).
--
-- For example, a @PROPFIND@ request from a WebDAV scanner. The error handler
-- middleware translates this into a @400 Bad Request@ response.
newtype BadHttpMethodException
    = BadHttpMethodException { BadHttpMethodException -> ByteString
method :: ByteString }
    deriving (Int -> BadHttpMethodException -> ShowS
[BadHttpMethodException] -> ShowS
BadHttpMethodException -> String
(Int -> BadHttpMethodException -> ShowS)
-> (BadHttpMethodException -> String)
-> ([BadHttpMethodException] -> ShowS)
-> Show BadHttpMethodException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> BadHttpMethodException -> ShowS
showsPrec :: Int -> BadHttpMethodException -> ShowS
$cshow :: BadHttpMethodException -> String
show :: BadHttpMethodException -> String
$cshowList :: [BadHttpMethodException] -> ShowS
showList :: [BadHttpMethodException] -> ShowS
Show, Show BadHttpMethodException
Typeable BadHttpMethodException
(Typeable BadHttpMethodException, Show BadHttpMethodException) =>
(BadHttpMethodException -> SomeException)
-> (SomeException -> Maybe BadHttpMethodException)
-> (BadHttpMethodException -> String)
-> (BadHttpMethodException -> Bool)
-> Exception BadHttpMethodException
SomeException -> Maybe BadHttpMethodException
BadHttpMethodException -> Bool
BadHttpMethodException -> String
BadHttpMethodException -> SomeException
forall e.
(Typeable e, Show e) =>
(e -> SomeException)
-> (SomeException -> Maybe e)
-> (e -> String)
-> (e -> Bool)
-> Exception e
$ctoException :: BadHttpMethodException -> SomeException
toException :: BadHttpMethodException -> SomeException
$cfromException :: SomeException -> Maybe BadHttpMethodException
fromException :: SomeException -> Maybe BadHttpMethodException
$cdisplayException :: BadHttpMethodException -> String
displayException :: BadHttpMethodException -> String
$cbacktraceDesired :: BadHttpMethodException -> Bool
backtraceDesired :: BadHttpMethodException -> Bool
Exception)