content: {-# LANGUAGE StandaloneDeriving #-}
  {-# LANGUAGE TypeFamilies       #-}
  
  module HelloWorldNoTH (main) where
  
  import           Data.Acid
  import           Data.Acid.Advanced
  
  import           Control.Monad
  import           Control.Monad.Reader (ask)
  import           Control.Monad.State  (put)
  import           Data.SafeCopy
  import           System.Environment
  
  ------------------------------------------------------
  -- The Haskell structure that we want to encapsulate
  
  data HelloWorldState = HelloWorldState String
      deriving (Show)
  
  instance SafeCopy HelloWorldState where
      putCopy (HelloWorldState state) = contain $ safePut state
      getCopy = contain $ liftM HelloWorldState safeGet
  
  ------------------------------------------------------
  -- The transaction we will execute over the state.
  
  writeState :: String -> Update HelloWorldState ()
  writeState newValue
      = put (HelloWorldState newValue)
  
  queryState :: Query HelloWorldState String
  queryState = do HelloWorldState string <- ask
                  return string
  
  
  ------------------------------------------------------
  -- This is how AcidState is used:
  
  main :: IO ()
  main = do acid <- openLocalState (HelloWorldState "Hello world")
            args <- getArgs
            if null args
               then do string <- query acid QueryState
                       putStrLn $ "The state is: " ++ string
               else do update acid (WriteState (unwords args))
                       putStrLn "The state has been modified!"
  
  
  ------------------------------------------------------
  -- The gritty details. These things may be done with
  -- Template Haskell in the future.
  
  data WriteState = WriteState String
  data QueryState = QueryState
  
  instance SafeCopy WriteState where
      putCopy (WriteState st) = contain $ safePut st
      getCopy = contain $ liftM WriteState safeGet
  instance Method WriteState where
      type MethodResult WriteState = ()
      type MethodState WriteState = HelloWorldState
  instance UpdateEvent WriteState
  
  instance SafeCopy QueryState where
      putCopy QueryState = contain $ return ()
      getCopy = contain $ return QueryState
  instance Method QueryState where
      type MethodResult QueryState = String
      type MethodState QueryState = HelloWorldState
  instance QueryEvent QueryState
  
  
  instance IsAcidic HelloWorldState where
      acidEvents = [ UpdateEvent (\(WriteState newState) -> writeState newState) safeCopyMethodSerialiser
                   , QueryEvent (\QueryState             -> queryState)          safeCopyMethodSerialiser
                   ]
  