    module Snap.Snaplet.Session
      ( SessionManager
      , withSession
      , commitSession
      , setInSession
      , getFromSession
      , deleteFromSession
      , csrfToken
      , sessionToList
      , resetSession
      , touchSession

      -- * Utilities Exported For Convenience
      , module Snap.Snaplet.Session.Common
      , module Snap.Snaplet.Session.SecureCookie
      ) where

    ------------------------------------------------------------------------------
    import           Control.Monad.State
    import           Data.Text                           (Text)
    import           Snap.Core
    ------------------------------------------------------------------------------
    import           Snap.Snaplet
    import           Snap.Snaplet.Session.Common
    import           Snap.Snaplet.Session.SecureCookie
    import           Snap.Snaplet.Session.SessionManager
                       ( ISessionManager(..), SessionManager(..) )
    import qualified Snap.Snaplet.Session.SessionManager as SM
    ------------------------------------------------------------------------------

    ------------------------------------------------------------------------------
    -- | Wrap around a handler, committing any changes in the session at the end
    --
    withSession :: SnapletLens b SessionManager
                -> Handler b v a
                -> Handler b v a
    withSession l h = do
        a <- h
        withTop l commitSession
        return a

    ------------------------------------------------------------------------------
    -- | Commit changes to session within the current request cycle
    --
    commitSession :: Handler b SessionManager ()
    commitSession = do
        SessionManager b <- loadSession
        liftSnap $ commit b

    ------------------------------------------------------------------------------
    -- | Set a key-value pair in the current session
    --
    setInSession :: Text -> Text -> Handler b SessionManager ()
    setInSession k v = do
        SessionManager r <- loadSession
        let r' = SM.insert k v r
        put $ SessionManager r'

    ------------------------------------------------------------------------------
    -- | Get a key from the current session
    --
    getFromSession :: Text -> Handler b SessionManager (Maybe Text)
    getFromSession k = do
        SessionManager r <- loadSession
        return $ SM.lookup k r

    ------------------------------------------------------------------------------
    -- | Remove a key from the current session
    --
    deleteFromSession :: Text -> Handler b SessionManager ()
    deleteFromSession k = do
        SessionManager r <- loadSession
        let r' = SM.delete k r
        put $ SessionManager r'

    ------------------------------------------------------------------------------
    -- | Returns a CSRF Token unique to the current session
    --
    csrfToken :: Handler b SessionManager Text
    csrfToken = do
        mgr@(SessionManager r) <- loadSession
        put mgr
        return $ SM.csrf r

    ------------------------------------------------------------------------------
    -- | Return session contents as an association list
    --
    sessionToList :: Handler b SessionManager [(Text, Text)]
    sessionToList = do
        SessionManager r <- loadSession
        return $ SM.toList r

    ------------------------------------------------------------------------------
    -- | Deletes the session cookie, effectively resetting the session
    --
    resetSession :: Handler b SessionManager ()
    resetSession = do
        SessionManager r <- loadSession
        r' <- liftSnap $ SM.reset r
        put $ SessionManager r'

    ------------------------------------------------------------------------------
    -- | Touch the session so the timeout gets refreshed
    --
    touchSession :: Handler b SessionManager ()
    touchSession = do
        SessionManager r <- loadSession
        let r' = SM.touch r
        put $ SessionManager r'

    ------------------------------------------------------------------------------
    -- | Load the session into the manager
    --
    loadSession :: Handler b SessionManager SessionManager
    loadSession = do
        SessionManager r <- get
        r' <- liftSnap $ load r
        return $ SessionManager r'