-- | A Map mapping multiple values to a key (cross between Map and Set).
--   This is not a complete module.
module Data.Parser.Grempa.Auxiliary.MultiMap
  ( MultiMap
  , lookup
  , insert
  , inserts
  , delete
  , union
  , unions
  , fromList
  , M.empty
  , toList
  ) where

import qualified Data.Map as M
import Data.Map(Map)
import Prelude hiding (lookup)
import Data.Maybe
import qualified Data.Set as S
import Data.Set(Set)

type MultiMap k a = Map k (Set a)

lookup :: Ord k => k -> MultiMap k a -> Set a
lookup k m = fromMaybe S.empty $ M.lookup k m

insert :: (Ord a, Ord k) => k -> a -> MultiMap k a -> MultiMap k a
insert k v m = M.insert k (S.insert v $ lookup k m) m

inserts :: (Ord a, Ord k) => k -> Set a -> MultiMap k a -> MultiMap k a
inserts k v m = M.insertWith S.union k v m

delete :: (Ord a, Ord k) => k -> a -> MultiMap k a -> MultiMap k a
delete k v m = M.update aux k m
  where aux ss = let ss' = S.delete v ss in if S.null ss'
                                               then Nothing
                                               else Just ss'

union :: (Ord a, Ord k) => MultiMap k a -> MultiMap k a -> MultiMap k a
union m1 m2 = foldl (flip $ uncurry inserts) m1 $ M.toList m2

unions :: (Ord a, Ord k) => [MultiMap k a] -> MultiMap k a
unions = foldl union M.empty

fromList :: (Ord a, Ord k) => [(k, a)] -> MultiMap k a
fromList = foldl (flip $ uncurry insert) M.empty

toList :: (Ord a, Ord k) => MultiMap k a -> [(k, Set a)]
toList = M.toList
