    {-# LANGUAGE CPP #-}
    {-# LANGUAGE ConstraintKinds #-}
    {-# LANGUAGE FlexibleContexts #-}
    {-# LANGUAGE FlexibleInstances #-}
    {-# LANGUAGE TupleSections #-}
    {-# LANGUAGE TypeFamilies #-}
    {-# LANGUAGE UndecidableInstances #-}

    module Yesod.Core.Class.Handler
        ( MonadHandler (..)
        , MonadWidget (..)
        , liftHandlerT
        , liftWidgetT
        ) where

    import Yesod.Core.Types
    import Control.Monad.Logger (MonadLogger)
    import Control.Monad.Trans.Resource (MonadResource)
    import Control.Monad.Trans.Class (lift)
    import Data.Conduit.Internal (Pipe, ConduitM)

    import Control.Monad.Trans.Identity ( IdentityT)
    #if !MIN_VERSION_transformers(0,6,0)
    import Control.Monad.Trans.List     ( ListT    )
    #endif
    import Control.Monad.Trans.Maybe    ( MaybeT   )
    import Control.Monad.Trans.Except   ( ExceptT  )
    import Control.Monad.Trans.Reader   ( ReaderT  )
    import Control.Monad.Trans.State    ( StateT   )
    import Control.Monad.Trans.Writer   ( WriterT  )
    import Control.Monad.Trans.RWS      ( RWST     )
    import qualified Control.Monad.Trans.RWS.Strict    as Strict ( RWST   )
    import qualified Control.Monad.Trans.State.Strict  as Strict ( StateT )
    import qualified Control.Monad.Trans.Writer.Strict as Strict ( WriterT )

    -- FIXME should we just use MonadReader instances instead?
    class (MonadResource m, MonadLogger m) => MonadHandler m where
        type HandlerSite m
        type SubHandlerSite m
        liftHandler :: HandlerFor (HandlerSite m) a -> m a
        liftSubHandler :: SubHandlerFor (SubHandlerSite m) (HandlerSite m) a -> m a

    liftHandlerT :: MonadHandler m => HandlerFor (HandlerSite m) a -> m a
    liftHandlerT :: forall (m :: * -> *) a.
    MonadHandler m =>
    HandlerFor (HandlerSite m) a -> m a
    liftHandlerT = HandlerFor (HandlerSite m) a -> m a
    forall a. HandlerFor (HandlerSite m) a -> m a
    forall (m :: * -> *) a.
    MonadHandler m =>
    HandlerFor (HandlerSite m) a -> m a
    liftHandler
    {-# DEPRECATED liftHandlerT "Use liftHandler instead" #-}

    instance MonadHandler (HandlerFor site) where
        type HandlerSite (HandlerFor site) = site
        type SubHandlerSite (HandlerFor site) = site
        liftHandler :: forall a.
    HandlerFor (HandlerSite (HandlerFor site)) a -> HandlerFor site a
    liftHandler = HandlerFor site a -> HandlerFor site a
    HandlerFor (HandlerSite (HandlerFor site)) a -> HandlerFor site a
    forall a. a -> a
    id
        {-# INLINE liftHandler #-}
        liftSubHandler :: forall a.
    SubHandlerFor
      (SubHandlerSite (HandlerFor site))
      (HandlerSite (HandlerFor site))
      a
    -> HandlerFor site a
    liftSubHandler (SubHandlerFor HandlerData
      (SubHandlerSite (HandlerFor site)) (HandlerSite (HandlerFor site))
    -> IO a
    f) = (HandlerData site site -> IO a) -> HandlerFor site a
    forall site a. (HandlerData site site -> IO a) -> HandlerFor site a
    HandlerFor HandlerData site site -> IO a
    HandlerData
      (SubHandlerSite (HandlerFor site)) (HandlerSite (HandlerFor site))
    -> IO a
    f
        {-# INLINE liftSubHandler #-}

    instance MonadHandler (SubHandlerFor sub master) where
        type HandlerSite (SubHandlerFor sub master) = master
        type SubHandlerSite (SubHandlerFor sub master) = sub
        liftHandler :: forall a.
    HandlerFor (HandlerSite (SubHandlerFor sub master)) a
    -> SubHandlerFor sub master a
    liftHandler (HandlerFor HandlerData
      (HandlerSite (SubHandlerFor sub master))
      (HandlerSite (SubHandlerFor sub master))
    -> IO a
    f) = (HandlerData sub master -> IO a) -> SubHandlerFor sub master a
    forall sub master a.
    (HandlerData sub master -> IO a) -> SubHandlerFor sub master a
    SubHandlerFor ((HandlerData sub master -> IO a) -> SubHandlerFor sub master a)
    -> (HandlerData sub master -> IO a) -> SubHandlerFor sub master a
    forall a b. (a -> b) -> a -> b
    $ \HandlerData sub master
    hd -> HandlerData
      (HandlerSite (SubHandlerFor sub master))
      (HandlerSite (SubHandlerFor sub master))
    -> IO a
    f HandlerData sub master
    hd
          { handlerEnv =
              let rhe = HandlerData sub master -> RunHandlerEnv sub master
    forall child site.
    HandlerData child site -> RunHandlerEnv child site
    handlerEnv HandlerData sub master
    hd
               in rhe
                    { rheRoute = fmap (rheRouteToMaster rhe) (rheRoute rhe)
                    , rheRouteToMaster = id
                    , rheChild = rheSite rhe
                    }
          }
        {-# INLINE liftHandler #-}
        liftSubHandler :: forall a.
    SubHandlerFor
      (SubHandlerSite (SubHandlerFor sub master))
      (HandlerSite (SubHandlerFor sub master))
      a
    -> SubHandlerFor sub master a
    liftSubHandler = SubHandlerFor sub master a -> SubHandlerFor sub master a
    SubHandlerFor
      (SubHandlerSite (SubHandlerFor sub master))
      (HandlerSite (SubHandlerFor sub master))
      a
    -> SubHandlerFor sub master a
    forall a. a -> a
    id
        {-# INLINE liftSubHandler #-}

    instance MonadHandler (WidgetFor site) where
        type HandlerSite (WidgetFor site) = site
        type SubHandlerSite (WidgetFor site) = site
        liftHandler :: forall a.
    HandlerFor (HandlerSite (WidgetFor site)) a -> WidgetFor site a
    liftHandler (HandlerFor HandlerData
      (HandlerSite (WidgetFor site)) (HandlerSite (WidgetFor site))
    -> IO a
    f) = (WidgetData site -> IO a) -> WidgetFor site a
    forall site a. (WidgetData site -> IO a) -> WidgetFor site a
    WidgetFor ((WidgetData site -> IO a) -> WidgetFor site a)
    -> (WidgetData site -> IO a) -> WidgetFor site a
    forall a b. (a -> b) -> a -> b
    $ HandlerData site site -> IO a
    HandlerData
      (HandlerSite (WidgetFor site)) (HandlerSite (WidgetFor site))
    -> IO a
    f (HandlerData site site -> IO a)
    -> (WidgetData site -> HandlerData site site)
    -> WidgetData site
    -> IO a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . WidgetData site -> HandlerData site site
    forall site. WidgetData site -> HandlerData site site
    wdHandler
        {-# INLINE liftHandler #-}
        liftSubHandler :: forall a.
    SubHandlerFor
      (SubHandlerSite (WidgetFor site)) (HandlerSite (WidgetFor site)) a
    -> WidgetFor site a
    liftSubHandler (SubHandlerFor HandlerData
      (SubHandlerSite (WidgetFor site)) (HandlerSite (WidgetFor site))
    -> IO a
    f) = (WidgetData site -> IO a) -> WidgetFor site a
    forall site a. (WidgetData site -> IO a) -> WidgetFor site a
    WidgetFor ((WidgetData site -> IO a) -> WidgetFor site a)
    -> (WidgetData site -> IO a) -> WidgetFor site a
    forall a b. (a -> b) -> a -> b
    $ HandlerData site site -> IO a
    HandlerData
      (SubHandlerSite (WidgetFor site)) (HandlerSite (WidgetFor site))
    -> IO a
    f (HandlerData site site -> IO a)
    -> (WidgetData site -> HandlerData site site)
    -> WidgetData site
    -> IO a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . WidgetData site -> HandlerData site site
    forall site. WidgetData site -> HandlerData site site
    wdHandler
        {-# INLINE liftSubHandler #-}

    #define GO(T) instance MonadHandler m => MonadHandler (T m) where type HandlerSite (T m) = HandlerSite m; type SubHandlerSite (T m) = SubHandlerSite m; liftHandler = lift . liftHandler; liftSubHandler = lift . liftSubHandler
    #define GOX(X, T) instance (X, MonadHandler m) => MonadHandler (T m) where type HandlerSite (T m) = HandlerSite m; type SubHandlerSite (T m) = SubHandlerSite m; liftHandler = lift . liftHandler; liftSubHandler = lift . liftSubHandler
    GO(IdentityT)
    #if !MIN_VERSION_transformers(0,6,0)
    GO(ListT)
    #endif
    GO(MaybeT)
    GO(ExceptT e)
    GO(ReaderT r)
    GO(StateT s)
    GOX(Monoid w, WriterT w)
    GOX(Monoid w, RWST r w s)
    GOX(Monoid w, Strict.RWST r w s)
    GO(Strict.StateT s)
    GOX(Monoid w, Strict.WriterT w)
    GO(Pipe l i o u)
    GO(ConduitM i o)
    #undef GO
    #undef GOX

    class MonadHandler m => MonadWidget m where
        liftWidget :: WidgetFor (HandlerSite m) a -> m a
    instance MonadWidget (WidgetFor site) where
        liftWidget :: forall a.
    WidgetFor (HandlerSite (WidgetFor site)) a -> WidgetFor site a
    liftWidget = WidgetFor site a -> WidgetFor site a
    WidgetFor (HandlerSite (WidgetFor site)) a -> WidgetFor site a
    forall a. a -> a
    id
        {-# INLINE liftWidget #-}

    liftWidgetT :: MonadWidget m => WidgetFor (HandlerSite m) a -> m a
    liftWidgetT :: forall (m :: * -> *) a.
    MonadWidget m =>
    WidgetFor (HandlerSite m) a -> m a
    liftWidgetT = WidgetFor (HandlerSite m) a -> m a
    forall a. WidgetFor (HandlerSite m) a -> m a
    forall (m :: * -> *) a.
    MonadWidget m =>
    WidgetFor (HandlerSite m) a -> m a
    liftWidget
    {-# DEPRECATED liftWidgetT "Use liftWidget instead" #-}

    #define GO(T) instance MonadWidget m => MonadWidget (T m) where liftWidget = lift . liftWidget
    #define GOX(X, T) instance (X, MonadWidget m) => MonadWidget (T m) where liftWidget = lift . liftWidget
    GO(IdentityT)
    #if !MIN_VERSION_transformers(0,6,0)
    GO(ListT)
    #endif
    GO(MaybeT)
    GO(ExceptT e)
    GO(ReaderT r)
    GO(StateT s)
    GOX(Monoid w, WriterT w)
    GOX(Monoid w, RWST r w s)
    GOX(Monoid w, Strict.RWST r w s)
    GO(Strict.StateT s)
    GOX(Monoid w, Strict.WriterT w)
    GO(Pipe l i o u)
    GO(ConduitM i o)
    #undef GO
    #undef GOX