module Language.Drasil.Printing.Import.Literal (literal) where

import Language.Drasil (dbl)
import Language.Drasil.Literal.Development (Literal(..))

import qualified Language.Drasil.Printing.AST as P
import Language.Drasil.Printing.PrintingInformation (PrintingInformation,
  Notation(..), notation)

import Control.Lens ((^.))
import Numeric (floatToDigits)

literal :: Literal -> PrintingInformation -> P.Expr
literal :: Literal -> PrintingInformation -> Expr
literal (Dbl Double
d)                  PrintingInformation
sm = case PrintingInformation
sm PrintingInformation
-> Getting Notation PrintingInformation Notation -> Notation
forall s a. s -> Getting a s a -> a
^. Getting Notation PrintingInformation Notation
Lens' PrintingInformation Notation
notation of
  Notation
Engineering ->
     let (Int
f, Int
s) = Int -> (Int, Int)
processExpo (Int -> (Int, Int)) -> Int -> (Int, Int)
forall a b. (a -> b) -> a -> b
$ ([Int], Int) -> Int
forall a b. (a, b) -> b
snd (([Int], Int) -> Int) -> ([Int], Int) -> Int
forall a b. (a -> b) -> a -> b
$ Integer -> Double -> ([Int], Int)
forall a. RealFloat a => Integer -> a -> ([Int], Int)
floatToDigits Integer
10 Double
d in
     [Expr] -> Expr
P.Row ([Expr] -> Expr) -> [Expr] -> Expr
forall a b. (a -> b) -> a -> b
$ [Integer] -> Int -> Int -> Integer -> [Expr]
digitsProcess ((Int -> Integer) -> [Int] -> [Integer]
forall a b. (a -> b) -> [a] -> [b]
map Int -> Integer
forall a. Integral a => a -> Integer
toInteger ([Int] -> [Integer]) -> [Int] -> [Integer]
forall a b. (a -> b) -> a -> b
$ ([Int], Int) -> [Int]
forall a b. (a, b) -> a
fst (([Int], Int) -> [Int]) -> ([Int], Int) -> [Int]
forall a b. (a -> b) -> a -> b
$ Integer -> Double -> ([Int], Int)
forall a. RealFloat a => Integer -> a -> ([Int], Int)
floatToDigits Integer
10 Double
d)
     Int
f Int
0 (Int -> Integer
forall a. Integral a => a -> Integer
toInteger Int
s)
  Notation
Scientific  ->  Double -> Expr
P.Dbl Double
d
literal (Int Integer
i)                   PrintingInformation
_ = Integer -> Expr
P.Int Integer
i
literal (ExactDbl Integer
d)              PrintingInformation
_ = Integer -> Expr
P.Int Integer
d
literal (Str String
s)                   PrintingInformation
_ = String -> Expr
P.Str String
s
literal (Perc Integer
a Integer
b)               PrintingInformation
sm = [Expr] -> Expr
P.Row [Literal -> PrintingInformation -> Expr
literal (Double -> Literal
forall r. LiteralC r => Double -> r
dbl Double
val) PrintingInformation
sm, Ops -> Expr
P.MO Ops
P.Perc]
  where
    val :: Double
val = Integer -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
a Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ (Double
10 Double -> Double -> Double
forall a. Floating a => a -> a -> a
** Integer -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Integer
b Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
2))

-- | Processes the digits from the 'floatToDigits' function, decimal point
-- position, a counter, and exponent.
digitsProcess :: [Integer] -> Int -> Int -> Integer -> [P.Expr]
digitsProcess :: [Integer] -> Int -> Int -> Integer -> [Expr]
digitsProcess [Integer
0] Int
_ Int
_ Integer
_ = [Integer -> Expr
P.Int Integer
0, Ops -> Expr
P.MO Ops
P.Point, Integer -> Expr
P.Int Integer
0]
digitsProcess [Integer]
ds Int
pos Int
_ (-3) = [Integer -> Expr
P.Int Integer
0, Ops -> Expr
P.MO Ops
P.Point] [Expr] -> [Expr] -> [Expr]
forall a. [a] -> [a] -> [a]
++ Int -> Expr -> [Expr]
forall a. Int -> a -> [a]
replicate (Int
3 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
pos) (Integer -> Expr
P.Int Integer
0) [Expr] -> [Expr] -> [Expr]
forall a. [a] -> [a] -> [a]
++ (Integer -> Expr) -> [Integer] -> [Expr]
forall a b. (a -> b) -> [a] -> [b]
map Integer -> Expr
P.Int [Integer]
ds
digitsProcess (Integer
hd:[Integer]
tl) Int
pos Int
coun Integer
ex
  | Int
pos Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
coun = Integer -> Expr
P.Int Integer
hd Expr -> [Expr] -> [Expr]
forall a. a -> [a] -> [a]
: [Integer] -> Int -> Int -> Integer -> [Expr]
digitsProcess [Integer]
tl Int
pos (Int
coun Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Integer
ex
  | Integer
ex Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
/= Integer
0 = [Ops -> Expr
P.MO Ops
P.Point, Integer -> Expr
P.Int Integer
hd] [Expr] -> [Expr] -> [Expr]
forall a. [a] -> [a] -> [a]
++ (Integer -> Expr) -> [Integer] -> [Expr]
forall a b. (a -> b) -> [a] -> [b]
map Integer -> Expr
P.Int [Integer]
tl [Expr] -> [Expr] -> [Expr]
forall a. [a] -> [a] -> [a]
++ [Ops -> Expr
P.MO Ops
P.Dot, Integer -> Expr
P.Int Integer
10, Expr -> Expr
P.Sup (Expr -> Expr) -> Expr -> Expr
forall a b. (a -> b) -> a -> b
$ Integer -> Expr
P.Int Integer
ex]
  | Bool
otherwise = [Ops -> Expr
P.MO Ops
P.Point, Integer -> Expr
P.Int Integer
hd] [Expr] -> [Expr] -> [Expr]
forall a. [a] -> [a] -> [a]
++ (Integer -> Expr) -> [Integer] -> [Expr]
forall a b. (a -> b) -> [a] -> [b]
map Integer -> Expr
P.Int [Integer]
tl
digitsProcess [] Int
pos Int
coun Integer
ex
  | Int
pos Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
coun = Integer -> Expr
P.Int Integer
0 Expr -> [Expr] -> [Expr]
forall a. a -> [a] -> [a]
: [Integer] -> Int -> Int -> Integer -> [Expr]
digitsProcess [] Int
pos (Int
counInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) Integer
ex
  | Integer
ex Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
/= Integer
0 = [Ops -> Expr
P.MO Ops
P.Point, Integer -> Expr
P.Int Integer
0, Ops -> Expr
P.MO Ops
P.Dot, Integer -> Expr
P.Int Integer
10, Expr -> Expr
P.Sup (Expr -> Expr) -> Expr -> Expr
forall a b. (a -> b) -> a -> b
$ Integer -> Expr
P.Int Integer
ex]
  | Bool
otherwise = [Ops -> Expr
P.MO Ops
P.Point, Integer -> Expr
P.Int Integer
0]

-- | Takes the exponent and the 'Int' of the base and gives the decimal point
-- position and processed exponent. This function supports transferring
-- scientific notation to engineering notation.
--
-- References for standard of Engineering Notation:
-- * <https://www.khanacademy.org/science/electrical-engineering/introduction-to-ee/intro-to-ee/a/ee-numbers-in-electrical-engineering>
-- * <https://www.calculatorsoup.com/calculators/math/scientific-notation-converter.php>
-- * <https://en.wikipedia.org/wiki/Scientific_notation>
processExpo :: Int -> (Int, Int)
processExpo :: Int -> (Int, Int)
processExpo Int
a = (Int
r, Int
a Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
r)
  where r :: Int
r = Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int -> Int -> Int
forall a. Integral a => a -> a -> a
mod (Int
a Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Int
3