-- |  Controlling the LiBro data flow.
module LiBro.Control where

import LiBro.Base
import LiBro.Config
import LiBro.Data
import LiBro.Data.Storage
import Control.Concurrent
import Control.Monad.Reader

-- |  Represents a blocking action because the system is loading
--    or saving data.
data Blocking
  = Reading
  | Writing
  deriving (Blocking -> Blocking -> Bool
(Blocking -> Blocking -> Bool)
-> (Blocking -> Blocking -> Bool) -> Eq Blocking
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Blocking -> Blocking -> Bool
== :: Blocking -> Blocking -> Bool
$c/= :: Blocking -> Blocking -> Bool
/= :: Blocking -> Blocking -> Bool
Eq, Int -> Blocking -> ShowS
[Blocking] -> ShowS
Blocking -> String
(Int -> Blocking -> ShowS)
-> (Blocking -> String) -> ([Blocking] -> ShowS) -> Show Blocking
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Blocking -> ShowS
showsPrec :: Int -> Blocking -> ShowS
$cshow :: Blocking -> String
show :: Blocking -> String
$cshowList :: [Blocking] -> ShowS
showList :: [Blocking] -> ShowS
Show)

-- |  Initially load data and put it into the shared state.
--    Expects the given 'MVar' to be empty.
initData :: MVar Blocking -> MVar LiBroData -> LiBro ()
initData :: MVar Blocking -> MVar LiBroData -> LiBro ()
initData MVar Blocking
blocking MVar LiBroData
libroData = do
  IO () -> LiBro ()
forall a. IO a -> LiBro a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> LiBro ()) -> IO () -> LiBro ()
forall a b. (a -> b) -> a -> b
$ MVar Blocking -> Blocking -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar Blocking
blocking Blocking
Reading
  LiBroData
ld <- LiBro LiBroData
loadData
  ()
_ <- IO () -> LiBro ()
forall a. IO a -> LiBro a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> LiBro ()) -> IO () -> LiBro ()
forall a b. (a -> b) -> a -> b
$ MVar LiBroData -> LiBroData -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar LiBroData
libroData LiBroData
ld
  Blocking
_ <- IO Blocking -> LiBro Blocking
forall a. IO a -> LiBro a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Blocking -> LiBro Blocking) -> IO Blocking -> LiBro Blocking
forall a b. (a -> b) -> a -> b
$ MVar Blocking -> IO Blocking
forall a. MVar a -> IO a
takeMVar MVar Blocking
blocking
  () -> LiBro ()
forall a. a -> LiBro a
forall (m :: * -> *) a. Monad m => a -> m a
return ()

-- |  Try to store shared state data. Expects the given blocking 'MVar'
--    to be empty. Iff not, returns 'False'.
saveData :: MVar Blocking -> MVar LiBroData -> LiBro Bool
saveData :: MVar Blocking -> MVar LiBroData -> LiBro Bool
saveData MVar Blocking
blocking MVar LiBroData
libroData = do
  Bool
isBlocked <- Bool -> Bool
not (Bool -> Bool) -> LiBro Bool -> LiBro Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO Bool -> LiBro Bool
forall a. IO a -> LiBro a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (MVar Blocking -> IO Bool
forall a. MVar a -> IO Bool
isEmptyMVar MVar Blocking
blocking)
  if Bool
isBlocked
    then Bool -> LiBro Bool
forall a. a -> LiBro a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
    else do
      IO () -> LiBro ()
forall a. IO a -> LiBro a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> LiBro ()) -> IO () -> LiBro ()
forall a b. (a -> b) -> a -> b
$ MVar Blocking -> Blocking -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar Blocking
blocking Blocking
Writing
      LiBroData -> LiBro ()
storeData (LiBroData -> LiBro ()) -> LiBro LiBroData -> LiBro ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO LiBroData -> LiBro LiBroData
forall a. IO a -> LiBro a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (MVar LiBroData -> IO LiBroData
forall a. MVar a -> IO a
readMVar MVar LiBroData
libroData)
      Blocking
_ <- IO Blocking -> LiBro Blocking
forall a. IO a -> LiBro a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Blocking -> LiBro Blocking) -> IO Blocking -> LiBro Blocking
forall a b. (a -> b) -> a -> b
$ MVar Blocking -> IO Blocking
forall a. MVar a -> IO a
takeMVar MVar Blocking
blocking
      Bool -> LiBro Bool
forall a. a -> LiBro a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True