{- ColtraneTypes.hs

Sean Welleck | Yuanfeng Peng | 2013

Defines the types used by Coltrane.
-}

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

module ColtraneTypes where

import Text.Regex as TR
import qualified Data.Text as DT
import qualified Data.ByteString.Char8 as BS hiding (putStrLn)
import Network.HTTP.Types
import Network.HTTP.Types.Method
import Network.Wai
import qualified Network.Wai.Parse as Parse
import Control.Monad.Error
import qualified Control.Monad.State as MS

-- | a Route is composed of:
--
--    * a method  (uses the StdMethod type from Network.HTTP.Types.Method)
--
--    * a path    (defined below)
--
--    * a handler (defined below)
data Route = Route { 
                     method  :: StdMethod,
                     path    :: Path,
                     handler :: Handler 
}

-- | A ResponseState holds a body, headers, and a status. When used
-- with MonadState, this type makes it easy to add headers and change
-- the response status; WAI does not provide simple mechanisms for
-- modifying the headers and status.
data ResponseState = RS {
                     body    :: ResponseBody,
                     headers :: [Header],
                     status  :: Status
}

rsPlus :: ResponseState -> ResponseState -> ResponseState
rsPlus r1 r2 = RS (body r1 ++ body r2) (headers r1 ++ headers r2) (status r2)

-- | The HandlerState contains the parameters, the request object, and
-- the response state.
data HandlerState = HS {
	resp :: ResponseState,
	pms  :: Params,
	req  :: Request
}

-- | Server options for running the application.
data Server = Warp | CGI
   deriving (Show)

-- | Stores the content-type constants for the response headers.
type ContentType = BS.ByteString
ctHTML = BS.pack "text/html"
ctText = BS.pack "text/plain"
ctJSON = BS.pack "application/json"
ctFile = BS.pack "application/octet-stream"

-- | A ResponseBody is a string.
type ResponseBody = String

-- | A path is either a String Literal or a Regular Expression.
data Path = Literal String | RegExp Regex

type ParamKey = String
type ParamValue = String 
-- | Key value pairs of URL parameters.
type Params  = [(ParamKey, ParamValue)] 

-- | Converts [Parse.Param] to Params.
convertBSParams :: [Parse.Param] -> Params
convertBSParams ps = map unpack ps where
  unpack (a, b) = (BS.unpack a, BS.unpack b)

-- | A type alias to make routes intuitive for the user.
type Handler = HandlerM ()

-- | A monad that holds the application's registered routes.
newtype ColtraneApp a = C { runCA :: MS.StateT [Route] IO a }
	deriving (Monad, MS.MonadState [Route])

-- | Stores the current parameters, Request, and the
-- ResponseState that gets 'built up' in a Handler; the response body, 
-- headers, and status may be altered. The HandlerM also has 
-- error handling capabilities. The Handler is the third component of a Route;
-- a Method and a Path are associated with a Handler.
newtype HandlerM a = HM { runHM :: ErrorT String (MS.StateT HandlerState IO) a }
  deriving (Monad, MS.MonadState HandlerState, MonadError String, MonadIO)