content: -- ----------------------------------------------------------------------------
  
  {- |
    Module     : Holumbus.Distribution.DValue
    Copyright  : Copyright (C) 2010 Stefan Schmidt
    License    : MIT
  
    Maintainer : Stefan Schmidt (stefanschmidt@web.de)
    Stability  : experimental
    Portability: portable
    Version    : 0.1
  
    This module offers the distrubted value datatype.
    
    A DValue is like a distributed MVar, but is can only be
    set once on the local node. If the value is set, it cannot be
    changed any more.
  
    I don't know if this is useful at all, so the implementation is not
    quite finished an some things could be improved.
  -}
  
  -- ----------------------------------------------------------------------------
  
  module Holumbus.Distribution.DValue
  (
    -- * datatypes
      DValue
      
    -- * creating and closing a DValue
    , newDValue
    , newRemoteDValue
    , closeDValue
  
    -- * access a DValue
    , getDValue
    -- , flushDValue
  )
  where
  
  import           Control.Concurrent.MVar
  
  import           Data.Binary
  
  import           Holumbus.Distribution.DMVar
  
  
  -- localLogger :: String
  --localLogger = "Holumbus.Distribution.DValue"
  
  
  data DValue a
    = DValueLocal (DMVar a)
    | DValueRemote (DMVar a) (MVar a)
  
  
  -- | Creates new DValue on the local DNode. The first parameter
  --   is the name of the value which could be used in other processes to
  --   access this stream. If you leave it empty, a random Id will be created.
  newDValue :: (Binary a) => String -> a -> IO (DValue a)
  newDValue s a
    = do
      dv <- newDMVar s a
      return (DValueLocal dv)
      
  
  -- | Creates a new DValue.
  --   The first parameter is the name of the resource and the second one
  --   the name of the node.
  newRemoteDValue :: String -> String -> IO (DValue a)
  newRemoteDValue r n
    = do
      dv <- newRemoteDMVar r n
      lv <- newEmptyMVar
      return (DValueRemote dv lv)
  
  
  -- | Closes a DValue.
  closeDValue :: (DValue a) -> IO ()
  closeDValue (DValueLocal dv)
    = do
      closeDMVar dv
  closeDValue (DValueRemote dv _)
    = do
      closeDMVar dv
  
  
  -- | Gets value. It will only access the network on the first
  --   time and my throw an exception. It returns always (Just a)
  --    but this may change in the future, so the type sticks to (Maybe a)
  getDValue :: (Binary a) => DValue a -> IO (Maybe a)
  getDValue (DValueLocal dv)
    = do
      a <- readDMVar dv
      return (Just a)
  getDValue (DValueRemote dv lv)
    = do
      e <- isEmptyMVar lv
      if e
        then do
          --TODO exception handling here...
          a <- readDMVar dv
          putMVar lv a
          return (Just a)
        else do
          a <- readMVar lv
          return (Just a)
  
  
  {-
  flushDValue :: DValue a -> IO ()
  flushDValue (DValueLocal _) = return ()
  flushDValue (DValueRemote _ lv)
    = do
      e <- isEmptyMVar lv
      if e
        then return ()
        else do
          _ <- takeMVar lv
          return ()
  -}
  
  