    {-# LANGUAGE DeriveGeneric #-}

    -----------------------------------------------------------------------------
    -- |
    -- Module      :  Distribution.Verbosity
    -- Copyright   :  Ian Lynagh 2007
    -- License     :  BSD3
    --
    -- Maintainer  :  cabal-devel@haskell.org
    -- Portability :  portable
    --
    -- A simple 'Verbosity' type with associated utilities. There are 4 standard
    -- verbosity levels from 'silent', 'normal', 'verbose' up to 'deafening'. This
    -- is used for deciding what logging messages to print.

    -- Verbosity for Cabal functions.

    module Distribution.Verbosity (
      -- * Verbosity
      Verbosity,
      silent, normal, verbose, deafening,
      moreVerbose, lessVerbose,
      intToVerbosity, flagToVerbosity,
      showForCabal, showForGHC
     ) where

    import Distribution.Compat.Binary (Binary)
    import Data.List (elemIndex)
    import Distribution.ReadE
    import GHC.Generics

    data Verbosity = Silent | Normal | Verbose | Deafening
        deriving (Generic, Show, Read, Eq, Ord, Enum, Bounded)

    instance Binary Verbosity

    -- We shouldn't print /anything/ unless an error occurs in silent mode
    silent :: Verbosity
    silent = Silent

    -- Print stuff we want to see by default
    normal :: Verbosity
    normal = Normal

    -- Be more verbose about what's going on
    verbose :: Verbosity
    verbose = Verbose

    -- Not only are we verbose ourselves (perhaps even noisier than when
    -- being "verbose"), but we tell everything we run to be verbose too
    deafening :: Verbosity
    deafening = Deafening

    moreVerbose :: Verbosity -> Verbosity
    moreVerbose Silent    = Silent    --silent should stay silent
    moreVerbose Normal    = Verbose
    moreVerbose Verbose   = Deafening
    moreVerbose Deafening = Deafening

    lessVerbose :: Verbosity -> Verbosity
    lessVerbose Deafening = Deafening
    lessVerbose Verbose   = Normal
    lessVerbose Normal    = Silent
    lessVerbose Silent    = Silent

    intToVerbosity :: Int -> Maybe Verbosity
    intToVerbosity 0 = Just Silent
    intToVerbosity 1 = Just Normal
    intToVerbosity 2 = Just Verbose
    intToVerbosity 3 = Just Deafening
    intToVerbosity _ = Nothing

    flagToVerbosity :: ReadE Verbosity
    flagToVerbosity = ReadE $ \s ->
       case reads s of
           [(i, "")] ->
               case intToVerbosity i of
                   Just v -> Right v
                   Nothing -> Left ("Bad verbosity: " ++ show i ++
                                         ". Valid values are 0..3")
           _ -> Left ("Can't parse verbosity " ++ s)

    showForCabal, showForGHC :: Verbosity -> String

    showForCabal v = maybe (error "unknown verbosity") show $
        elemIndex v [silent,normal,verbose,deafening]
    showForGHC   v = maybe (error "unknown verbosity") show $
        elemIndex v [silent,normal,__,verbose,deafening]
            where __ = silent -- this will be always ignored by elemIndex