module System.Taffybar.Widget.Text.MemoryMonitor (textMemoryMonitorNew, showMemoryInfo) where

import Control.Monad.IO.Class ( MonadIO )
import qualified Data.Text as T
import qualified Text.StringTemplate as ST
import System.Taffybar.Information.Memory
import System.Taffybar.Widget.Generic.PollingLabel ( pollingLabelNew )
import qualified GI.Gtk
import Text.Printf ( printf )

-- | Creates a simple textual memory monitor. It updates once every polling
-- period (in seconds).
textMemoryMonitorNew :: MonadIO m
                     => String -- ^ Format. You can use variables: "used", "total", "free", "buffer",
                               -- "cache", "rest", "available", "swapUsed", "swapTotal", "swapFree".
                     -> Double -- ^ Polling period in seconds.
                     -> m GI.Gtk.Widget
textMemoryMonitorNew :: forall (m :: * -> *). MonadIO m => String -> Double -> m Widget
textMemoryMonitorNew String
fmt Double
period = do
    Widget
label <- Double -> IO Text -> m Widget
forall (m :: * -> *). MonadIO m => Double -> IO Text -> m Widget
pollingLabelNew Double
period (String -> Int -> MemoryInfo -> Text
showMemoryInfo String
fmt Int
3 (MemoryInfo -> Text) -> IO MemoryInfo -> IO Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO MemoryInfo
parseMeminfo)
    Widget -> m Widget
forall (m :: * -> *) o. (MonadIO m, IsWidget o) => o -> m Widget
GI.Gtk.toWidget Widget
label

showMemoryInfo :: String -> Int -> MemoryInfo -> T.Text
showMemoryInfo :: String -> Int -> MemoryInfo -> Text
showMemoryInfo String
fmt Int
prec MemoryInfo
info =
  let template :: StringTemplate Text
template = String -> StringTemplate Text
forall a. Stringable a => String -> StringTemplate a
ST.newSTMP String
fmt
      labels :: [String]
labels = [ String
"used"
               , String
"total"
               , String
"free"
               , String
"buffer"
               , String
"cache"
               , String
"rest"
               , String
"available"
               , String
"swapUsed"
               , String
"swapTotal"
               , String
"swapFree"
               ]
      actions :: [MemoryInfo -> Double]
actions = [ MemoryInfo -> Double
memoryUsed
                , MemoryInfo -> Double
memoryTotal
                , MemoryInfo -> Double
memoryFree
                , MemoryInfo -> Double
memoryBuffer
                , MemoryInfo -> Double
memoryCache
                , MemoryInfo -> Double
memoryRest
                , MemoryInfo -> Double
memoryAvailable
                , MemoryInfo -> Double
memorySwapUsed
                , MemoryInfo -> Double
memorySwapTotal
                , MemoryInfo -> Double
memorySwapFree
                ]
      actions' :: [MemoryInfo -> String]
actions' = ((MemoryInfo -> Double) -> MemoryInfo -> String)
-> [MemoryInfo -> Double] -> [MemoryInfo -> String]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Double -> String
toAuto Int
prec (Double -> String)
-> (MemoryInfo -> Double) -> MemoryInfo -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) [MemoryInfo -> Double]
actions
      stats :: [String]
stats = [MemoryInfo -> String
f MemoryInfo
info | MemoryInfo -> String
f <- [MemoryInfo -> String]
actions']
      template' :: StringTemplate Text
template' = [(String, String)] -> StringTemplate Text -> StringTemplate Text
forall a b.
(ToSElem a, Stringable b) =>
[(String, a)] -> StringTemplate b -> StringTemplate b
ST.setManyAttrib ([String] -> [String] -> [(String, String)]
forall a b. [a] -> [b] -> [(a, b)]
zip [String]
labels [String]
stats) StringTemplate Text
template
  in StringTemplate Text -> Text
forall a. Stringable a => StringTemplate a -> a
ST.render StringTemplate Text
template'

toAuto :: Int -> Double -> String
toAuto :: Int -> Double -> String
toAuto Int
prec Double
value = String -> Int -> Double -> String -> String
forall r. PrintfType r => String -> r
printf String
"%.*f%s" Int
p Double
v String
unit
  where value' :: Double
value' = Double -> Double -> Double
forall a. Ord a => a -> a -> a
max Double
0 Double
value
        mag :: Int
        mag :: Int
mag = if Double
value' Double -> Double -> Bool
forall a. Eq a => a -> a -> Bool
== Double
0 then Int
0 else Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
0 (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
2 (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ Double -> Int
forall b. Integral b => Double -> b
forall a b. (RealFrac a, Integral b) => a -> b
floor (Double -> Int) -> Double -> Int
forall a b. (a -> b) -> a -> b
$ Double -> Double -> Double
forall a. Floating a => a -> a -> a
logBase Double
1024 Double
value'
        v :: Double
v = Double
value' Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
1024 Double -> Double -> Double
forall a. Floating a => a -> a -> a
** Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
mag
        unit :: String
unit = case Int
mag of
          Int
0 -> String
"MiB"
          Int
1 -> String
"GiB"
          Int
2 -> String
"TiB"
          Int
_ -> String
"??B" -- unreachable
        p :: Int
        p :: Int
p = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
0 (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ Double -> Int
forall b. Integral b => Double -> b
forall a b. (RealFrac a, Integral b) => a -> b
floor (Double -> Int) -> Double -> Int
forall a b. (a -> b) -> a -> b
$ Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
prec Double -> Double -> Double
forall a. Num a => a -> a -> a
- Double -> Double -> Double
forall a. Floating a => a -> a -> a
logBase Double
10 Double
v