{-# LANGUAGE DeriveDataTypeable, RecordWildCards, TemplateHaskell, TypeFamilies #-}
module Clckwrks.Media.Acid where

import Control.Monad.Reader   (ask)
import Control.Monad.State    (get, put)
import Data.Acid              (Query, Update, makeAcidic)
import Data.Data              (Data, Typeable)
import Data.IxSet             (IxSet, (@=), getOne, empty, toList, updateIx)
import Data.SafeCopy          (base, deriveSafeCopy)
import Clckwrks.Media.Types   (Medium(..), MediumId(..))

data MediaState = MediaState 
    { nextMediumId :: MediumId
    , media        :: IxSet Medium
    } deriving (Data, Typeable)
$(deriveSafeCopy 0 'base ''MediaState)

initialMediaState :: MediaState
initialMediaState = MediaState
    { nextMediumId = MediumId 0
    , media        = empty
    }

-- | get the next unused 'MediaId'
genMediumId :: Update MediaState MediumId
genMediumId =
    do ms@MediaState{..} <- get
       put $ ms { nextMediumId = MediumId $ succ $ unMediumId $ nextMediumId }
       return nextMediumId

-- | get 'Media' by 'MediumId'
getMediumById :: MediumId -> Query MediaState (Maybe Medium)
getMediumById mid =
    do MediaState{..} <- ask
       return $ getOne (media @= mid)

-- | store 'Media' in the state. Will overwrite an existing entry with the same 'MediumId'
putMedium :: Medium -> Update MediaState ()
putMedium m =
    do ms@MediaState{..} <- get
       put $ ms { media = updateIx (mediumId m) m media }

allMediumIds :: Query MediaState [MediumId]
allMediumIds =
    do MediaState{..} <- ask
       return $ map mediumId (toList media)

$(makeAcidic ''MediaState 
   [ 'genMediumId
   , 'getMediumById
   , 'putMedium
   , 'allMediumIds
   ]
 )