-- | Printing helpers.
module Language.Drasil.Printing.Import.Helpers where

import Language.Drasil (Stage(..), codeSymb, eqSymb, Idea(..),
  NamedIdea(..), NounPhrase(..), Sentence(S), Symbol, UID,
  TermCapitalization(..), titleizeNP, titleizeNP', atStartNP, atStartNP', NP)
import Database.Drasil (ChunkDB, symbResolve, termResolve)

import qualified Language.Drasil.Printing.AST as P

import Control.Lens ((^.))
import Data.Char (toUpper)

-- * Expr-related

-- | Helper for inserting parentheses.
parens :: P.Expr -> P.Expr
parens :: Expr -> Expr
parens = Fence -> Fence -> Expr -> Expr
P.Fenced Fence
P.Paren Fence
P.Paren

-- | 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] forall a. [a] -> [a] -> [a]
++ forall a. Int -> a -> [a]
replicate (Int
3 forall a. Num a => a -> a -> a
- Int
pos) (Integer -> Expr
P.Int Integer
0) forall a. [a] -> [a] -> [a]
++ 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 forall a. Eq a => a -> a -> Bool
/= Int
coun = Integer -> Expr
P.Int Integer
hd forall a. a -> [a] -> [a]
: [Integer] -> Int -> Int -> Integer -> [Expr]
digitsProcess [Integer]
tl Int
pos (Int
coun forall a. Num a => a -> a -> a
+ Int
1) Integer
ex
  | Integer
ex forall a. Eq a => a -> a -> Bool
/= Integer
0 = [Ops -> Expr
P.MO Ops
P.Point, Integer -> Expr
P.Int Integer
hd] forall a. [a] -> [a] -> [a]
++ forall a b. (a -> b) -> [a] -> [b]
map Integer -> Expr
P.Int [Integer]
tl forall a. [a] -> [a] -> [a]
++ [Ops -> Expr
P.MO Ops
P.Dot, Integer -> Expr
P.Int Integer
10, Expr -> Expr
P.Sup 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] forall a. [a] -> [a] -> [a]
++ forall a b. (a -> b) -> [a] -> [b]
map Integer -> Expr
P.Int [Integer]
tl
digitsProcess [] Int
pos Int
coun Integer
ex
  | Int
pos forall a. Ord a => a -> a -> Bool
> Int
coun = Integer -> Expr
P.Int Integer
0 forall a. a -> [a] -> [a]
: [Integer] -> Int -> Int -> Integer -> [Expr]
digitsProcess [] Int
pos (Int
counforall a. Num a => a -> a -> a
+Int
1) Integer
ex
  | Integer
ex 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 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
  | forall a. Integral a => a -> a -> a
mod (Int
aforall a. Num a => a -> a -> a
-Int
1) Int
3 forall a. Eq a => a -> a -> Bool
== Int
0 = (Int
1, Int
aforall a. Num a => a -> a -> a
-Int
1)
  | forall a. Integral a => a -> a -> a
mod (Int
aforall a. Num a => a -> a -> a
-Int
1) Int
3 forall a. Eq a => a -> a -> Bool
== Int
1 = (Int
2, Int
aforall a. Num a => a -> a -> a
-Int
2)
  | forall a. Integral a => a -> a -> a
mod (Int
aforall a. Num a => a -> a -> a
-Int
1) Int
3 forall a. Eq a => a -> a -> Bool
== Int
2 = (Int
3, Int
aforall a. Num a => a -> a -> a
-Int
3)
  | Bool
otherwise = forall a. HasCallStack => [Char] -> a
error [Char]
"The cases of processExpo should be exhaustive!"

-- * Lookup/Term Resolution Functions

-- | Given the stage of the symbol, looks up a character/symbol
-- inside a chunk database that matches the given 'UID'. 
lookupC :: Stage -> ChunkDB -> UID -> Symbol
lookupC :: Stage -> ChunkDB -> UID -> Symbol
lookupC Stage
Equational     ChunkDB
sm UID
c = forall q. HasSymbol q => q -> Symbol
eqSymb   forall a b. (a -> b) -> a -> b
$ ChunkDB -> UID -> QuantityDict
symbResolve ChunkDB
sm UID
c
lookupC Stage
Implementation ChunkDB
sm UID
c = forall q. HasSymbol q => q -> Symbol
codeSymb forall a b. (a -> b) -> a -> b
$ ChunkDB -> UID -> QuantityDict
symbResolve ChunkDB
sm UID
c

-- | Look up a term given a chunk database and a 'UID' associated with the term. Also specifies capitalization
lookupT :: ChunkDB -> UID -> TermCapitalization -> Sentence
lookupT :: ChunkDB -> UID -> TermCapitalization -> Sentence
lookupT ChunkDB
sm UID
c TermCapitalization
tCap = TermCapitalization -> NP -> Sentence
resolveCapT TermCapitalization
tCap forall a b. (a -> b) -> a -> b
$ ChunkDB -> UID -> IdeaDict
termResolve ChunkDB
sm UID
c forall s a. s -> Getting a s a -> a
^. forall c. NamedIdea c => Lens' c NP
term

-- | Look up the acronym/abbreviation of a term. Otherwise returns the singular form of a term. Takes a chunk database and a 'UID' associated with the term.
lookupS :: ChunkDB -> UID -> TermCapitalization -> Sentence
lookupS :: ChunkDB -> UID -> TermCapitalization -> Sentence
lookupS ChunkDB
sm UID
c TermCapitalization
sCap = forall b a. b -> (a -> b) -> Maybe a -> b
maybe (TermCapitalization -> NP -> Sentence
resolveCapT TermCapitalization
sCap forall a b. (a -> b) -> a -> b
$ IdeaDict
l forall s a. s -> Getting a s a -> a
^. forall c. NamedIdea c => Lens' c NP
term) [Char] -> Sentence
S forall a b. (a -> b) -> a -> b
$ forall c. Idea c => c -> Maybe [Char]
getA IdeaDict
l forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= TermCapitalization -> [Char] -> Maybe [Char]
capHelper TermCapitalization
sCap
  where l :: IdeaDict
l = ChunkDB -> UID -> IdeaDict
termResolve ChunkDB
sm UID
c

-- | Look up the plural form of a term given a chunk database and a 'UID' associated with the term.
lookupP :: ChunkDB -> UID -> TermCapitalization -> Sentence
lookupP :: ChunkDB -> UID -> TermCapitalization -> Sentence
lookupP ChunkDB
sm UID
c TermCapitalization
pCap = TermCapitalization -> NP -> Sentence
resolveCapP TermCapitalization
pCap forall a b. (a -> b) -> a -> b
$ ChunkDB -> UID -> IdeaDict
termResolve ChunkDB
sm UID
c forall s a. s -> Getting a s a -> a
^. forall c. NamedIdea c => Lens' c NP
term

-- | Helper to get the proper function for capitalizing a 'NP' based on its 'TermCapitalization'. Singular case.
resolveCapT :: TermCapitalization -> (NP -> Sentence)
resolveCapT :: TermCapitalization -> NP -> Sentence
resolveCapT TermCapitalization
NoCap = forall n. NounPhrase n => n -> Sentence
phraseNP
resolveCapT TermCapitalization
CapF = forall n. NounPhrase n => n -> Sentence
atStartNP
resolveCapT TermCapitalization
CapW = forall n. NounPhrase n => n -> Sentence
titleizeNP

-- | Helper to get the right function for capitalizing a 'NP' based on its 'TermCapitalization'. Plural case.
resolveCapP :: TermCapitalization -> (NP -> Sentence)
resolveCapP :: TermCapitalization -> NP -> Sentence
resolveCapP TermCapitalization
NoCap = forall n. NounPhrase n => n -> Sentence
pluralNP
resolveCapP TermCapitalization
CapF = forall n. NounPhrase n => n -> Sentence
atStartNP'
resolveCapP TermCapitalization
CapW = forall n. NounPhrase n => n -> Sentence
titleizeNP'

-- | Helper to get the capital case of an abbreviation based on 'TermCapitalization'. For sentence and title cases.
capHelper :: TermCapitalization -> String -> Maybe String
capHelper :: TermCapitalization -> [Char] -> Maybe [Char]
capHelper TermCapitalization
NoCap [Char]
s      = forall (m :: * -> *) a. Monad m => a -> m a
return [Char]
s
capHelper TermCapitalization
_     []     = forall a. Maybe a
Nothing
capHelper TermCapitalization
_     (Char
x:[Char]
xs) = forall a. a -> Maybe a
Just (Char -> Char
toUpper Char
xforall a. a -> [a] -> [a]
: [Char]
xs)