------------------------------------------------------------------------------
-- |
-- Module      : Redact.Internal
-- Description : internal functions
-- Copyright   : Copyright (c) 2020-2023 Travis Cardwell
-- License     : MIT
------------------------------------------------------------------------------

{-# LANGUAGE ScopedTypeVariables #-}

module Redact.Internal
  ( -- * Internal
    redact
  , redact'
  ) where

-- https://hackage.haskell.org/package/text
import qualified Data.Text as T
import Data.Text (Text)

-- (redact)
import Redact.Types (Line)

------------------------------------------------------------------------------
-- $Internal

-- | Redact text strictly
redact
  :: forall s
   . (s -> Text -> Either String (Line, s))  -- ^ step function
  -> (s -> Maybe String)                     -- ^ end function
  -> s                                       -- ^ initial state
  -> Text
  -> Either String [Line]
redact :: forall s.
(s -> Text -> Either String (Line, s))
-> (s -> Maybe String) -> s -> Text -> Either String [Line]
redact s -> Text -> Either String (Line, s)
step s -> Maybe String
end s
initialState = s -> [Line] -> [Text] -> Either String [Line]
go s
initialState [] forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Text]
T.lines
  where
    go :: s -> [Line] -> [Text] -> Either String [Line]
    go :: s -> [Line] -> [Text] -> Either String [Line]
go s
state [Line]
acc (Text
t:[Text]
ts) = case s -> Text -> Either String (Line, s)
step s
state Text
t of
      Right (Line
line, s
state') -> s -> [Line] -> [Text] -> Either String [Line]
go s
state' (Line
line forall a. a -> [a] -> [a]
: [Line]
acc) [Text]
ts
      Left String
err -> forall a b. a -> Either a b
Left String
err
    go s
state [Line]
acc [] = case s -> Maybe String
end s
state of
      Maybe String
Nothing -> forall a b. b -> Either a b
Right forall a b. (a -> b) -> a -> b
$ forall a. [a] -> [a]
reverse [Line]
acc
      Just String
err -> forall a b. a -> Either a b
Left String
err

------------------------------------------------------------------------------

-- | Redact text leniently
redact'
  :: forall s
   . (s -> Text -> (Line, s))  -- ^ step function
  -> s                         -- ^ initial state
  -> Text
  -> [Line]
redact' :: forall s. (s -> Text -> (Line, s)) -> s -> Text -> [Line]
redact' s -> Text -> (Line, s)
step s
initialState = s -> [Text] -> [Line]
go s
initialState forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Text]
T.lines
  where
    go :: s -> [Text] -> [Line]
    go :: s -> [Text] -> [Line]
go s
state (Text
t:[Text]
ts) =
      let (Line
line, s
state') = s -> Text -> (Line, s)
step s
state Text
t
      in  Line
line forall a. a -> [a] -> [a]
: s -> [Text] -> [Line]
go s
state' [Text]
ts
    go s
_state [] = []