packages feed

doc-review-0.7: src/State/Mem.hs

module State.Mem
    ( new
    )
where

import State.Types

import Data.Maybe ( listToMaybe, fromMaybe )
import Data.Function ( on )
import Data.List ( sortBy )
import Control.Monad ( mplus )
import qualified Data.Sequence as S
import qualified Data.Set as Set
import qualified Data.Map as Map
import Data.Foldable ( toList )
import Control.Concurrent.MVar ( newMVar, withMVar, modifyMVar_ )
import Control.Arrow ( second, (***) )
import Network.URI ( URI )

--------------------------------------------------
-- Stateful

new :: IO State
new = do
  v <- newMVar emptyMemState
  return $ State
             { findComments = \cId        ->
                              withMVar v $
                              return . maybe [] toList . Map.lookup cId . cms

             , getCounts    = \chId       ->
                              withMVar v $ return . getCounts' chId

             , addComment   = \cId chId c ->
                              modifyMVar_ v $ return . addComment' cId chId c

             , addChapter   = \chId cIds mURI ->
                              modifyMVar_ v $ return . addChapter' chId cIds mURI

             , getLastInfo  = \sid ->
                              withMVar v $ return . getInfo' sid

             , getChapterComments =
               \chId -> withMVar v $ return . getChapterComments' chId

             , getChapterURI = \chId -> withMVar v $ return . chapterURI chId
             }

--------------------------------------------------
-- Pure

data MemState = MemState { chs :: Map.Map ChapterId (Maybe URI, Set.Set CommentId)
                         , cms :: Map.Map CommentId (S.Seq Comment)
                         }

chapterComments :: ChapterId -> MemState -> Set.Set CommentId
chapterComments chId = maybe Set.empty snd . Map.lookup chId . chs

chapterURI :: ChapterId -> MemState -> Maybe URI
chapterURI chId st = fst =<< Map.lookup chId (chs st)

withChapterComments :: (Set.Set CommentId -> Set.Set CommentId)
                    -> ChapterId -> MemState -> MemState
withChapterComments = withChapter . second

withChapter :: ((Maybe URI, Set.Set CommentId) -> (Maybe URI, Set.Set CommentId))
            -> ChapterId -> MemState -> MemState
withChapter f chId st =
    let upd x = case f $ fromMaybe (Nothing, Set.empty) x of
                  (Nothing, s) | Set.null s -> Nothing
                  p                         -> Just p
    in st { chs = Map.alter upd chId $ chs st }

emptyMemState :: MemState
emptyMemState = MemState Map.empty Map.empty

getInfo' :: SessionId -> MemState -> Maybe SessionInfo
getInfo' sId =
    fmap toInfo .
    listToMaybe .
    take 1 .
    reverse .
    sortBy (compare `on` cDate) .
    filter ((== sId) . cSession) .
    concatMap toList .
    Map.elems .
    cms
    where
      toInfo c = SessionInfo (cName c) (cEmail c)

getCounts' :: Maybe ChapterId -> MemState -> [(CommentId, Int)]
getCounts' mChId st =
    map (second S.length) $ Map.toList $
    case mChId of
      Nothing   -> cms st
      Just chId ->
          let cIds = chapterComments chId st
              p k _ =  k `Set.member` cIds
          in Map.filterWithKey p (cms st)

addChapter' :: ChapterId -> [CommentId] -> Maybe URI -> MemState -> MemState
addChapter' chId cIds mURI =
    withChapter ((mURI `mplus`) *** (Set.union $ Set.fromList cIds)) chId

addComment' :: CommentId -> Maybe ChapterId -> Comment -> MemState -> MemState
addComment' cId mChId c st =
    maybe id (withChapterComments (Set.insert cId)) mChId $
    st { cms = Map.alter (addSeq c) cId $ cms st }
    where
      addSeq x = return . (S.|> x) . maybe S.empty id

getChapterComments' :: ChapterId -> MemState -> [(CommentId, Comment)]
getChapterComments' chId st =
    let sortDateDesc       = sortBy $ flip (compare `on` (cDate . snd))
        lookupComments cId = maybe [] (map ((,) cId) . toList) $
                             Map.lookup cId $ cms st
    in sortDateDesc $ concatMap lookupComments $
       toList $ chapterComments chId st