-- | A module for compiling Scala source files using @scalac@.
module System.Build.Scala.Scalac(
                                  Fsc,
                                  Scalac,
                                  -- * @Scalac@ members
                                  debug,
                                  nowarn,
                                  verbose,
                                  deprecation,
                                  unchecked,
                                  classpath,
                                  sourcepath,
                                  bootclasspath,
                                  extdirs,
                                  directory,
                                  encoding,
                                  target,
                                  print,
                                  optimise,
                                  explaintypes,
                                  uniqid,
                                  version,
                                  help,
                                  (?),
                                  etc,
                                  -- * @Scalac@ values
                                  scalac,
                                  scalac',
                                  kscalac,
                                  fscalac,
                                  -- * @Fsc@ members
                                  reset,
                                  shutdown,
                                  server,
                                  flags,
                                  -- * @Fsc@ values
                                  fsc
                                ) where

import Prelude hiding (print)
import System.Build.Args
import System.Build.Scala.Debug
import System.Build.Scala.Target
import System.Build.CompilePaths
import System.Build.Extensions
import System.Build.OutputDirectory
import System.Build.OutputReferenceSet
import System.Build.OutputReferenceGet
import System.Build.Command
import Data.List
import Data.Maybe
import System.FilePath

-- | Scalac is the compiler for Scala source files.
data Scalac = Scalac {
  debug :: Maybe Debug,        -- ^ @-g@
  nowarn :: Bool,              -- ^ @-nowarn@
  verbose :: Bool,             -- ^ @-verbose@
  deprecation :: Bool,         -- ^ @-deprecation@
  unchecked :: Bool,           -- ^ @-unchecked@
  classpath :: [FilePath],     -- ^ @-classpath@
  sourcepath :: [FilePath],    -- ^ @-sourcepath@
  bootclasspath :: [FilePath], -- ^ @-bootclasspath@
  extdirs :: [FilePath],       -- ^ @-extdirs@
  directory :: Maybe FilePath, -- ^ @-d@
  encoding :: Maybe String,    -- ^ @-encoding@
  target :: Maybe Target,      -- ^ @-target@
  print :: Bool,               -- ^ @-print@
  optimise :: Bool,            -- ^ @-optimise@
  explaintypes :: Bool,        -- ^ @-explaintypes@
  uniqid :: Bool,              -- ^ @-uniqid@
  version :: Bool,             -- ^ @-version@
  help :: Bool,                -- ^ @-help@
  (?) :: Maybe FilePath,       -- ^ @\@@
  etc :: Maybe String
}

-- | A @Scalac@ with nothing set.
scalac :: Scalac
scalac = Scalac Nothing False False False False [] [] [] [] Nothing Nothing Nothing False False False False False False Nothing Nothing

-- | Construct a @Scalac@.
scalac' :: Maybe System.Build.Scala.Debug.Debug
           -> Bool
           -> Bool
           -> Bool
           -> Bool
           -> [FilePath]
           -> [FilePath]
           -> [FilePath]
           -> [FilePath]
           -> Maybe FilePath
           -> Maybe String
           -> Maybe Target
           -> Bool
           -> Bool
           -> Bool
           -> Bool
           -> Bool
           -> Bool
           -> Maybe FilePath
           -> Maybe String
           -> Scalac
scalac' = Scalac

-- | Convert the given scalac to a list of command line options which may be used by other scala tools.
kscalac :: Scalac -> [String]
kscalac (Scalac debug'
                 nowarn'
                 verbose'
                 deprecation'
                 unchecked'
                 classpath'
                 sourcepath'
                 bootclasspath'
                 extdirs'
                 directory'
                 encoding'
                 target'
                 print'
                 optimise'
                 explaintypes'
                 uniqid'
                 version'
                 help'
                 script'
                 etc') = ["g" -~> debug',
                         "nowarn" ~~ nowarn',
                         "verbose" ~~ verbose',
                         "deprecation" ~~ deprecation',
                         "unchecked" ~~ unchecked',
                         "classpath" ~: classpath',
                         "sourcepath" ~: sourcepath',
                         "bootclasspath" ~: bootclasspath',
                         "extdirs" ~: extdirs',
                         "d" ~~> directory',
                         "encoding" ~~> encoding',
                         "target" -~> target',
                         "print" ~~ print',
                         "optimise" ~~ optimise',
                         "explaintypes" ~~ explaintypes',
                         "uniqid" ~~ uniqid',
                         "version" ~~ version',
                         "help" ~~ help',
                         (:) '@' ~? script',
                         fromMaybe [] etc']

instance Show Scalac where
  show s = kscalac s ^^^ " "

instance CompilePaths Scalac where
  j =>> ps = show j ++ ' ' : space ps

instance Extensions Scalac where
  exts _ = ["java", "scala"]

instance OutputDirectory Scalac where
  outdir = directory

instance OutputReferenceSet Scalac where
  setReference p j = j { classpath = p }

instance OutputReferenceGet Scalac where
  getReference = classpath

instance Command Scalac where
  command _ = let envs = [
                            ("SCALA_HOME", (</> "bin" </> "scalac")),
                            ("SCALAC", id)
                         ]
              in fromMaybe "scalac" `fmap` tryEnvs envs

-- | The Scala fast compiler (@fsc@).
data Fsc = Fsc {
  fscalac :: Scalac,                -- ^ The scalac options to use.
  reset :: Bool,                    -- ^ @-reset@
  shutdown :: Bool,                 -- ^ @-shutdown@
  server :: Maybe (String, String), -- ^ @-server@
  flags :: [String]                 -- ^ @-flags@
}

instance Show Fsc where
  show (Fsc fscalac' reset' shutdown' server' flags') = (kscalac fscalac' ++ ["reset" ~~ reset', "shutdown" ~~ shutdown', maybe [] (uncurry (++)) server', intercalate " " (fmap ("-J" ++) flags')]) ^^^ " "

instance CompilePaths Fsc where
  j =>> ps = show j ++ ' ' : space ps

instance Extensions Fsc where
  exts _ = ["java", "scala"]

instance OutputDirectory Fsc where
  outdir = directory . fscalac

instance OutputReferenceSet Fsc where
  setReference p j = let s = fscalac j in j { fscalac = setReference p s }

instance OutputReferenceGet Fsc where
  getReference = getReference . fscalac

instance Command Fsc where
  command _ = let envs = [
                            ("SCALA_HOME", (</> "bin" </> "fsc")),
                            ("FSC", id)
                         ]
              in fromMaybe "fsc" `fmap` tryEnvs envs

-- | A @Fsc@ with nothing set.
fsc :: Fsc
fsc = Fsc scalac False False Nothing []