1 -- | The whole point of this module is
 
   2 -- to reach sub-linear time complexity
 
   3 -- when filtering with 'Filter_Bool'
 
   4 -- over sorted inputs, doing this by:
 
   6 -- 1. Deriving from a generic 'Filter_Bool':
 
   7 --    a specific 'Filter_Bool' only testing
 
   8 --    on the input's sorting key, such that
 
   9 --    it forms a necessary (obviously not sufficient) filter
 
  10 --    to pass for an input's sorting key to let it filter-in (eg. 'bool_date').
 
  11 -- 2. Deriving from this specific 'Filter_Bool':
 
  12 --    a 'Sieve' uniquely uniting 'Interval's
 
  13 --    spanning over sorting keys of inputs
 
  14 --    which can filter-in (eg. 'sieve_date').
 
  15 -- 3. Slicing the input according to this 'Sieve':
 
  16 --    to filter-out inputs which cannot possibly filter-in
 
  19 -- In the end, this module potentially gives less time complexity, but:
 
  21 -- * this is only sensible on large inputs;
 
  22 -- * this significantly increases the code complexity
 
  23 --   of the filtering algorithm, hence its reliability.
 
  24 module Hcompta.Filter.Reduce where
 
  26 import           Control.Arrow ((***))
 
  27 import           Control.Monad (join)
 
  29 import           Data.Either (Either(..))
 
  30 import           Data.Functor (Functor(..), (<$>))
 
  31 import           Data.Maybe (Maybe(..), fromJust, fromMaybe)
 
  32 import qualified Data.List
 
  33 import           Data.Map.Strict (Map)
 
  34 import           Prelude (($), (.), uncurry)
 
  36 import           Hcompta.Date (Date)
 
  37 import qualified Hcompta.Date as Date
 
  38 import qualified Hcompta.Date.Interval as Date.Interval
 
  40 import qualified Hcompta.Lib.Interval as Interval
 
  41 import qualified Hcompta.Lib.Interval.Sieve as Interval.Sieve
 
  42 import qualified Hcompta.Lib.Map.Strict as Map
 
  46 type Reduce_Date = Filter_Bool Filter_Date
 
  49         dated :: t -> Maybe (Filter_Bool Filter_Date)
 
  51 instance Dated Filter_Date where
 
  53 instance Transaction t
 
  54  => Dated (Filter_Transaction t) where
 
  57                  Filter_Transaction_Date d -> Just d
 
  60 -- | Return a 'Reduce_Date'
 
  62 --   for the given 'Filter_Bool' to filter.
 
  63 bool_date :: Dated t => Filter_Bool t -> Simplified Reduce_Date
 
  65         simplify (fromMaybe Any $ go tst)
 
  74                          (Not t)     -> Not <$> go t
 
  76                                 case (go t0, go t1) of
 
  77                                  (Nothing, Nothing)   -> Just $ Any
 
  78                                  (Nothing, Just td)   -> Just $ td
 
  79                                  (Just td, Nothing)   -> Just $ td
 
  80                                  (Just td0, Just td1) -> Just $ And td0 td1
 
  82                                 case (go t0, go t1) of
 
  83                                  (Just td0, Just td1) -> Just $ Or td0 td1
 
  86 -- | Return given 'Interval.Sieve.Sieve' 'Date'
 
  87 --   with given 'Reduce_Date' applied on it.
 
  89 -- WARNING: no reducing is done below the day level.
 
  92  -> Interval.Sieve.Sieve Date
 
  93  -> Interval.Sieve.Sieve Date
 
  95         case Interval.Sieve.interval si of
 
  97          Just bounds -> go bounds tb si
 
 103                                 Interval.Sieve.complement_with bounds $
 
 106                                 Interval.Sieve.intersection
 
 115                                  Filter_Date_UTC to ->
 
 116                                         Interval.Sieve.intersection s $
 
 117                                         Interval.Sieve.singleton $
 
 119                                          Filter_Ord Lt o -> fromJust $ Interval.interval (Interval.low bounds) (Interval.Limit Interval.Out o)
 
 120                                          Filter_Ord Le o -> fromJust $ Interval.interval (Interval.low bounds) (Interval.Limit Interval.In  o)
 
 121                                          Filter_Ord Eq o -> Interval.point o
 
 122                                          Filter_Ord Ge o -> fromJust $ Interval.interval (Interval.Limit Interval.In  o) (Interval.high bounds)
 
 123                                          Filter_Ord Gt o -> fromJust $ Interval.interval (Interval.Limit Interval.Out o) (Interval.high bounds)
 
 124                                          Filter_Ord_Any  -> bounds
 
 125                                  Filter_Date_Year (Filter_Interval_In i) ->
 
 126                                         Interval.Sieve.intersection s $
 
 127                                         Interval.Sieve.singleton $
 
 128                                         fromJust $ uncurry Interval.interval $
 
 131                                                  Interval.Unlimited_low  -> Interval.low bounds
 
 132                                                  Interval.Limited l      -> l
 
 133                                                  Interval.Unlimited_high -> Interval.high bounds) $
 
 134                                         (fmap Interval.low *** fmap Interval.high) $
 
 135                                         join (***) (fmap Date.Interval.year . Interval.limit) $
 
 137                                  Filter_Date_Month (Filter_Interval_In i) ->
 
 138                                         case Interval.Sieve.interval s of
 
 141                                                 Interval.Sieve.intersection s $
 
 142                                                 Interval.Sieve.from_Foldable $
 
 152                                                  Date.Interval.month_slice
 
 154                                  Filter_Date_DoM (Filter_Interval_In i) ->
 
 155                                         case Interval.Sieve.interval s of
 
 158                                                 Interval.Sieve.intersection s $
 
 159                                                 Interval.Sieve.from_Foldable $
 
 169                                                  Date.Interval.dom_slice
 
 171                                  Filter_Date_Hour   _ti -> s -- NOTE: no reducing at this level
 
 172                                  Filter_Date_Minute _ti -> s -- NOTE: no reducing at this level
 
 173                                  Filter_Date_Second _ti -> s -- NOTE: no reducing at this level
 
 175 -- | Return given 'Map' with 'Map.slice' applied on it
 
 176 --   to only get sub-'Map's filtering through given 'Reduce_Date',
 
 177 --   also return derived 'Interval.Sieve.Sieve' used for the slicing.
 
 178 map_date :: Simplified Reduce_Date -> Map Date x -> ([Map Date x], Interval.Sieve.Sieve Date)
 
 181                 case Map.interval m of
 
 182                  Nothing -> Interval.Sieve.empty
 
 184                         case simplified reducer of
 
 185                          Left tb     -> sieve_date tb $ Interval.Sieve.singleton bounds
 
 186                          Right True  -> Interval.Sieve.singleton bounds
 
 187                          Right False -> Interval.Sieve.empty in
 
 188         (Map.slice sieve m, sieve)