module Indexation.Folds
where

import Indexation.Prelude
import Indexation.Types
import Control.Foldl
import qualified Data.HashMap.Strict as B
import qualified Data.Serialize as C
import qualified Data.ByteString as D


indexTable :: (Eq entity, Hashable entity) => Fold entity (IndexTable entity)
indexTable =
  Fold step init extract
  where
    init = IndexTable 0 B.empty
    step (IndexTable index map) key =
      case B.lookup key map of
        Just _ -> IndexTable index map
        Nothing -> let
          newMap = B.insert key index map
          newIndex = succ index
          in IndexTable newIndex newMap
    extract = id

serializeToFile :: Serialize entity => FilePath -> FoldM IO entity (Either IOException ())
serializeToFile filePath =
  lmap C.encode (writeBytesToFile filePath)

writeBytesToFile :: FilePath -> FoldM IO ByteString (Either IOException ())
writeBytesToFile filePath =
  FoldM step init exit
  where
    step :: Either IOException Handle -> ByteString -> IO (Either IOException Handle)
    step errorOrFileHandle bytes =
      case errorOrFileHandle of
        Right fileHandle -> try (D.hPut fileHandle bytes $> fileHandle)
        Left exception -> return (Left exception)
    init :: IO (Either IOException Handle)
    init =
      try (openFile filePath WriteMode)
    exit :: Either IOException Handle -> IO (Either IOException ())
    exit errorOrFileHandle =
      case errorOrFileHandle of
        Right fileHandle -> try (hClose fileHandle)
        Left exception -> return (Left exception)