content: --
  -- | Let's go lambdabot!
  --
  module Main where
  
  import Lambdabot.Main
  import Lambdabot.Plugin.Haskell
  import Modules      (modulesInfo)
  import qualified Paths_lambdabot as P
  
  import Control.Applicative
  import Control.Monad
  import Control.Monad.Identity
  import Data.Char
  import Data.Version
  import System.Console.GetOpt
  import System.Environment
  import System.Exit
  import System.IO
  
  flags :: [OptDescr (IO (DSum Config Identity))]
  flags = 
      [ Option "h?" ["help"]  (NoArg (usage []))                      "Print this help message"
      , Option "e"  []        (arg "<command>" onStartupCmds   strs)  "Run a lambdabot command instead of a REPL"
      , Option "l"  []        (arg "<level>"   consoleLogLevel level) "Set the logging level"
      , Option "t"  ["trust"] (arg "<package>" trustedPackages strs)  "Trust the specified packages when evaluating code"
      , Option "V"  ["version"] (NoArg version)                       "Print the version of lambdabot"
      , Option "X"  []        (arg "<extension>" languageExts strs)   "Set a GHC language extension for @run"
      , Option "n"  ["nice"]  (NoArg noinsult)                        "Be nice (disable insulting error messages)"
      ] where 
          arg :: String -> Config t -> (String -> IO t) -> ArgDescr (IO (DSum Config Identity))
          arg descr key fn = ReqArg (fmap (key ==>) . fn) descr
          
          strs = return . (:[])
          
          level str = case reads (map toUpper str) of
              (lv, []):_ -> return lv
              _          -> usage
                  [ "Unknown log level."
                  , "Valid levels are: " ++ show [DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, EMERGENCY]
                  ]
          
          noinsult = return (enableInsults ==> False)
  
  versionString :: String
  versionString = ("lambdabot version " ++ showVersion P.version)
  
  version :: IO a
  version = do
      putStrLn versionString
      exitWith ExitSuccess
  
  usage :: [String] -> IO a
  usage errors = do
      cmd <- getProgName
      
      let isErr = not (null errors)
          out = if isErr then stderr else stdout
      
      mapM_ (hPutStrLn out) errors
      when isErr (hPutStrLn out "")
      
      hPutStrLn out versionString
      hPutStr   out (usageInfo (cmd ++ " [options]") flags)
      
      exitWith (if isErr then ExitFailure 1 else ExitSuccess)
  
  -- do argument handling
  main :: IO ()
  main = do
      (config, nonOpts, errors) <- getOpt Permute flags <$> getArgs
      when (not (null errors && null nonOpts)) (usage errors)
      config' <- sequence config
      dir <- P.getDataDir
      exitWith <=< lambdabotMain modulesInfo $
          [dataDir ==> dir, lbVersion ==> P.version] ++ config'
  
  -- special online target for ghci use
  online :: [String] -> IO ()
  online strs = do
      dir <- P.getDataDir
      void $ lambdabotMain modulesInfo
          [dataDir ==> dir, lbVersion ==> P.version, onStartupCmds ==> strs]
  