module Charon.Runner.FileSizeMode
  ( FileSizeMode (..),
    defaultSizeMode,
    parseFileSizeMode,
  )
where

import Charon.Prelude
import Data.Bytes (Size (M), SomeSize)
import Data.Bytes qualified as Bytes
import Data.Char qualified as Ch
import Data.Text qualified as T
import GHC.Real (truncate)

-- | Determines what to do if the log file surpasses the given size
-- threshold.
data FileSizeMode
  = -- | Print a warning.
    FileSizeModeWarn (Bytes B Natural)
  | -- | Delete the file.
    FileSizeModeDelete (Bytes B Natural)
  deriving stock (FileSizeMode -> FileSizeMode -> Bool
(FileSizeMode -> FileSizeMode -> Bool)
-> (FileSizeMode -> FileSizeMode -> Bool) -> Eq FileSizeMode
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: FileSizeMode -> FileSizeMode -> Bool
== :: FileSizeMode -> FileSizeMode -> Bool
$c/= :: FileSizeMode -> FileSizeMode -> Bool
/= :: FileSizeMode -> FileSizeMode -> Bool
Eq, Int -> FileSizeMode -> ShowS
[FileSizeMode] -> ShowS
FileSizeMode -> String
(Int -> FileSizeMode -> ShowS)
-> (FileSizeMode -> String)
-> ([FileSizeMode] -> ShowS)
-> Show FileSizeMode
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FileSizeMode -> ShowS
showsPrec :: Int -> FileSizeMode -> ShowS
$cshow :: FileSizeMode -> String
show :: FileSizeMode -> String
$cshowList :: [FileSizeMode] -> ShowS
showList :: [FileSizeMode] -> ShowS
Show)

defaultSizeMode :: FileSizeMode
defaultSizeMode :: FileSizeMode
defaultSizeMode = Bytes 'B Natural -> FileSizeMode
FileSizeModeDelete (Bytes 'B Natural -> FileSizeMode)
-> Bytes 'B Natural -> FileSizeMode
forall a b. (a -> b) -> a -> b
$ Proxy 'B -> Bytes 'M Natural -> Converted 'B (Bytes 'M Natural)
forall a (t :: Size).
(Conversion a, SingSize t) =>
Proxy t -> a -> Converted t a
forall (t :: Size).
SingSize t =>
Proxy t -> Bytes 'M Natural -> Converted t (Bytes 'M Natural)
Bytes.convert Proxy 'B
forall {k} (t :: k). Proxy t
Proxy Bytes 'M Natural
fiftyMb
  where
    fiftyMb :: Bytes 'M Natural
fiftyMb = forall (s :: Size) n. n -> Bytes s n
MkBytes @M Natural
50

parseFileSizeMode :: (MonadFail m) => Text -> m FileSizeMode
parseFileSizeMode :: forall (m :: * -> *). MonadFail m => Text -> m FileSizeMode
parseFileSizeMode Text
txt = do
  let (Text
m, Text
byteTxt) = (Char -> Bool) -> Text -> (Text, Text)
T.break Char -> Bool
Ch.isSpace Text
txt
  Bytes 'B Natural -> FileSizeMode
cons <- case Text
m of
    Text
"warn" -> (Bytes 'B Natural -> FileSizeMode)
-> m (Bytes 'B Natural -> FileSizeMode)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bytes 'B Natural -> FileSizeMode
FileSizeModeWarn
    Text
"delete" -> (Bytes 'B Natural -> FileSizeMode)
-> m (Bytes 'B Natural -> FileSizeMode)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bytes 'B Natural -> FileSizeMode
FileSizeModeDelete
    Text
bad -> String -> m (Bytes 'B Natural -> FileSizeMode)
forall a. String -> m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> m (Bytes 'B Natural -> FileSizeMode))
-> String -> m (Bytes 'B Natural -> FileSizeMode)
forall a b. (a -> b) -> a -> b
$ String
"Unrecognized size-mode: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Text -> String
T.unpack Text
bad
  case Text -> Either Text (Bytes 'B Natural)
parseByteText Text
byteTxt of
    Right Bytes 'B Natural
b -> FileSizeMode -> m FileSizeMode
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (FileSizeMode -> m FileSizeMode) -> FileSizeMode -> m FileSizeMode
forall a b. (a -> b) -> a -> b
$ Bytes 'B Natural -> FileSizeMode
cons Bytes 'B Natural
b
    Left Text
err -> String -> m FileSizeMode
forall a. String -> m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> m FileSizeMode) -> String -> m FileSizeMode
forall a b. (a -> b) -> a -> b
$ String
"Could not parse size-mode size: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Text -> String
T.unpack Text
err

parseByteText :: Text -> Either Text (Bytes B Natural)
parseByteText :: Text -> Either Text (Bytes 'B Natural)
parseByteText Text
txt =
  case forall a. Parser a => Text -> Either Text a
Bytes.parse @(SomeSize Natural) Text
txt of
    Right SomeSize Natural
b -> Bytes 'B Natural -> Either Text (Bytes 'B Natural)
forall a b. b -> Either a b
Right (Bytes 'B Natural -> Either Text (Bytes 'B Natural))
-> Bytes 'B Natural -> Either Text (Bytes 'B Natural)
forall a b. (a -> b) -> a -> b
$ Proxy 'B -> SomeSize Natural -> Converted 'B (SomeSize Natural)
forall a (t :: Size).
(Conversion a, SingSize t) =>
Proxy t -> a -> Converted t a
forall (t :: Size).
SingSize t =>
Proxy t -> SomeSize Natural -> Converted t (SomeSize Natural)
Bytes.convert (forall {k} (t :: k). Proxy t
forall (t :: Size). Proxy t
Proxy @B) SomeSize Natural
b
    Left Text
_ -> case forall a. Parser a => Text -> Either Text a
Bytes.parse @(SomeSize Double) Text
txt of
      Right SomeSize Double
b -> Bytes 'B Natural -> Either Text (Bytes 'B Natural)
forall a b. b -> Either a b
Right (Double -> Natural
forall b. Integral b => Double -> b
forall a b. (RealFrac a, Integral b) => a -> b
truncate (Double -> Natural) -> Bytes 'B Double -> Bytes 'B Natural
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Proxy 'B -> SomeSize Double -> Converted 'B (SomeSize Double)
forall a (t :: Size).
(Conversion a, SingSize t) =>
Proxy t -> a -> Converted t a
forall (t :: Size).
SingSize t =>
Proxy t -> SomeSize Double -> Converted t (SomeSize Double)
Bytes.convert (forall {k} (t :: k). Proxy t
forall (t :: Size). Proxy t
Proxy @B) SomeSize Double
b)
      Left Text
err -> Text -> Either Text (Bytes 'B Natural)
forall a b. a -> Either a b
Left Text
err