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

import Prelude hiding (print)
import Lastik.Util
import Lastik.Compile
import Lastik.Extension
import Lastik.Output
import Lastik.Scala.Debug
import Lastik.Scala.Target
import Data.List
import System.Exit

-- | 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 Lastik.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" -~> show $ debug,
                         "nowarn" ~~ nowarn,
                         "verbose" ~~ verbose,
                         "deprecation" ~~ deprecation,
                         "unchecked" ~~ unchecked,
                         "classpath" ~?? classpath,
                         "sourcepath" ~?? sourcepath,
                         "bootclasspath" ~?? bootclasspath,
                         "extdirs" ~?? extdirs,
                         "d" ~~~> directory,
                         "encoding" ~~~> encoding,
                         "target" -~> show $ target,
                         "print" ~~ print,
                         "optimise" ~~ optimise,
                         "explaintypes" ~~ explaintypes,
                         "uniqid" ~~ uniqid,
                         "version" ~~ version,
                         "help" ~~ help,
                         ((:) '@') ~? script,
                         id ~? etc]

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

instance Compile Scalac where
  compile s ps = "scalac " ++ show s ++ ' ' : space ps

instance Output Scalac where
  output = directory

instance Extension Scalac where
  ext _ = "scala"

instance OutputReference Scalac where
  reference p s = s { classpath = p }
  reference' = classpath

-- | 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, (uncurry (++)) ~? server, intercalate " " (fmap ("-J" ++) flags)]) ^^^ " "

instance Compile Fsc where
  compile f ps = "fsc " ++ show f ++ ' ' : space ps

instance Output Fsc where
  output = directory . fscalac

instance Extension Fsc where
  ext _ = "scala"

instance OutputReference Fsc where
  reference p f = let s = fscalac f in f { fscalac = reference p s }
  reference' = reference' . fscalac

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