{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}

module Data.DeltaMap
    ( DeltaMap(..)
    ) where

import Prelude

import Data.Delta
    ( Delta (..) )
import Data.Map.Strict
    ( Map )
import Fmt
    ( Buildable (..) )


import qualified Data.Map.Strict as Map

{-------------------------------------------------------------------------------
    A Delta type for Maps,
    useful for handling multiple wallets.
-------------------------------------------------------------------------------}
-- | Delta type for 'Map'.
data DeltaMap key da
    = Insert key (Base da)
    | Delete key
    | Adjust key da

deriving instance (Show key, Show da, Show (Base da)) => Show (DeltaMap key da)
instance (Ord key, Delta da)
    => Delta (DeltaMap key da) where
    type Base (DeltaMap key da) = Map key (Base da)
    apply :: DeltaMap key da -> Base (DeltaMap key da) -> Base (DeltaMap key da)
apply (Insert key
key Base da
a) = key -> Base da -> Map key (Base da) -> Map key (Base da)
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert key
key Base da
a
    apply (Delete key
key) = key -> Map key (Base da) -> Map key (Base da)
forall k a. Ord k => k -> Map k a -> Map k a
Map.delete key
key
    apply (Adjust key
key da
da) = (Base da -> Base da)
-> key -> Map key (Base da) -> Map key (Base da)
forall k a. Ord k => (a -> a) -> k -> Map k a -> Map k a
Map.adjust (da -> Base da -> Base da
forall delta. Delta delta => delta -> Base delta -> Base delta
apply da
da) key
key

instance (Show key, Show da, Show (Base da))
    => Buildable (DeltaMap key da) where
    build :: DeltaMap key da -> Builder
build = String -> Builder
forall p. Buildable p => p -> Builder
build (String -> Builder)
-> (DeltaMap key da -> String) -> DeltaMap key da -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DeltaMap key da -> String
forall a. Show a => a -> String
show