module Data.TimeSet where

import Data.TimeMap (TimeMap, newTimeMap)
import qualified Data.TimeMap as TimeMap
import Data.Hashable (Hashable (..))
import Data.Time (UTCTime, NominalDiffTime, addUTCTime, diffUTCTime, getCurrentTime)
import qualified Data.HashSet             as HS
import Control.Concurrent.STM (STM)


newtype TimeSet a = TimeSet {getTimeSet :: TimeMap a ()}


newTimeSet :: STM (TimeSet a)
newTimeSet = TimeSet <$> newTimeMap


insert :: (Hashable a, Eq a) => a -> TimeSet a -> IO ()
insert a (TimeSet xs) = TimeMap.insert a () xs


insertWithTime :: (Hashable a, Eq a) => UTCTime -> a -> TimeSet a -> STM ()
insertWithTime t a (TimeSet xs) = TimeMap.insertWithTime t a () xs


elem :: (Hashable a, Eq a) => a -> TimeSet a -> STM Bool
elem a (TimeSet xs) = do
  r <- TimeMap.lookup a xs
  case r of
    Nothing -> pure False
    Just () -> pure True


elems :: (Hashable a, Eq a) => TimeSet a -> STM (HS.HashSet a)
elems (TimeSet xs) = TimeMap.keys xs


size :: TimeSet a -> STM Int
size (TimeSet xs) = TimeMap.size xs


null :: TimeSet a -> STM Bool
null (TimeSet xs) = TimeMap.null xs


timeOf :: (Hashable a, Eq a) => a -> TimeSet a -> STM (Maybe UTCTime)
timeOf a (TimeSet xs) = TimeMap.timeOf a xs


ageOf :: (Hashable a, Eq a) => a -> TimeSet a -> IO (Maybe NominalDiffTime)
ageOf a (TimeSet xs) = TimeMap.ageOf a xs


delete :: (Hashable a, Eq a) => a -> TimeSet a -> STM ()
delete a (TimeSet xs) = TimeMap.delete a xs


touch :: (Hashable a, Eq a) => a -> TimeSet a -> IO ()
touch a (TimeSet xs) = TimeMap.touch a xs


filter :: (Hashable a, Eq a) => (a -> Bool) -> TimeSet a -> STM ()
filter f (TimeSet xs) = TimeMap.filterWithKey (\k _ -> f k) xs


filterSince :: (Hashable a, Eq a) => UTCTime -> TimeSet a -> STM ()
filterSince t (TimeSet xs) = TimeMap.filterSince t xs


filterFromNow :: (Hashable a, Eq a) => NominalDiffTime -> TimeSet a -> IO ()
filterFromNow t (TimeSet xs) = TimeMap.filterFromNow t xs