-- | Atomically modifies the configuration state in the WConfdMonad
-- with a computation that can possibly fail; immediately afterwards,
-- while config write is still going on, do the followup action. Return
-- only after replication is finished.
modifyConfigStateErrWithImmediate
  :: (TempResState -> ConfigState -> AtomicModifyMonad (a, ConfigState))
  -> WConfdMonad ()
  -> WConfdMonad a
modifyConfigStateErrWithImmediate f immediateFollowup = do
  dh <- daemonHandle
  now <- liftIO getClockTime

  let modCS ds@(DaemonState { dsTempRes = tr }) =
        mapMOf2
          dsConfigStateL (\cs -> liftM (unpackConfigResult now cs) (f tr cs)) ds
  (r, modified, distSync) <- atomicModifyIORefErrLog (dhDaemonState dh)
                                                     (liftM swap . modCS)
  if modified
    then if distSync
      then do
        logDebug $ "Triggering config write" ++
                   " together with full synchronous distribution"
        res <- liftBase . triggerWithResult (Any True) $ dhSaveConfigWorker dh
        immediateFollowup
        wait res
        logDebug "Config write and distribution finished"
      else do
        -- trigger the config. saving worker and wait for it
        logDebug $ "Triggering config write" ++
                   " and asynchronous distribution"
        res <- liftBase . triggerWithResult (Any False) $ dhSaveConfigWorker dh
        immediateFollowup
        wait res
        logDebug "Config writer finished with local task"
    else
      immediateFollowup
  return r

-- | Atomically modifies the configuration state in the WConfdMonad
-- with a computation that can possibly fail.
modifyConfigStateErrWithImmediate
  :: (TempResState -> ConfigState -> AtomicModifyMonad (a, ConfigState))
  -> WConfdMonad ()
  -> WConfdMonad a
modifyConfigStateErrWithImmediate f immediateFollowup = do
  dh <- daemonHandle
  now <- liftIO getClockTime

  let modCS ds@(DaemonState { dsTempRes = tr }) =
        mapMOf2
          dsConfigStateL (\cs -> liftM (unpackConfigResult now cs) (f tr cs)) ds
  (r, modified, distSync) <- atomicModifyIORefErrLog (dhDaemonState dh)
                                                     (liftM swap . modCS)
  if modified
    then if distSync
      then do
        logDebug $ "Triggering config write" ++
                   " together with full synchronous distribution"
        res <- liftBase . triggerWithResult (Any True) $ dhSaveConfigWorker dh
        immediateFollowup
        wait res
        logDebug "Config write and distribution finished"
      else do
        -- trigger the config. saving worker and wait for it
        logDebug $ "Triggering config write" ++
                   " and asynchronous distribution"
        res <- liftBase . triggerWithResult (Any False) $ dhSaveConfigWorker dh
        immediateFollowup
        wait res
        logDebug "Config writer finished with local task"
    else
      immediateFollowup
  return r

-- | Atomically modifies the configuration state in the WConfdMonad
-- with a computation that can possibly fail.
modifyConfigStateErrWithImmediate f immediateFollowup = do
  dh <- daemonHandle
  now <- liftIO getClockTime

  let modCS ds@(DaemonState { dsTempRes = tr }) =
        mapMOf2
          dsConfigStateL (\cs -> liftM (unpackConfigResult now cs) (f tr cs)) ds
  (r, modified, distSync) <- atomicModifyIORefErrLog (dhDaemonState dh)
                                                     (liftM swap . modCS)
  if modified
    then if distSync
      then do
        logDebug $ "Triggering config write" ++
                   " together with full synchronous distribution"
        res <- liftBase . triggerWithResult (Any True) $ dhSaveConfigWorker dh
        immediateFollowup
        wait res
        logDebug "Config write and distribution finished"
      else do
        -- trigger the config. saving worker and wait for it
        logDebug $ "Triggering config write" ++
                   " and asynchronous distribution"
        res <- liftBase . triggerWithResult (Any False) $ dhSaveConfigWorker dh
        immediateFollowup
        wait res
        logDebug "Config writer finished with local task"
    else
      immediateFollowup
  return r

-- | Atomically modifies the configuration state in the WConfdMonad
-- with a computation that can possibly fail.