{-# OPTIONS -XTypeFamilies #-}
module Util.GMap where

import Data.Monoid
import Util.HasSize
import Util.SetLike
import qualified Data.IntMap as IM
import qualified Data.IntSet as IS
import qualified Data.Set as Set


data family GMap k :: * -> *
data family GSet k :: *

newtype instance GMap Int v = GMapInt (IM.IntMap v)
    deriving(Monoid,IsEmpty,HasSize,Collection,Unionize,SetLike,MapLike)
newtype instance GSet Int = GSetInt IS.IntSet
    deriving(Monoid,IsEmpty,HasSize,Collection,Unionize,SetLike)

instance Functor (GMap Int) where
    fmap f (GMapInt v) = GMapInt $ fmap f v

type instance Elem (GMap k v) = (k,v)
type instance Key (GMap k v) = k
type instance Value (GMap k v) = v
type instance Elem (GSet k) = k
type instance Key (GSet k) = k

newtype instance GSet Char = GSetChar (EnumSet Char)
    deriving(Monoid,IsEmpty,HasSize,Collection,Unionize,SetLike)
newtype instance GMap Char v = GMapChar (EnumMap Char v)
    deriving(Monoid,IsEmpty,HasSize,Collection,Unionize,SetLike,MapLike)

--newtype instance GSet (a,b) = GSetTup2 (GMap a (GSet b))

gsetToSet :: (Collection (GSet a), Ord a) => GSet a -> Set.Set a
gsetToSet gs = Set.fromDistinctAscList (toList gs)

class GMapSet k where
    toSet :: GMap k v -> GSet k
    toMap :: (k -> v) -> GSet k -> GMap k v

instance GMapSet Int where
    toSet (GMapInt im) = GSetInt (IM.keysSet im)
    toMap f (GSetInt is) = GMapInt $ IM.fromDistinctAscList [ (x,f x) | x <- IS.toAscList is]