module Numeric.DigitGroup where

import Data.List
import Data.List.Split 
import Data.Char
import Numeric

digitGroupIntegral :: Integral a => Char -> p -> a -> [Char]
digitGroupIntegral :: Char -> p -> a -> [Char]
digitGroupIntegral Char
separator p
_ a
n = (if a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
0 then [Char]
"-" else [Char]
"") 
                  [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ ([Char] -> [Char]
forall a. [a] -> [a]
reverse ([Char] -> [Char]) -> [Char] -> [Char]
forall a b. (a -> b) -> a -> b
$ [Char] -> [[Char]] -> [Char]
forall a. [a] -> [[a]] -> [a]
intercalate [Char
separator] ([[Char]] -> [Char]) -> [[Char]] -> [Char]
forall a b. (a -> b) -> a -> b
$ Int -> [Char] -> [[Char]]
forall e. Int -> [e] -> [[e]]
chunksOf Int
3 ([Char] -> [Char]
forall a. [a] -> [a]
reverse ([Char] -> [Char]) -> [Char] -> [Char]
forall a b. (a -> b) -> a -> b
$ (a -> Char) -> [a] -> [Char]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Char
intToDigit (Int -> Char) -> (a -> Int) -> a -> Char
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral)  ([a] -> [Char]) -> [a] -> [Char]
forall a b. (a -> b) -> a -> b
$ a -> [a]
forall a. Integral a => a -> [a]
nums a
n))  
                  where 
                   nums :: a -> [a]
nums a
x = [a] -> [a]
forall a. [a] -> [a]
reverse ([a] -> [a]) -> [a] -> [a]
forall a b. (a -> b) -> a -> b
$  (a -> Maybe (a, a)) -> a -> [a]
forall b a. (b -> Maybe (a, b)) -> b -> [a]
unfoldr (\a
x -> case  a -> a -> (a, a)
forall a. Integral a => a -> a -> (a, a)
divMod a
x a
10 of  { (a
0,a
0) -> Maybe (a, a)
forall a. Maybe a
Nothing  ; (a
x,a
y) -> (a, a) -> Maybe (a, a)
forall a. a -> Maybe a
Just (a
y,a
x)}) a
x  

digitGroupRealFrac :: RealFloat a => Char -> Maybe Char -> a -> [Char]
digitGroupRealFrac :: Char -> Maybe Char -> a -> [Char]
digitGroupRealFrac Char
separator1 Maybe Char
separator2 a
n = (if a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
0 then [Char]
"-" else [Char]
"") 
             [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char] -> [Char]
forall a. [a] -> [a]
reverse ([Char] -> [[Char]] -> [Char]
forall a. [a] -> [[a]] -> [a]
intercalate [Char
separator1] (Int -> [Char] -> [[Char]]
forall e. Int -> [e] -> [[e]]
chunksOf Int
3 ([Char] -> [[Char]]) -> [Char] -> [[Char]]
forall a b. (a -> b) -> a -> b
$ [Char] -> [Char]
forall a. [a] -> [a]
reverse [Char]
whole')) 
             [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"." [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++  [Char] -> [[Char]] -> [Char]
forall a. [a] -> [[a]] -> [a]
intercalate [Char]
separator2' (Int -> [Char] -> [[Char]]
forall e. Int -> [e] -> [[e]]
chunksOf Int
3 [Char]
frac)
  where 
  separator2' :: [Char]
separator2' = case Maybe Char
separator2 of { (Just Char
x) -> [Char
x] ; Maybe Char
_ -> [] } 
  whole' :: [Char]
whole' = if [Char]
whole [Char] -> [Char] -> Bool
forall a. Eq a => a -> a -> Bool
== [] then [Char]
"0" else [Char]
whole
  ([Char]
whole,[Char]
frac)  = Int -> [Char] -> ([Char], [Char])
forall a. Int -> [a] -> ([a], [a])
splitAt Int
y [Char]
digitString
  digitString :: [Char]
digitString = (Int -> Char) -> [Int] -> [Char]
forall a b. (a -> b) -> [a] -> [b]
map Int -> Char
intToDigit ( Int -> Int -> [Int]
forall a. Int -> a -> [a]
replicate (if Int
y Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 then Int -> Int
forall a. Num a => a -> a
abs Int
y else Int
0 ) Int
0 [Int] -> [Int] -> [Int]
forall a. [a] -> [a] -> [a]
++ [Int]
xs [Int] -> [Int] -> [Int]
forall a. [a] -> [a] -> [a]
++ Int -> Int -> [Int]
forall a. Int -> a -> [a]
replicate (Int
yInt -> Int -> Int
forall a. Num a => a -> a -> a
-[Int] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Int]
xsInt -> Int -> Int
forall a. Num a => a -> a -> a
+if Int
y Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
1 then Int
1 else Int
0 ) Int
0) 
  ([Int]
xs,Int
y) = Integer -> a -> ([Int], Int)
forall a. RealFloat a => Integer -> a -> ([Int], Int)
floatToDigits Integer
10 a
n


class DigitGroupShow a where
  digitGroup :: Char -> Maybe Char -> a -> String

instance DigitGroupShow Integer where
  digitGroup :: Char -> Maybe Char -> Integer -> [Char]
digitGroup Char
separator Maybe Char
_ Integer
x = Char -> Maybe Any -> Integer -> [Char]
forall a p. Integral a => Char -> p -> a -> [Char]
digitGroupIntegral Char
separator Maybe Any
forall a. Maybe a
Nothing Integer
x

instance DigitGroupShow Int where
  digitGroup :: Char -> Maybe Char -> Int -> [Char]
digitGroup Char
separator Maybe Char
_ Int
x = Char -> Maybe Any -> Int -> [Char]
forall a p. Integral a => Char -> p -> a -> [Char]
digitGroupIntegral Char
separator Maybe Any
forall a. Maybe a
Nothing Int
x

instance DigitGroupShow Float where
  digitGroup :: Char -> Maybe Char -> Float -> [Char]
digitGroup Char
separator1 Maybe Char
separator2 Float
x = Char -> Maybe Char -> Float -> [Char]
forall a. RealFloat a => Char -> Maybe Char -> a -> [Char]
digitGroupRealFrac Char
separator1 Maybe Char
separator2 Float
x

instance DigitGroupShow Double where
  digitGroup :: Char -> Maybe Char -> Double -> [Char]
digitGroup Char
separator1 Maybe Char
separator2 Double
x = Char -> Maybe Char -> Double -> [Char]
forall a. RealFloat a => Char -> Maybe Char -> a -> [Char]
digitGroupRealFrac Char
separator1 Maybe Char
separator2 Double
x

digitGroupComma :: DigitGroupShow a => a -> String
digitGroupComma :: a -> [Char]
digitGroupComma a
num = Char -> Maybe Char -> a -> [Char]
forall a. DigitGroupShow a => Char -> Maybe Char -> a -> [Char]
digitGroup Char
',' (Char -> Maybe Char
forall a. a -> Maybe a
Just Char
' ') a
num

digitGroupUnderScore :: DigitGroupShow a => a -> String
digitGroupUnderScore :: a -> [Char]
digitGroupUnderScore a
num = Char -> Maybe Char -> a -> [Char]
forall a. DigitGroupShow a => Char -> Maybe Char -> a -> [Char]
digitGroup Char
'_' (Char -> Maybe Char
forall a. a -> Maybe a
Just Char
'_') a
num