module TextBuilderDev.Domains.Other where

import TextBuilder
import TextBuilderDev.Domains.Digits
import TextBuilderDev.Prelude hiding (intercalate)

-- | Data size in decimal notation over amount of bytes.
--
-- >>> approximateDataSize 999
-- "999B"
--
-- >>> approximateDataSize 9999
-- "9.9kB"
--
-- >>> approximateDataSize (-9999)
-- "-9.9kB"
--
-- >>> approximateDataSize 1234567890
-- "1.2GB"
--
-- >>> approximateDataSize 10000000000000000000000000000000023
-- "10,000,000,000YB"
{-# INLINEABLE approximateDataSize #-}
approximateDataSize :: (Integral a) => a -> TextBuilder
approximateDataSize :: forall a. Integral a => a -> TextBuilder
approximateDataSize = (a -> TextBuilder) -> a -> TextBuilder
forall a. (Ord a, Num a) => (a -> TextBuilder) -> a -> TextBuilder
signed \a
a ->
  if a
a a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
1000
    then a -> TextBuilder
forall a. Integral a => a -> TextBuilder
decimal a
a TextBuilder -> TextBuilder -> TextBuilder
forall a. Semigroup a => a -> a -> a
<> TextBuilder
"B"
    else
      if a
a a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
1000000
        then a -> a -> TextBuilder
forall {a}. Integral a => a -> a -> TextBuilder
dividedDecimal a
100 a
a TextBuilder -> TextBuilder -> TextBuilder
forall a. Semigroup a => a -> a -> a
<> TextBuilder
"kB"
        else
          if a
a a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
1000000000
            then a -> a -> TextBuilder
forall {a}. Integral a => a -> a -> TextBuilder
dividedDecimal a
100000 a
a TextBuilder -> TextBuilder -> TextBuilder
forall a. Semigroup a => a -> a -> a
<> TextBuilder
"MB"
            else
              if a
a a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
1000000000000
                then a -> a -> TextBuilder
forall {a}. Integral a => a -> a -> TextBuilder
dividedDecimal a
100000000 a
a TextBuilder -> TextBuilder -> TextBuilder
forall a. Semigroup a => a -> a -> a
<> TextBuilder
"GB"
                else
                  if a
a a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
1000000000000000
                    then a -> a -> TextBuilder
forall {a}. Integral a => a -> a -> TextBuilder
dividedDecimal a
100000000000 a
a TextBuilder -> TextBuilder -> TextBuilder
forall a. Semigroup a => a -> a -> a
<> TextBuilder
"TB"
                    else
                      if a
a a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
1000000000000000000
                        then a -> a -> TextBuilder
forall {a}. Integral a => a -> a -> TextBuilder
dividedDecimal a
100000000000000 a
a TextBuilder -> TextBuilder -> TextBuilder
forall a. Semigroup a => a -> a -> a
<> TextBuilder
"PB"
                        else
                          if a
a a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
1000000000000000000000
                            then a -> a -> TextBuilder
forall {a}. Integral a => a -> a -> TextBuilder
dividedDecimal a
100000000000000000 a
a TextBuilder -> TextBuilder -> TextBuilder
forall a. Semigroup a => a -> a -> a
<> TextBuilder
"EB"
                            else
                              if a
a a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
1000000000000000000000000
                                then a -> a -> TextBuilder
forall {a}. Integral a => a -> a -> TextBuilder
dividedDecimal a
100000000000000000000 a
a TextBuilder -> TextBuilder -> TextBuilder
forall a. Semigroup a => a -> a -> a
<> TextBuilder
"ZB"
                                else a -> a -> TextBuilder
forall {a}. Integral a => a -> a -> TextBuilder
dividedDecimal a
100000000000000000000000 a
a TextBuilder -> TextBuilder -> TextBuilder
forall a. Semigroup a => a -> a -> a
<> TextBuilder
"YB"
  where
    dividedDecimal :: a -> a -> TextBuilder
dividedDecimal a
divisor a
n =
      let byDivisor :: a
byDivisor = a -> a -> a
forall a. Integral a => a -> a -> a
div a
n a
divisor
          byExtraTen :: a
byExtraTen = a -> a -> a
forall a. Integral a => a -> a -> a
div a
byDivisor a
10
          remainder :: a
remainder = a
byDivisor a -> a -> a
forall a. Num a => a -> a -> a
- a
byExtraTen a -> a -> a
forall a. Num a => a -> a -> a
* a
10
          separatorChar :: Char
separatorChar = Char
','
       in if a
remainder a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0 Bool -> Bool -> Bool
|| a
byExtraTen a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
10
            then Char -> a -> TextBuilder
forall a. Integral a => Char -> a -> TextBuilder
thousandSeparatedDecimal Char
separatorChar a
byExtraTen
            else Char -> a -> TextBuilder
forall a. Integral a => Char -> a -> TextBuilder
thousandSeparatedDecimal Char
separatorChar a
byExtraTen TextBuilder -> TextBuilder -> TextBuilder
forall a. Semigroup a => a -> a -> a
<> TextBuilder
"." TextBuilder -> TextBuilder -> TextBuilder
forall a. Semigroup a => a -> a -> a
<> a -> TextBuilder
forall a. Integral a => a -> TextBuilder
decimalDigit a
remainder

-- | Double with a fixed number of decimal places.
--
-- >>> doubleFixedPoint 4 0.123456
-- "0.1235"
--
-- >>> doubleFixedPoint 2 2.1
-- "2.10"
--
-- >>> doubleFixedPoint (-2) 2.1
-- "2"
--
-- >>> doubleFixedPoint 2 (-2.1)
-- "-2.10"
--
-- >>> doubleFixedPoint 2 0
-- "0.00"
{-# INLINE doubleFixedPoint #-}
doubleFixedPoint ::
  -- | Amount of decimals after point.
  Int ->
  Double ->
  TextBuilder
doubleFixedPoint :: Int -> Double -> TextBuilder
doubleFixedPoint (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
0 -> Int
decimalPlaces) =
  String -> TextBuilder
forall a. IsString a => String -> a
fromString (String -> TextBuilder)
-> (Double -> String) -> Double -> TextBuilder
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. String -> Double -> String
forall r. PrintfType r => String -> r
printf (String
"%." String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
decimalPlaces String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"f")

-- | Double multiplied by 100 with a fixed number of decimal places applied and followed by a percent-sign.
--
-- >>> doubleFixedPointPercent 3 0.123456
-- "12.346%"
--
-- >>> doubleFixedPointPercent 0 2
-- "200%"
--
-- >>> doubleFixedPointPercent 0 (-2)
-- "-200%"
{-# INLINE doubleFixedPointPercent #-}
doubleFixedPointPercent ::
  -- | Amount of decimals after point.
  Int ->
  Double ->
  TextBuilder
doubleFixedPointPercent :: Int -> Double -> TextBuilder
doubleFixedPointPercent Int
decimalPlaces Double
x = Int -> Double -> TextBuilder
doubleFixedPoint Int
decimalPlaces (Double
x Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
100) TextBuilder -> TextBuilder -> TextBuilder
forall a. Semigroup a => a -> a -> a
<> TextBuilder
"%"