{-# LANGUAGE ScopedTypeVariables #-}
{- |
   Module     : Data.IxSet.Typed.Conversions
   License    : MIT
   Stability  : experimental

Conversions from ixset-typed to other containers.
-}
module Data.IxSet.Typed.Conversions (
  toHashMap
, toHashMapBy
, toHashMapByM
, toZipperAsc
, toZipperDesc
) where

import           Control.Comonad.Zipper.Extra
import           Control.Monad
import           Control.Monad.Catch
import           Data.Hashable
import qualified Data.HashMap.Strict          as HM
import           Data.IxSet.Typed             as Ix
import           Data.Proxy

-- | Convert an `IxSet to a `HashMap`.
toHashMap :: (Hashable a, IsIndexOf a xs) => IxSet xs k -> HM.HashMap a [k]
toHashMap = HM.fromList . Ix.groupDescBy

-- | Convert an `IxSet` to a `HashMap` via a function on the index and associated list.
toHashMapBy :: (Hashable a, IsIndexOf a xs) => IxSet xs k -> (a -> [k] -> k') -> HM.HashMap a k'
toHashMapBy xs f = HM.fromList $ flip map (Ix.groupDescBy xs) $ \(a, ks) -> (a, f a ks)

-- | Monadic variant of `toHashMapBy`.
toHashMapByM :: (Monad m, Hashable a, IsIndexOf a xs) => IxSet xs k -> (a -> [k] -> m k') -> m (HM.HashMap a k')
toHashMapByM xs f = fmap HM.fromList $ forM (Ix.groupDescBy xs) $ \(a, ks) -> do
                       z <- f a ks
                       return (a, z)

-- | Convert an `IxSet` to a `Zipper` by descending sort on an index.
toZipperAsc :: forall proxy ix ixs a m. (IsIndexOf ix ixs, MonadThrow m) => proxy ix -> IxSet ixs a -> m (Zipper [] a)
toZipperAsc _ = zipper' . Ix.toAscList (Proxy :: Proxy ix)

-- | Convert an `IxSet` to a `Zipper` by descending sort on an index.
toZipperDesc :: forall proxy ix ixs a m. (IsIndexOf ix ixs, MonadThrow m) => proxy ix -> IxSet ixs a -> m (Zipper [] a)
toZipperDesc _ = zipper' . Ix.toDescList (Proxy :: Proxy ix)