-- | Markdown file creator for generated GOOL code.
module Language.Drasil.Markdown.CreateMd (
    -- * Main Function
    makeMd,
    -- * Section Creators
    introInfo, verInfo, unsupOS, extLibSec, regularSec, instDoc, endNote) 
    where

import Prelude hiding ((<>))
import Text.PrettyPrint.HughesPJ (Doc, empty, isEmpty, vcat, text, (<+>),
    (<>), comma, punctuate, hsep)

-- | Separates document sections.
type Seperator = Doc

-- | Combines a list of sentences into a final Doc, also appends end note.
makeMd :: [Doc] -> Doc
makeMd :: [Doc] -> Doc
makeMd = [Doc] -> Doc
vcat ([Doc] -> Doc) -> ([Doc] -> [Doc]) -> [Doc] -> Doc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Doc -> [Doc] -> [Doc]
punctuate Doc
secSep ([Doc] -> [Doc]) -> ([Doc] -> [Doc]) -> [Doc] -> [Doc]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Doc] -> [Doc]
filtEmp

-- | Example title and purpose section.
introInfo :: String -> [String] -> Doc
introInfo :: String -> [String] -> Doc
introInfo name :: String
name auths :: [String]
auths = Doc -> Doc -> Int -> Doc
introSec (String -> Doc
text String
name) ([String] -> Doc
listToDoc [String]
auths) (Int -> Doc) -> Int -> Doc
forall a b. (a -> b) -> a -> b
$ [String] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [String]
auths

-- | Instruction section, contains 3 paragraphs, Running, Building and Config Files.
-- The Config file section is only displayed if there are configuration files.
instDoc :: [String] -> Doc
instDoc :: [String] -> Doc
instDoc cfp :: [String]
cfp = Doc -> Doc -> Doc
regularSec (String -> Doc
text "Making Examples") 
    (Doc
runInstDoc Doc -> Doc -> Doc
<> Doc
doubleSep Doc -> Doc -> Doc
<> Doc
makeInstDoc) Doc -> Doc -> Doc
<> [String] -> Doc
configSec [String]
cfp 

-- | Helper for giving instructions on the command line.
commandLine :: Doc
commandLine :: Doc
commandLine = String -> Doc
text (String -> Doc) -> String -> Doc
forall a b. (a -> b) -> a -> b
$ "In your terminal command line, enter the same directory as this " String -> String -> String
forall a. [a] -> [a] -> [a]
++
    "README file. Then enter the following line:"

-- | Helper for giving instructions on how to run the program.
runInstDoc :: Doc
runInstDoc :: Doc
runInstDoc = String -> Doc
text "How to Run the Program:" Doc -> Doc -> Doc
<> Doc
contSep Doc -> Doc -> Doc
<>
    Doc
commandLine Doc -> Doc -> Doc
<> Doc
contSep Doc -> Doc -> Doc
<> Doc
bkQuote3 Doc -> Doc -> Doc
<> Doc
contSep Doc -> Doc -> Doc
<> String -> Doc
text "make run RUNARGS=input.txt" Doc -> Doc -> Doc
<> Doc
contSep Doc -> Doc -> Doc
<> Doc
bkQuote3

-- | Helper for giving instructions on how to build the program.
makeInstDoc :: Doc
makeInstDoc :: Doc
makeInstDoc = String -> Doc
text "How to Build the Program:" Doc -> Doc -> Doc
<> Doc
contSep Doc -> Doc -> Doc
<> Doc
commandLine Doc -> Doc -> Doc
<> Doc
contSep Doc -> Doc -> Doc
<>
    Doc
bkQuote3 Doc -> Doc -> Doc
<> Doc
contSep Doc -> Doc -> Doc
<> String -> Doc
text "make build" Doc -> Doc -> Doc
<> Doc
contSep Doc -> Doc -> Doc
<> Doc
bkQuote3

-- | Helper for giving instructions for configuration files.
configSec :: [String] -> Doc
configSec :: [String] -> Doc
configSec [] = Doc
empty
configSec cfp :: [String]
cfp = Doc
doubleSep Doc -> Doc -> Doc
<> Doc -> Doc -> Doc
regularSec (String -> Doc
text "Configuration Files") (String -> Doc
text ("Configuration files are files that must be " String -> String -> String
forall a. [a] -> [a] -> [a]
++
    "in the same directory as the executable in order to run or build successfully.")
    Doc -> Doc -> Doc
<> Doc
doubleSep Doc -> Doc -> Doc
<> Doc
bkQuote Doc -> Doc -> Doc
<> [String] -> Doc
listToDoc [String]
cfp Doc -> Doc -> Doc
<> Doc
bkQuote)

-- | Language version section.
verInfo :: String -> String -> Doc
verInfo :: String -> String -> Doc
verInfo pl :: String
pl plv :: String
plv = Doc -> Doc -> Doc
regularSec (String -> Doc
text "Version") (Doc
bkQuote Doc -> Doc -> Doc
<> String -> Doc
text String
pl Doc -> Doc -> Doc
<+> String -> Doc
text String
plv Doc -> Doc -> Doc
<> Doc
bkQuote)

-- | Invalid Operating Systems section, does not display unless atleast 1 invalid OS.
unsupOS :: Maybe String -> Doc
unsupOS :: Maybe String -> Doc
unsupOS = Doc -> (String -> Doc) -> Maybe String -> Doc
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Doc
empty (\uns :: String
uns-> Doc -> Doc -> Doc
regularSec (String -> Doc
text "Unsupported Operating Systems")
    (String -> Doc
text (String -> Doc) -> String -> Doc
forall a b. (a -> b) -> a -> b
$ "- " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
uns))

-- | External Libraries section. The inputs are a list of name and version pairs
-- and a list of the corresponding version numbers, these are first combined into a 
-- list of triplets, and then each printed on a new line.
extLibSec:: [(String, String)] -> [String]-> Doc
extLibSec :: [(String, String)] -> [String] -> Doc
extLibSec libns :: [(String, String)]
libns libfps :: [String]
libfps = 
    let libs :: [(String, String, String)]
libs = [(String, String)] -> [String] -> [(String, String, String)]
addListToTuple [(String, String)]
libns [String]
libfps
        formattedLibs :: Doc
formattedLibs = ([Doc] -> Doc
hsep ([Doc] -> Doc)
-> ([(String, String, String)] -> [Doc])
-> [(String, String, String)]
-> Doc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Doc -> [Doc] -> [Doc]
punctuate Doc
contSep ([Doc] -> [Doc])
-> ([(String, String, String)] -> [Doc])
-> [(String, String, String)]
-> [Doc]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Doc] -> [Doc]
filtEmp ([Doc] -> [Doc])
-> ([(String, String, String)] -> [Doc])
-> [(String, String, String)]
-> [Doc]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. 
            ((String, String, String) -> Doc)
-> [(String, String, String)] -> [Doc]
forall a b. (a -> b) -> [a] -> [b]
map (String, String, String) -> Doc
libStatment) [(String, String, String)]
libs
    in if Doc -> Bool
isEmpty Doc
formattedLibs then Doc
empty else 
            Doc -> Doc -> Doc
regularSec (String -> Doc
text "External Libraries") Doc
formattedLibs

-- | Helper for formatting the library section.
libStatment :: (String, String, String) -> Doc
libStatment :: (String, String, String) -> Doc
libStatment ("","", _) = Doc
empty
libStatment (nam :: String
nam,vers :: String
vers, fp :: String
fp) = Doc
bkQuote Doc -> Doc -> Doc
<> String -> Doc
text String
nam Doc -> Doc -> Doc
<+>
    String -> Doc
text String
vers Doc -> Doc -> Doc
<> Doc
bkQuote Doc -> Doc -> Doc
<> if String
fp String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== "" then Doc
empty else
    String -> Doc
text ". The local file path to the library is" Doc -> Doc -> Doc
<+> Doc
bkQuote Doc -> Doc -> Doc
<> String -> Doc
text String
fp Doc -> Doc -> Doc
<> Doc
bkQuote

-- | Helper for converting a list of tuples and another list into a list of triplets.
addListToTuple :: [(String,String)] -> [String] -> [(String, String, String)]
addListToTuple :: [(String, String)] -> [String] -> [(String, String, String)]
addListToTuple [] [] = []
addListToTuple ((n :: String
n,v :: String
v):_) [] = [(String
n,String
v,"")]
addListToTuple ((n :: String
n,v :: String
v):xtup :: [(String, String)]
xtup) (l :: String
l:xlst :: [String]
xlst) = (String
n,String
v,String
l)(String, String, String)
-> [(String, String, String)] -> [(String, String, String)]
forall a. a -> [a] -> [a]
:[(String, String)] -> [String] -> [(String, String, String)]
addListToTuple [(String, String)]
xtup [String]
xlst
addListToTuple _ _ = []

-- TODO: Allow licenses to have updated date information.
-- | License section.
license :: Doc -> Doc
license :: Doc -> Doc
license auth :: Doc
auth = String -> Doc
text "Copyright (c) 2021," Doc -> Doc -> Doc
<+> Doc
auth Doc -> Doc -> Doc
<>
  String -> Doc
text ". All rights reserved. Please see the [full license](https://github.com/JacquesCarette/Drasil/blob/4b9ad0a3016fecb3c7a2aa82ab142f9e805b5cc8/LICENSE) for more details."
-- | Drasil Tree icon. Uses HTML directly to format image since normal markdown doesn't support it.
drasilImage :: Doc
drasilImage :: Doc
drasilImage = String -> Doc
alignImage "../../../../drasil-website/WebInfo/images/Icon.png"
-- | Aligns an image to the center using HTML, since markdown doesn't support it.
alignImage :: FilePath -> Doc
alignImage :: String -> Doc
alignImage img :: String
img = String -> Doc
text "<p align=\"center\">" Doc -> Doc -> Doc
<>
  Doc
contSep Doc -> Doc -> Doc
<> String -> Doc
text ("<img src=\"" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
img String -> String -> String
forall a. [a] -> [a] -> [a]
++ "\" alt=\"Drasil Tree\" width=\"200\" />")
  Doc -> Doc -> Doc
<> Doc
contSep Doc -> Doc -> Doc
<> String -> Doc
text "</p>"
-- | End section.
endNote :: [String] -> Doc
endNote :: [String] -> Doc
endNote auth :: [String]
auth = String -> Doc
text "*This README is a software artifact generated by Drasil.*" Doc -> Doc -> Doc
<> Doc
doubleSep Doc -> Doc -> Doc
<> Doc -> Doc
license ([String] -> Doc
listToDoc [String]
auth) Doc -> Doc -> Doc
<> Doc
doubleSep Doc -> Doc -> Doc
<> Doc
drasilImage 

-- | Section seperators.
secSep, contSep, doubleSep, bkQuote, bkQuote3 :: Seperator
-- | Horizontal line separator.
secSep :: Doc
secSep = String -> Doc
text "\n\n------------------------------------------------------------"
-- | Newline separator.
contSep :: Doc
contSep = String -> Doc
text "\n"
-- | Double newline separator.
doubleSep :: Doc
doubleSep = String -> Doc
text "\n\n"
-- | Back quote separator.
bkQuote :: Doc
bkQuote = String -> Doc
text "`"
-- | Triple backquote separator.
bkQuote3 :: Doc
bkQuote3 = String -> Doc
text "```"


-- FIXME as explained in #2224 we still need to add in the purpose section, 
-- this could be done by adding a third parameter to introSec
-- | Constructs introduction section from header and message.
introSec ::  Doc -> Doc -> Int -> Doc
introSec :: Doc -> Doc -> Int -> Doc
introSec hd :: Doc
hd ms1 :: Doc
ms1 l :: Int
l = String -> Doc
text "#" Doc -> Doc -> Doc
<+> Doc
hd Doc -> Doc -> Doc
<+> Doc
contSep Doc -> Doc -> Doc
<> (if Int
l Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== 1 then String -> Doc
text "> Author:" else String -> Doc
text "> Authors: ") Doc -> Doc -> Doc
<+> Doc
ms1 

-- | Constructs regular section section from header and message.
regularSec :: Doc -> Doc -> Doc
regularSec :: Doc -> Doc -> Doc
regularSec hd :: Doc
hd ms :: Doc
ms = String -> Doc
text "##" Doc -> Doc -> Doc
<+> Doc
hd Doc -> Doc -> Doc
<+> Doc
contSep Doc -> Doc -> Doc
<+> Doc
ms

-- | Helper for 'makeMd' and 'extLibSec'.
filtEmp :: [Doc] -> [Doc]
filtEmp :: [Doc] -> [Doc]
filtEmp = (Doc -> Bool) -> [Doc] -> [Doc]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (Doc -> Bool) -> Doc -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Doc -> Bool
isEmpty) 

-- | Helper for authors and configuration files.
listToDoc :: [String] -> Doc
listToDoc :: [String] -> Doc
listToDoc = [Doc] -> Doc
hsep ([Doc] -> Doc) -> ([String] -> [Doc]) -> [String] -> Doc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Doc -> [Doc] -> [Doc]
punctuate Doc
comma ([Doc] -> [Doc]) -> ([String] -> [Doc]) -> [String] -> [Doc]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> Doc) -> [String] -> [Doc]
forall a b. (a -> b) -> [a] -> [b]
map String -> Doc
text