{-# LANGUAGE RecordWildCards, ApplicativeDo #-}

import Options.Applicative

import System.FilePath
import System.FileLock

import Data.Char
import Data.Monoid
import Data.List

import Trivmix.Types


data Options = Options
               { baseDirectory :: FilePath
               , targetDirectory :: FilePath
               , levelFile :: FilePath
               , adjustment :: Adjustment Level
               }


optionParser :: Parser Options
optionParser = do
  baseDirectory <- strOption $ mconcat
    [ long "base", metavar "DIRECTORY", showDefault
    , value "/dev/shm/mix"
    , help "Base directory"
    ]
  levelFile <- strOption $ mconcat
    [ long "level", short 'l', metavar "FILENAME", showDefault
    , value "level"
    , help "Filename of the level file"
    ]
  targetDirectory <- strArgument $ mconcat
    [ metavar "DIRECTORY"
    , help "Directory relative to ‘--base’ containing the level file"
    ]
  adjustment <- getAlt . mconcat $ map Alt
    [ Set <$> option auto (mconcat
                           [ long "set", short 'o', metavar "LEVEL"
                           , help "Overwrite the current level"
                           ])
    , Add <$> option auto (mconcat
                           [ long "add", short 'a', metavar "LEVEL"
                           , help "Add to the current level"
                           ])
    , Sub <$> option auto (mconcat
                           [ long "sub", short 's', metavar "LEVEL"
                           , help "Subtract from the current level"
                           ])
    , let
        adjMode = getAlt . mconcat $ map Alt
          [ flag' Add (mconcat
                       [ long "inc", short 'i'
                       , help "Increase level by a preset amount (see ‘--by’)"
                       ])
          , flag' Sub (mconcat
                       [ long "dec", short 'd'
                       , help "Decrease level by a preset amount (see ‘--by’)"
                       ])
          ]
        adjBy = option auto (mconcat
                             [ long "by", short 'b', metavar "LEVEL", value (read "2.5dB"), showDefault
                             , help "Value to increase/decrease level by when using ‘--inc’ or ‘--dec’"
                             ])
      in adjMode <*> adjBy
    ]
  return Options{..}

main :: IO ()
main = execParser opts >>= adjmix
  where
    opts = info (helper <*> optionParser) $ mconcat
      [ progDesc "Adjust the level file of a trivmix"
      , header "Adjmix — A trivial interface to a trivial mixer"
      , fullDesc
      ]

adjmix :: Options -> IO ()
adjmix Options{..} = withFileLock levelFile' Exclusive . const $ do
  oldLevel <- readFile levelFile' >>= readIO . stripSpace
  let newLevel = oldLevel `doAdjustment` adjustment
  writeFile levelFile' $ show newLevel ++ "\n"
  where
    levelFile' = baseDirectory </> targetDirectory </> levelFile
    stripSpace = dropWhile isSpace . dropWhileEnd isSpace