module Control.Monad.Trans.MSF.Maybe
  ( module Control.Monad.Trans.MSF.Maybe
  , module Control.Monad.Trans.Maybe
  , maybeToExceptS
  ) where
import Control.Monad.Trans.Maybe
  hiding (liftCallCC, liftCatch, liftListen, liftPass) 
import Control.Monad.Trans.MSF.Except
import Control.Monad.Trans.MSF.GenLift
import Data.MonadicStreamFunction
exit :: Monad m => MSF (MaybeT m) a b
exit = arrM_ $ MaybeT $ return Nothing
exitWhen :: Monad m => (a -> Bool) -> MSF (MaybeT m) a a
exitWhen condition = proc a -> do
  _ <- exitIf -< condition a
  returnA     -< a
exitIf :: Monad m => MSF (MaybeT m) Bool ()
exitIf = proc condition -> if condition
  then exit    -< ()
  else returnA -< ()
maybeExit :: Monad m => MSF (MaybeT m) (Maybe a) a
maybeExit = inMaybeT
inMaybeT :: Monad m => MSF (MaybeT m) (Maybe a) a
inMaybeT = arrM $ MaybeT . return
untilMaybe :: Monad m => MSF m a b -> MSF m b Bool -> MSF (MaybeT m) a b
untilMaybe msf cond = proc a -> do
  b <- liftMSFTrans msf  -< a
  c <- liftMSFTrans cond -< b
  inMaybeT -< if c then Nothing else Just b
catchMaybe
  :: (Functor m, Monad m)
  => MSF (MaybeT m) a b -> MSF m a b -> MSF m a b
catchMaybe msf1 msf2 = safely $ do
  _ <- try $ maybeToExceptS msf1
  safe msf2
listToMaybeS :: Monad m => [b] -> MSF (MaybeT m) a b
listToMaybeS = foldr iPost exit
runMaybeS :: Monad m => MSF (MaybeT m) a b -> MSF m a (Maybe b)
runMaybeS msf = go
  where
    go = MSF $ \a -> do
           bmsf <- runMaybeT $ unMSF msf a
           case bmsf of
             Just (b, msf') -> return (Just b, runMaybeS msf')
             Nothing        -> return (Nothing, go)
runMaybeS'' :: Monad m => MSF (MaybeT m) a b -> MSF m a (Maybe b)
runMaybeS'' = transG transformInput transformOutput
  where
    transformInput       = return
    transformOutput _ m1 = do r <- runMaybeT m1
                              case r of
                                Nothing     -> return (Nothing, Nothing)
                                Just (b, c) -> return (Just b,  Just c)
reactimateMaybe
  :: (Functor m, Monad m)
  => MSF (MaybeT m) () () -> m ()
reactimateMaybe msf = reactimateExcept $ try $ maybeToExceptS msf
embed_ :: (Functor m, Monad m) => MSF m a () -> [a] -> m ()
embed_ msf as = reactimateMaybe $ listToMaybeS as >>> liftMSFTrans msf