module Option where

import qualified Configuration as Config

import qualified Sound.ALSA.Sequencer.Event as Event

import qualified System.Exit as Exit
import qualified System.IO as IO

import qualified Options.Applicative as OP

import qualified Control.Functor.HT as FuncHT
import Control.Applicative ((<*>), )

import Data.Bool.HT (if')
import Data.Monoid ((<>))


exitFailureMsg :: String -> IO a
exitFailureMsg msg = do
   IO.hPutStrLn IO.stderr msg
   Exit.exitFailure

parseChannel :: String -> Either String Event.Channel
parseChannel str =
   case reads str of
      [(ch, "")] ->
         if' (ch<0) (Left "negative MIDI channel") $
         if' (ch>=16) (Left "MIDI channel larger than 15") $
         Right $ Event.Channel $ fromInteger ch
      _ -> Left "MIDI channel must be a number"

parseArgs :: OP.Parser (Either String Config.T, ([String], Event.Channel))
parseArgs =
   OP.liftA2 (,) Config.option $
   OP.liftA2 (,)
      (OP.many $ OP.strOption $
         OP.short 'p' <>
         OP.long "connect-to" <>
         OP.metavar "ADDRESS" <>
         OP.help "Connect with synthesizer at startup")
      (OP.option (OP.eitherReader parseChannel) $
         OP.long "midi-channel" <>
         OP.value (Event.Channel 0) <>
         OP.metavar "CHANNEL" <>
         OP.help "Send on a certain MIDI channel (default: 0)")

info :: String -> OP.Parser a -> OP.ParserInfo a
info desc parser =
   OP.info
      (OP.helper <*> parser)
      (OP.fullDesc <> OP.progDesc desc)

multiArgs :: String -> IO (Config.T, ([String], Event.Channel))
multiArgs desc = do
   FuncHT.mapFst (either exitFailureMsg return)
      =<< OP.execParser (info desc parseArgs)