{-- | IxSet-specific backend to filter data from the model. --}
module Cardano.Wallet.API.Response.Filter.IxSet (
      applyFilters
      ) where

import           Cardano.Wallet.API.Indices (Indexable, IsIndexOf, IxSet)
import qualified Cardano.Wallet.API.Request.Filter as F
import           Cardano.Wallet.Kernel.DB.Util.IxSet ((@+), (@<), (@<=), (@=),
                     (@>), (@>=), (@>=<=))

-- | Applies all the input filters to the input 'IxSet''.
applyFilters :: Indexable a => F.FilterOperations ixs a -> IxSet a -> IxSet a
applyFilters F.NoFilters iset        = iset
applyFilters (F.FilterNop  fop) iset = applyFilters fop iset
applyFilters (F.FilterOp f fop) iset = applyFilters fop (applyFilter f iset)

-- | Applies a single 'FilterOperation' on the input 'IxSet'', producing another 'IxSet'' as output.
applyFilter :: forall ix a. (Indexable a , IsIndexOf ix a) => F.FilterOperation ix a -> IxSet a -> IxSet a
applyFilter fltr inputData =
    let byPredicate o i = case o of
            F.Equal            -> inputData @= (i :: ix)
            F.LesserThan       -> inputData @< (i :: ix)
            F.GreaterThan      -> inputData @> (i :: ix)
            F.LesserThanEqual  -> inputData @<= (i :: ix)
            F.GreaterThanEqual -> inputData @>= (i :: ix)
    in case fltr of
           F.FilterByIndex idx          -> byPredicate F.Equal idx
           F.FilterByPredicate ordr idx -> byPredicate ordr idx
           F.FilterByRange from to      -> inputData @>=<= (from, to)
           F.FilterIn ixs               -> inputData @+ ixs
