{-|
Module      : Network.Wai.RequestSpec.Combinators
Description : Derived parser combinators
Copyright   : Alej Cabrera 2015
License     : BSD-3
Maintainer  : cpp.cabrera@gmail.com
Stability   : experimental
Portability : POSIX
-}
module Network.Wai.RequestSpec.Combinators (
  intP,
  boolP,
  floatP,
  textP,
  bytesP,
  textPM,
  intPM,
  floatPM,
  bytesPM,

  intH,
  boolH,
  floatH,
  textH,
  bytesH,
  textHM,
  intHM,
  floatHM,
  bytesHM,

  choice
) where

import Control.Applicative
import Data.ByteString
import Data.CaseInsensitive
import Data.Foldable (asum)
import Data.Text

import Network.Wai.RequestSpec.Internal.Combinators
import Network.Wai.RequestSpec.Internal.Env
import Network.Wai.RequestSpec.Internal.Parser

----------------------------------------------------------------------
                     -- Typed Parameter Access --
----------------------------------------------------------------------

-- |
-- Require a parameter as an integral type
intP :: (Read a, Integral a) => Text -> Env -> P a
intP = param int

-- |
-- Require a parameter as a boolean: "true" | "false"
boolP :: Text -> Env -> P Bool
boolP = param bool

-- |
-- Require a parameter as a fractional type
floatP :: (Read a, Fractional a) => Text -> Env -> P a
floatP = param float

-- |
-- Require a parameter as text
textP :: Text -> Env -> P Text
textP = param pure

-- |
-- Require a parameter as bytes, applying the encoding function `f`
bytesP :: (Text -> ByteString) -> Text -> Env -> P ByteString
bytesP f = param (pure . f)

-- |
-- Optional parameter as integral
intPM :: (Read a, Integral a) => Text -> Env -> P (Maybe a)
intPM = paramM int

-- |
-- Optional parameter as fractional
floatPM :: (Read a, Fractional a) => Text -> Env -> P (Maybe a)
floatPM = paramM float

-- |
-- Optional parameter as text
textPM :: Text -> Env -> P (Maybe Text)
textPM = paramM pure

-- |
-- Optional header as bytes, applying the encoding function `f`
bytesPM :: (Text -> ByteString) -> Text -> Env -> P (Maybe ByteString)
bytesPM f = paramM (pure . f)

----------------------------------------------------------------------
                      -- Typed Header Access --
----------------------------------------------------------------------

-- |
-- Require a header as an integral type
intH :: (Integral a, Read a) => CI Text -> Env -> P a
intH = header int

-- |
-- Require a header as a boolean: "true" | "false"
boolH :: CI Text -> Env -> P Bool
boolH = header bool

-- |
-- Require a header a fractional type
floatH :: (Fractional a, Read a) => CI Text -> Env -> P a
floatH = header float

-- |
-- Require a header as text
textH :: CI Text -> Env -> P Text
textH = header pure

-- |
-- Require a header as bytes, applying the encoding function `f`
bytesH :: (Text -> ByteString) -> CI Text -> Env -> P ByteString
bytesH f = header (pure . f)

-- |
-- Optional header as text
textHM :: CI Text -> Env -> P (Maybe Text)
textHM = headerM pure

-- |
-- Optional header as integral
intHM :: (Integral a, Read a) => CI Text -> Env -> P (Maybe a)
intHM = headerM int

-- |
-- Optional header as floating
floatHM :: (Fractional a, Read a) => CI Text -> Env -> P (Maybe a)
floatHM = headerM float

-- |
-- Optional header as bytes, applying the encoding function `f`
bytesHM :: (Text -> ByteString) -> CI Text -> Env -> P (Maybe ByteString)
bytesHM f = headerM (pure . f)

----------------------------------------------------------------------
                      -- Utility Combinators --
----------------------------------------------------------------------

-- |
-- Combine a series of alternatives
-- choice [a, b, c] == a <|> b <|> c <|> empty
choice :: [P a] -> P a
choice = asum