{- | Access helper functions in a Reader-Writer-State monad -}
module Data.Accessor.Monad.Trans.RWS where

import qualified Data.Accessor.Basic as Accessor
import qualified Control.Monad.Trans.RWS as RWS
import qualified Control.Monad.Trans.Class as Trans
import Control.Monad.Trans.RWS (RWS, runRWS, RWST(runRWST), )
import Control.Monad.Trans.Class (MonadTrans, )
import Data.Monoid (Monoid)


-- * accessors in the form of actions in the RWS monad

set :: (Monad m, Monoid w) => Accessor.T s a -> a -> RWST r w s m ()
set f x = RWS.modify (Accessor.set f x)

get :: (Monad m, Monoid w) => Accessor.T s a -> RWST r w s m a
get f = RWS.gets (Accessor.get f)

modify :: (Monad m, Monoid w) => Accessor.T s a -> (a -> a) -> RWST r w s m ()
modify f g = RWS.modify (Accessor.modify f g)

{- |
Modify a record element and return its old value.
-}
getAndModify :: (Monad m, Monoid w) => Accessor.T s a -> (a -> a) -> RWST r w s m a
getAndModify f g =
   do x <- get f
      modify f g
      return x

{- |
Modify a record element and return its new value.
-}
modifyAndGet :: (Monad m, Monoid w) => Accessor.T s a -> (a -> a) -> RWST r w s m a
modifyAndGet f g =
   do modify f g
      get f



infix 1 %=, %:

{- |
Infix variant of 'set'.
-}
(%=) :: (Monad m, Monoid w) => Accessor.T s a -> a -> RWST r w s m ()
(%=) = set

{- |
Infix variant of 'modify'.
-}
(%:) :: (Monad m, Monoid w) => Accessor.T s a -> (a -> a) -> RWST r w s m ()
(%:) = modify



-- * lift a RWS monadic accessor to an accessor of a parent record

lift :: (Monad m, Monoid w) => Accessor.T s1 s0 -> RWS r w s0 a -> RWST r w s1 m a
lift f m =
   do r <- RWS.ask
      s0 <- get f
      let (a,s1,w) = runRWS m r s0
      set f s1
      RWS.tell w
      return a

liftT :: (Monad m, Monoid w) =>
   Accessor.T s1 s0 -> RWST r w s0 m a -> RWST r w s1 m a
liftT f m =
   do r <- RWS.ask
      s0 <- get f
      (a,s1,w) <- Trans.lift $ runRWST m r s0
      set f s1
      RWS.tell w
      return a