{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RecordWildCards  #-}
{-# LANGUAGE TypeFamilies     #-}
module FRP.Rhine.Schedule.Trans where
import Control.Monad.Schedule
import FRP.Rhine
schedule
  :: ( Monad m
     , Clock (ScheduleT (Diff (TimeDomainOf cl1)) m) cl1
     , Clock (ScheduleT (Diff (TimeDomainOf cl1)) m) cl2
     , TimeDomainOf cl1 ~ TimeDomainOf cl2
     , Ord (Diff (TimeDomainOf cl1))
     , Num (Diff (TimeDomainOf cl1))
     )
  => Schedule (ScheduleT (Diff (TimeDomainOf cl1)) m) cl1 cl2
schedule = Schedule {..}
  where
    startSchedule cl1 cl2 = do
      (runningClock1, initTime) <- startClock cl1
      (runningClock2, _)        <- startClock cl2
      return
        ( runningSchedule cl1 cl2 runningClock1 runningClock2
        , initTime
        )
    
    runningSchedule
      :: ( Monad m
         , Clock (ScheduleT (Diff (TimeDomainOf cl1)) m) cl1
         , Clock (ScheduleT (Diff (TimeDomainOf cl2)) m) cl2
         , TimeDomainOf cl1 ~ TimeDomainOf cl2
         , Ord (Diff (TimeDomainOf cl1))
         , Num (Diff (TimeDomainOf cl1))
         )
      => cl1 -> cl2
      -> MSF (ScheduleT (Diff (TimeDomainOf cl1)) m) () (TimeDomainOf cl1, Tag cl1)
      -> MSF (ScheduleT (Diff (TimeDomainOf cl1)) m) () (TimeDomainOf cl2, Tag cl2)
      -> MSF (ScheduleT (Diff (TimeDomainOf cl1)) m) () (TimeDomainOf cl1, Either (Tag cl1) (Tag cl2))
    runningSchedule cl1 cl2 rc1 rc2 = MSF $ \_ -> do
      
      raceResult <- race (unMSF rc1 ()) (unMSF rc2 ())
      case raceResult of
        
        Left  (((td, tag1), rc1'), cont2) -> return
          
          ( (td, Left tag1)
          
          , runningSchedule cl1 cl2 rc1' (MSF $ const cont2)
          )
        
        Right (cont1, ((td, tag2), rc2')) -> return
          
          ( (td, Right tag2)
          
          , runningSchedule cl1 cl2 (MSF $ const cont1) rc2'
          )