{-# LANGUAGE CPP                #-}
{-# LANGUAGE DeriveDataTypeable #-}
module CommandArgs
    ( HDevTools(..)
    , loadHDevTools
    )
where

import qualified Config
import           System.Console.CmdArgs.Implicit
import           System.Environment              (getProgName)
import           System.Info                     (arch, os)

#ifdef CABAL
import           Data.Version                    (showVersion)
import           Paths_hdevtools                 (version)
#endif

programVersion :: String
programVersion =
#ifdef CABAL
    "version " ++ showVersion version
#else
    "unknown-version (not built with cabal)"
#endif

fullVersion :: String
fullVersion =
    concat
        [ programVersion
        , " (ghc-", Config.cProjectVersion, "-", arch, "-", os, ")"
        ]

data HDevTools
    = Admin
        { socket       :: Maybe FilePath
        , start_server :: Bool
        , noDaemon     :: Bool
        , status       :: Bool
        , stop_server  :: Bool
        , no_cabal     :: Bool
        , verbose      :: Bool
        }
    | Check
        { socket   :: Maybe FilePath
        , ghcOpts  :: [String]
        , file     :: String
        , no_cabal :: Bool
        , verbose  :: Bool
        }
    | ModuleFile
        { socket   :: Maybe FilePath
        , ghcOpts  :: [String]
        , module_  :: String
        , no_cabal :: Bool
        , verbose  :: Bool
        }
    | Info
        { socket     :: Maybe FilePath
        , ghcOpts    :: [String]
        , file       :: String
        , identifier :: String
        , no_cabal   :: Bool
        , verbose    :: Bool
        }
    | Type
        { socket   :: Maybe FilePath
        , ghcOpts  :: [String]
        , file     :: String
        , line     :: Int
        , col      :: Int
        , no_cabal :: Bool
        , verbose  :: Bool
        }
    deriving (Show, Data, Typeable)

dummyAdmin :: HDevTools
dummyAdmin = Admin
    { socket = Nothing
    , start_server = False
    , noDaemon = False
    , status = False
    , stop_server = False
    , no_cabal = False
    , verbose = False
    }

dummyCheck :: HDevTools
dummyCheck = Check
    { socket = Nothing
    , ghcOpts = []
    , file = ""
    , no_cabal = False
    , verbose = False
    }

dummyModuleFile :: HDevTools
dummyModuleFile = ModuleFile
    { socket = Nothing
    , ghcOpts = []
    , module_ = ""
    , no_cabal = False
    , verbose = False
    }

dummyInfo :: HDevTools
dummyInfo = Info
    { socket = Nothing
    , ghcOpts = []
    , file = ""
    , identifier = ""
    , no_cabal = False
    , verbose = False
    }

dummyType :: HDevTools
dummyType = Type
    { socket = Nothing
    , ghcOpts = []
    , file = ""
    , line = 0
    , col = 0
    , no_cabal = False
    , verbose = False
    }

admin :: Annotate Ann
admin = record dummyAdmin
    [ socket   := def += typFile += help "socket file to use"
    , start_server   := def            += help "start server"
    , noDaemon := def            += help "do not daemonize (only if --start-server)"
    , status   := def            += help "show status of server"
    , stop_server := def         += help "shutdown the server"
    , no_cabal := def            += help "don't search for a cabal file and behave like there wasn't any cabal file"
    , verbose := def             += help "enable verbose mode"
    ] += help "Interactions with the server"

check :: Annotate Ann
check = record dummyCheck
    [ socket   := def += typFile += help "socket file to use"
    , ghcOpts  := def += typ "OPTION"   += help "ghc options"
    , file     := def += typFile      += argPos 0 += opt ""
    ] += help "Check a haskell source file for errors and warnings"

moduleFile :: Annotate Ann
moduleFile = record dummyModuleFile
    [ socket   := def += typFile += help "socket file to use"
    , ghcOpts  := def += typ "OPTION" += help "ghc options"
    , module_  := def += typ "MODULE" += argPos 0
    ] += help "Get the haskell source file corresponding to a module name"

info :: Annotate Ann
info = record dummyInfo
    [ socket     := def += typFile += help "socket file to use"
    , ghcOpts    := def += typ "OPTION" += help "ghc options"
    , file       := def += typFile      += argPos 0 += opt ""
    , identifier := def += typ "IDENTIFIER" += argPos 1
    ] += help "Get info from GHC about the specified identifier"

type_ :: Annotate Ann
type_ = record dummyType
    [ socket   := def += typFile += help "socket file to use"
    , ghcOpts  := def += typ "OPTION" += help "ghc options"
    , file     := def += typFile      += argPos 0 += opt ""
    , line     := def += typ "LINE"   += argPos 1
    , col      := def += typ "COLUMN" += argPos 2
    ] += help "Get the type of the expression at the specified line and column"

full :: String -> Annotate Ann
full progName = modes_ [admin += auto, check, moduleFile, info, type_]
        += helpArg [name "h", groupname "Help"]
        += versionArg [groupname "Help"]
        += program progName
        += summary (progName ++ ": " ++ fullVersion)

loadHDevTools :: IO HDevTools
loadHDevTools = do
    progName <- getProgName
    cmdArgs_ (full progName) :: IO HDevTools
