module Options
  ( Opts(..)
  , execParser
  , prefs
  , showHelpOnEmpty
  , optsParser
  , optsParserInfo ) where

import Options.Applicative
    ( (<**>),
      auto,
      fullDesc,
      header,
      help,
      info,
      long,
      metavar,
      option,
      strOption,
      prefs,
      progDesc,
      short,
      showHelpOnEmpty,
      value,
      execParser,
      Parser,
      ParserInfo,
      infoOption,
      hidden )

import Options.Applicative.Extra ( helperWith )

import Version ( versionStr, progName )
import Data.Kind (Type)

data Opts = Opts  -- ^ Custom data record for storing 'Options.Applicative.Parser' values
  { Opts -> Integer
optPort    :: Integer  -- ^ MPD port to connect.
  , Opts -> String
optHost    :: String   -- ^ MPD host address to connect.
  , Opts -> String
optPass    :: String   -- ^ Plain text password to connect to MPD.
  , Opts -> * -> *
optVersion :: Type -> Type  -- ^ Print program version.
  }

optsParser :: Parser Opts
optsParser :: Parser Opts
optsParser
  = Integer -> String -> String -> (* -> *) -> Opts
Opts
  (Integer -> String -> String -> (* -> *) -> Opts)
-> Parser Integer -> Parser (String -> String -> (* -> *) -> Opts)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser Integer
portOptParser
  Parser (String -> String -> (* -> *) -> Opts)
-> Parser String -> Parser (String -> (* -> *) -> Opts)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser String
hostOptParser
  Parser (String -> (* -> *) -> Opts)
-> Parser String -> Parser ((* -> *) -> Opts)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser String
passOptParser
  Parser ((* -> *) -> Opts) -> Parser (* -> *) -> Parser Opts
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser (* -> *)
forall a. Parser (a -> a)
versionOptParse

portOptParser :: Parser Integer
portOptParser :: Parser Integer
portOptParser
  = ReadM Integer -> Mod OptionFields Integer -> Parser Integer
forall a. ReadM a -> Mod OptionFields a -> Parser a
option ReadM Integer
forall a. Read a => ReadM a
auto
  (Mod OptionFields Integer -> Parser Integer)
-> Mod OptionFields Integer -> Parser Integer
forall a b. (a -> b) -> a -> b
$ String -> Mod OptionFields Integer
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"port"
  Mod OptionFields Integer
-> Mod OptionFields Integer -> Mod OptionFields Integer
forall a. Semigroup a => a -> a -> a
<> Char -> Mod OptionFields Integer
forall (f :: * -> *) a. HasName f => Char -> Mod f a
short Char
'p'
  Mod OptionFields Integer
-> Mod OptionFields Integer -> Mod OptionFields Integer
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields Integer
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar String
"PORTNUM"
  Mod OptionFields Integer
-> Mod OptionFields Integer -> Mod OptionFields Integer
forall a. Semigroup a => a -> a -> a
<> Integer -> Mod OptionFields Integer
forall (f :: * -> *) a. HasValue f => a -> Mod f a
value Integer
6600
  Mod OptionFields Integer
-> Mod OptionFields Integer -> Mod OptionFields Integer
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields Integer
forall (f :: * -> *) a. String -> Mod f a
help String
"Port number"

hostOptParser :: Parser String
hostOptParser :: Parser String
hostOptParser
  = Mod OptionFields String -> Parser String
forall s. IsString s => Mod OptionFields s -> Parser s
strOption
  (Mod OptionFields String -> Parser String)
-> Mod OptionFields String -> Parser String
forall a b. (a -> b) -> a -> b
$ String -> Mod OptionFields String
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar String
"ADDRESS"
  Mod OptionFields String
-> Mod OptionFields String -> Mod OptionFields String
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields String
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"host"
  Mod OptionFields String
-> Mod OptionFields String -> Mod OptionFields String
forall a. Semigroup a => a -> a -> a
<> Char -> Mod OptionFields String
forall (f :: * -> *) a. HasName f => Char -> Mod f a
short Char
'h'
  Mod OptionFields String
-> Mod OptionFields String -> Mod OptionFields String
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields String
forall (f :: * -> *) a. HasValue f => a -> Mod f a
value String
"localhost"
  Mod OptionFields String
-> Mod OptionFields String -> Mod OptionFields String
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields String
forall (f :: * -> *) a. String -> Mod f a
help String
"Host address"

passOptParser :: Parser String
passOptParser :: Parser String
passOptParser
  = ReadM String -> Mod OptionFields String -> Parser String
forall a. ReadM a -> Mod OptionFields a -> Parser a
option ReadM String
forall a. Read a => ReadM a
auto
  (Mod OptionFields String -> Parser String)
-> Mod OptionFields String -> Parser String
forall a b. (a -> b) -> a -> b
$ String -> Mod OptionFields String
forall (f :: * -> *) a. HasMetavar f => String -> Mod f a
metavar String
"PASSWORD"
  Mod OptionFields String
-> Mod OptionFields String -> Mod OptionFields String
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields String
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"password"
  Mod OptionFields String
-> Mod OptionFields String -> Mod OptionFields String
forall a. Semigroup a => a -> a -> a
<> Char -> Mod OptionFields String
forall (f :: * -> *) a. HasName f => Char -> Mod f a
short Char
'P'
  Mod OptionFields String
-> Mod OptionFields String -> Mod OptionFields String
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields String
forall (f :: * -> *) a. HasValue f => a -> Mod f a
value String
""
  Mod OptionFields String
-> Mod OptionFields String -> Mod OptionFields String
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields String
forall (f :: * -> *) a. String -> Mod f a
help String
"Password for connecting (will be sent as plain text)"

versionOptParse :: Parser (a -> a)
versionOptParse :: forall a. Parser (a -> a)
versionOptParse =
  String -> Mod OptionFields (a -> a) -> Parser (a -> a)
forall a. String -> Mod OptionFields (a -> a) -> Parser (a -> a)
infoOption String
versionStr
  (Mod OptionFields (a -> a) -> Parser (a -> a))
-> Mod OptionFields (a -> a) -> Parser (a -> a)
forall a b. (a -> b) -> a -> b
$ String -> Mod OptionFields (a -> a)
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"version"
  Mod OptionFields (a -> a)
-> Mod OptionFields (a -> a) -> Mod OptionFields (a -> a)
forall a. Semigroup a => a -> a -> a
<> Char -> Mod OptionFields (a -> a)
forall (f :: * -> *) a. HasName f => Char -> Mod f a
short Char
'V'
  Mod OptionFields (a -> a)
-> Mod OptionFields (a -> a) -> Mod OptionFields (a -> a)
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields (a -> a)
forall (f :: * -> *) a. String -> Mod f a
help String
"Display the version number"

optsParserInfo :: ParserInfo Opts
optsParserInfo :: ParserInfo Opts
optsParserInfo = Parser Opts -> InfoMod Opts -> ParserInfo Opts
forall a. Parser a -> InfoMod a -> ParserInfo a
info (Parser Opts
optsParser Parser Opts -> Parser (Opts -> Opts) -> Parser Opts
forall (f :: * -> *) a b. Applicative f => f a -> f (a -> b) -> f b
<**> Parser (Opts -> Opts)
forall a. Parser (a -> a)
helper')
  (InfoMod Opts -> ParserInfo Opts)
-> InfoMod Opts -> ParserInfo Opts
forall a b. (a -> b) -> a -> b
$ InfoMod Opts
forall a. InfoMod a
fullDesc
  InfoMod Opts -> InfoMod Opts -> InfoMod Opts
forall a. Semigroup a => a -> a -> a
<> String -> InfoMod Opts
forall a. String -> InfoMod a
progDesc String
"Print currently playing song information as JSON"
  InfoMod Opts -> InfoMod Opts -> InfoMod Opts
forall a. Semigroup a => a -> a -> a
<> String -> InfoMod Opts
forall a. String -> InfoMod a
header (String
progName String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" - " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"Current MPD song information as JSON")

helper' :: Parser (a -> a)
helper' :: forall a. Parser (a -> a)
helper' = Mod OptionFields (a -> a) -> Parser (a -> a)
forall a. Mod OptionFields (a -> a) -> Parser (a -> a)
helperWith
          (Mod OptionFields (a -> a) -> Parser (a -> a))
-> Mod OptionFields (a -> a) -> Parser (a -> a)
forall a b. (a -> b) -> a -> b
$ String -> Mod OptionFields (a -> a)
forall (f :: * -> *) a. HasName f => String -> Mod f a
long String
"help"
          -- <> help "Show this help text"
          Mod OptionFields (a -> a)
-> Mod OptionFields (a -> a) -> Mod OptionFields (a -> a)
forall a. Semigroup a => a -> a -> a
<> Mod OptionFields (a -> a)
forall (f :: * -> *) a. Mod f a
hidden -- don't show in help messages