--
-- Data vault for metrics
--
-- Copyright © 2013-2014 Anchor Systems, Pty Ltd and Others
--
-- The code in this file, and the program it is a part of, is
-- made available to you by its authors as open source software:
-- you can redistribute it and/or modify it under the terms of
-- the 3-clause BSD licence.
--

--
-- | Common program initalization for Vaultaire binaries
--
module Vaultaire.Program
(
    initializeProgram,
    Verbosity(..)
)
where

import Control.Concurrent.MVar
import Control.Monad
import GHC.Conc
import System.Environment
import System.IO (hFlush, hPutStrLn, stdout)
import System.Log.Formatter
import System.Log.Handler (setFormatter)
import System.Log.Handler.Simple
import System.Log.Logger
import System.Posix.Signals


--
-- Main program entry point
--

interruptHandler :: MVar () -> Handler
interruptHandler semaphore = Catch $ do
    putStrLn "\nInterrupt"
    hFlush stdout
    putMVar semaphore ()

terminateHandler :: MVar () -> Handler
terminateHandler semaphore = Catch $ do
    putStrLn "Terminating"
    hFlush stdout
    putMVar semaphore ()

quitHandler :: Handler
quitHandler = Catch $ do
    putStrLn ""
    hFlush stdout
    logger <- getLogger rootLoggerName
    let level   = getLevel logger
        level'  = case level of
                    Just DEBUG  -> INFO
                    Just INFO   -> DEBUG
                    _           -> DEBUG
        logger' = setLevel level' logger
    saveGlobalLogger logger'
    infoM "Main.quitHandler" ("Change log level to " ++ show level')

data Verbosity = Debug | Normal | Quiet deriving Show

--
-- | Initialize a program. Call this from your 'main' program entry point
-- before doing anything else. Indicate the logging verbosity you want, along
-- with an identification of your program. Returns an MVar which will be set to
-- unit if one of the installed signal handlers catches a signal and requests a
-- shutdown as a result.
--
initializeProgram :: String -> Verbosity -> IO (MVar ())
initializeProgram banner verbosity = do
    -- Indicate startup
    name <- getProgName
    case verbosity of
        Quiet -> return ()
        _     -> putStrLn $ name ++ " (" ++ banner ++ ") starting"

    -- command line +RTS -Nn -RTS value
    when (numCapabilities == 1) (getNumProcessors >>= setNumCapabilities)

    -- Start and configure logger, deleting the default handler in favour of
    -- our own formatter outputting to stdout with timestamps. Run in Zulu time.
    setEnv "TZ" "UTC"

    let level = case verbosity of
                   Debug  -> DEBUG
                   Normal -> INFO
                   Quiet  -> WARNING

    logger  <- getRootLogger
    handler <- streamHandler stdout DEBUG
    let handler' = setFormatter handler (tfLogFormatter "%Y-%m-%dT%H:%M:%SZ" "$time  $msg")
    let logger' = (setHandlers [handler'] . setLevel level) logger
    saveGlobalLogger logger'

    debugM "Program.initialize" "Logging initialized"

    quit <- newEmptyMVar

    _ <- installHandler sigINT  (interruptHandler quit) Nothing
    _ <- installHandler sigTERM (terminateHandler quit) Nothing
    _ <- installHandler sigQUIT quitHandler Nothing


    debugM "Program.initialize" "Signal handlers installed"

    return quit