{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE PostfixOperators #-}

-- | The logic to render Java auxiliary files is contained in this module
module Language.Drasil.Code.Imperative.GOOL.LanguageRenderer.JavaRenderer (
  JavaProject(..)
) where

import Language.Drasil.Choices (ImplementationType(..))
import Language.Drasil.Code.Imperative.GOOL.ClassInterface (ReadMeInfo(..),
  PackageSym(..), AuxiliarySym(..))
import qualified 
  Language.Drasil.Code.Imperative.GOOL.LanguageRenderer.LanguagePolymorphic as 
  G (doxConfig, readMe, sampleInput, makefile, noRunIfLib, doxDocConfig, docIfEnabled)
import Language.Drasil.Code.Imperative.GOOL.Data (AuxData(..), ad, PackData(..),
  packD)
import Language.Drasil.Code.Imperative.Build.AST (BuildConfig, BuildName(..), 
  Ext(..), Runnable, NameOpts(NameOpts), asFragment, buildSingle, 
  buildAllAdditionalName, includeExt, inCodePackage, interp, mainModule, 
  mainModuleFile, packSep, withExt)
import Language.Drasil.Code.Imperative.Doxygen.Import (yes)

import GOOL.Drasil (onCodeList, jName, jVersion)

import Data.List (intercalate)
import Prelude hiding (break,print,sin,cos,tan,floor,(<>))
import Text.PrettyPrint.HughesPJ (Doc)

-- | Name options for Java files.
jNameOpts :: NameOpts
jNameOpts :: NameOpts
jNameOpts = NameOpts :: String -> Bool -> NameOpts
NameOpts {
  packSep :: String
packSep = ".",
  includeExt :: Bool
includeExt = Bool
False
}

-- | Holds a Java project.
newtype JavaProject a = JP {JavaProject a -> a
unJP :: a}

instance Functor JavaProject where
  fmap :: (a -> b) -> JavaProject a -> JavaProject b
fmap f :: a -> b
f (JP x :: a
x) = b -> JavaProject b
forall a. a -> JavaProject a
JP (a -> b
f a
x)

instance Applicative JavaProject where
  pure :: a -> JavaProject a
pure = a -> JavaProject a
forall a. a -> JavaProject a
JP
  (JP f :: a -> b
f) <*> :: JavaProject (a -> b) -> JavaProject a -> JavaProject b
<*> (JP x :: a
x) = b -> JavaProject b
forall a. a -> JavaProject a
JP (a -> b
f a
x)

instance Monad JavaProject where
  return :: a -> JavaProject a
return = a -> JavaProject a
forall a. a -> JavaProject a
JP
  JP x :: a
x >>= :: JavaProject a -> (a -> JavaProject b) -> JavaProject b
>>= f :: a -> JavaProject b
f = a -> JavaProject b
f a
x

instance PackageSym JavaProject where
  type Package JavaProject = PackData
  package :: ProgData
-> [JavaProject (Auxiliary JavaProject)]
-> JavaProject (Package JavaProject)
package p :: ProgData
p = ([AuxData] -> PackData)
-> [JavaProject AuxData] -> JavaProject PackData
forall (m :: * -> *) a b. Monad m => ([a] -> b) -> [m a] -> m b
onCodeList (ProgData -> [AuxData] -> PackData
packD ProgData
p)

instance AuxiliarySym JavaProject where
  type Auxiliary JavaProject = AuxData
  type AuxHelper JavaProject = Doc
  doxConfig :: String
-> GOOLState -> Verbosity -> JavaProject (Auxiliary JavaProject)
doxConfig = JavaProject (AuxHelper JavaProject)
-> String
-> GOOLState
-> Verbosity
-> JavaProject (Auxiliary JavaProject)
forall (r :: * -> *).
AuxiliarySym r =>
r (AuxHelper r)
-> String -> GOOLState -> Verbosity -> r (Auxiliary r)
G.doxConfig JavaProject (AuxHelper JavaProject)
forall (r :: * -> *). AuxiliarySym r => r (AuxHelper r)
optimizeDox
  readMe :: ReadMeInfo -> JavaProject (Auxiliary JavaProject)
readMe rmi :: ReadMeInfo
rmi =
    ReadMeInfo -> JavaProject (Auxiliary JavaProject)
forall (r :: * -> *).
AuxiliarySym r =>
ReadMeInfo -> r (Auxiliary r)
G.readMe ReadMeInfo
rmi {
        langName :: String
langName = String
jName,
        langVersion :: String
langVersion = String
jVersion}
  sampleInput :: ChunkDB
-> DataDesc -> [Expr] -> JavaProject (Auxiliary JavaProject)
sampleInput = ChunkDB
-> DataDesc -> [Expr] -> JavaProject (Auxiliary JavaProject)
forall (r :: * -> *).
AuxiliarySym r =>
ChunkDB -> DataDesc -> [Expr] -> r (Auxiliary r)
G.sampleInput

  optimizeDox :: JavaProject (AuxHelper JavaProject)
optimizeDox = Doc -> JavaProject Doc
forall (m :: * -> *) a. Monad m => a -> m a
return Doc
yes

  makefile :: [String]
-> ImplementationType
-> [Comments]
-> GOOLState
-> ProgData
-> JavaProject (Auxiliary JavaProject)
makefile fs :: [String]
fs it :: ImplementationType
it cms :: [Comments]
cms = Maybe BuildConfig
-> Maybe Runnable
-> Maybe DocConfig
-> GOOLState
-> ProgData
-> JavaProject (Auxiliary JavaProject)
forall (r :: * -> *).
AuxiliarySym r =>
Maybe BuildConfig
-> Maybe Runnable
-> Maybe DocConfig
-> GOOLState
-> ProgData
-> r (Auxiliary r)
G.makefile ([String] -> ImplementationType -> Maybe BuildConfig
jBuildConfig [String]
fs ImplementationType
it) 
    (ImplementationType -> Maybe Runnable -> Maybe Runnable
G.noRunIfLib ImplementationType
it ([String] -> Maybe Runnable
jRunnable [String]
fs)) ([Comments] -> DocConfig -> Maybe DocConfig
G.docIfEnabled [Comments]
cms DocConfig
G.doxDocConfig)

  auxHelperDoc :: JavaProject (AuxHelper JavaProject) -> Doc
auxHelperDoc = JavaProject (AuxHelper JavaProject) -> Doc
forall a. JavaProject a -> a
unJP
  auxFromData :: String -> Doc -> JavaProject (Auxiliary JavaProject)
auxFromData fp :: String
fp d :: Doc
d = AuxData -> JavaProject (Auxiliary JavaProject)
forall (m :: * -> *) a. Monad m => a -> m a
return (AuxData -> JavaProject (Auxiliary JavaProject))
-> AuxData -> JavaProject (Auxiliary JavaProject)
forall a b. (a -> b) -> a -> b
$ String -> Doc -> AuxData
ad String
fp Doc
d

-- | Create a build configuration for Java files. Takes in 'FilePath's and the type of implementation.
jBuildConfig :: [FilePath] -> ImplementationType -> Maybe BuildConfig
jBuildConfig :: [String] -> ImplementationType -> Maybe BuildConfig
jBuildConfig fs :: [String]
fs Program = ([CommandFragment] -> CommandFragment -> [[CommandFragment]])
-> BuildName -> BuildName -> Maybe BuildConfig
buildSingle (\i :: [CommandFragment]
i _ -> [String -> CommandFragment
asFragment "javac" CommandFragment -> [CommandFragment] -> [CommandFragment]
forall a. a -> [a] -> [a]
: (String -> CommandFragment) -> [String] -> [CommandFragment]
forall a b. (a -> b) -> [a] -> [b]
map 
  String -> CommandFragment
asFragment ([String] -> [String]
classPath [String]
fs) [CommandFragment] -> [CommandFragment] -> [CommandFragment]
forall a. [a] -> [a] -> [a]
++ [CommandFragment]
i]) (BuildName -> String -> BuildName
withExt (BuildName -> BuildName
inCodePackage BuildName
mainModule) 
  ".class") (BuildName -> Maybe BuildConfig) -> BuildName -> Maybe BuildConfig
forall a b. (a -> b) -> a -> b
$ BuildName -> BuildName
inCodePackage BuildName
mainModuleFile
jBuildConfig fs :: [String]
fs Library = ([CommandFragment]
 -> CommandFragment -> CommandFragment -> [[CommandFragment]])
-> BuildName -> BuildName -> Maybe BuildConfig
buildAllAdditionalName (\i :: [CommandFragment]
i o :: CommandFragment
o a :: CommandFragment
a -> 
  [String -> CommandFragment
asFragment "javac" CommandFragment -> [CommandFragment] -> [CommandFragment]
forall a. a -> [a] -> [a]
: (String -> CommandFragment) -> [String] -> [CommandFragment]
forall a b. (a -> b) -> [a] -> [b]
map String -> CommandFragment
asFragment ([String] -> [String]
classPath [String]
fs) [CommandFragment] -> [CommandFragment] -> [CommandFragment]
forall a. [a] -> [a] -> [a]
++ [CommandFragment]
i,
    (String -> CommandFragment) -> [String] -> [CommandFragment]
forall a b. (a -> b) -> [a] -> [b]
map String -> CommandFragment
asFragment ["jar", "-cvf"] [CommandFragment] -> [CommandFragment] -> [CommandFragment]
forall a. [a] -> [a] -> [a]
++ [CommandFragment
o, CommandFragment
a]]) 
  (BuildName -> Ext -> BuildName
BWithExt BuildName
BPackName (Ext -> BuildName) -> Ext -> BuildName
forall a b. (a -> b) -> a -> b
$ CommandFragment -> Ext
OtherExt (CommandFragment -> Ext) -> CommandFragment -> Ext
forall a b. (a -> b) -> a -> b
$ String -> CommandFragment
asFragment ".jar") BuildName
BPackName

-- | Default runnable information for Java files.
jRunnable :: [FilePath] -> Maybe Runnable
jRunnable :: [String] -> Maybe Runnable
jRunnable fs :: [String]
fs = BuildName -> NameOpts -> String -> [String] -> Maybe Runnable
interp ((BuildName -> String -> BuildName)
-> String -> BuildName -> BuildName
forall a b c. (a -> b -> c) -> b -> a -> c
flip BuildName -> String -> BuildName
withExt ".class" (BuildName -> BuildName) -> BuildName -> BuildName
forall a b. (a -> b) -> a -> b
$ BuildName -> BuildName
inCodePackage BuildName
mainModule) 
  NameOpts
jNameOpts "java" ([String] -> [String]
classPath [String]
fs)

-- | Helper for formating file paths for use in 'jBuildConfig'.
classPath :: [FilePath] -> [String]
classPath :: [String] -> [String]
classPath fs :: [String]
fs = if [String] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
fs then [] else 
  ["-cp", "\"" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate ":" ([String]
fs [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ ["."]) String -> String -> String
forall a. [a] -> [a] -> [a]
++ "\""]