{-# LANGUAGE OverloadedStrings #-}

module Wordlist.Args
  ( Args (..), getArgs, argsNumber, argsDelimiter

  -- * Parser details
  , argsP
  , defaultNumber, defaultDelimiter
  , numberP, delimiterP
  ) where

import Control.Applicative (optional)
import Data.Maybe (fromMaybe)
import Data.Text (Text)
import Options.Applicative.Extra (execParser, helper)
import Options.Applicative.Types (Parser)

import qualified Data.Text as Text
import qualified Options.Applicative.Builder as Opt

data Args = Args
  { Args -> Maybe Int
argsNumberMaybe :: Maybe Int
  , Args -> Maybe Text
argsDelimiterMaybe :: Maybe Text
  }

defaultNumber :: Int
defaultNumber :: Int
defaultNumber = Int
4

defaultDelimiter :: Text
defaultDelimiter :: Text
defaultDelimiter = Text
" "

numberP :: Parser (Maybe Int)
numberP :: Parser (Maybe Int)
numberP =
    Parser Int -> Parser (Maybe Int)
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (Parser Int -> Parser (Maybe Int))
-> Parser Int -> Parser (Maybe Int)
forall a b. (a -> b) -> a -> b
$ ReadM Int -> Mod OptionFields Int -> Parser Int
forall a. ReadM a -> Mod OptionFields a -> Parser a
Opt.option ReadM Int
forall a. Read a => ReadM a
Opt.auto (Mod OptionFields Int -> Parser Int)
-> Mod OptionFields Int -> Parser Int
forall a b. (a -> b) -> a -> b
$
    String -> Mod OptionFields Int
forall (f :: * -> *) a. HasName f => String -> Mod f a
Opt.long String
"number" Mod OptionFields Int
-> Mod OptionFields Int -> Mod OptionFields Int
forall a. Semigroup a => a -> a -> a
<> Char -> Mod OptionFields Int
forall (f :: * -> *) a. HasName f => Char -> Mod f a
Opt.short Char
'n' Mod OptionFields Int
-> Mod OptionFields Int -> Mod OptionFields Int
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields Int
forall (f :: * -> *) a. String -> Mod f a
Opt.help String
help
  where
    help :: String
help = String
"Number of words (default: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<>
           Int -> String
forall a. Show a => a -> String
show Int
defaultNumber String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
")"

delimiterP :: Parser (Maybe Text)
delimiterP :: Parser (Maybe Text)
delimiterP =
    Parser Text -> Parser (Maybe Text)
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (Parser Text -> Parser (Maybe Text))
-> Parser Text -> Parser (Maybe Text)
forall a b. (a -> b) -> a -> b
$ ReadM Text -> Mod OptionFields Text -> Parser Text
forall a. ReadM a -> Mod OptionFields a -> Parser a
Opt.option ((String -> Text) -> ReadM String -> ReadM Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap String -> Text
Text.pack ReadM String
forall s. IsString s => ReadM s
Opt.str) (Mod OptionFields Text -> Parser Text)
-> Mod OptionFields Text -> Parser Text
forall a b. (a -> b) -> a -> b
$
    String -> Mod OptionFields Text
forall (f :: * -> *) a. HasName f => String -> Mod f a
Opt.long String
"delimiter" Mod OptionFields Text
-> Mod OptionFields Text -> Mod OptionFields Text
forall a. Semigroup a => a -> a -> a
<> Char -> Mod OptionFields Text
forall (f :: * -> *) a. HasName f => Char -> Mod f a
Opt.short Char
'd' Mod OptionFields Text
-> Mod OptionFields Text -> Mod OptionFields Text
forall a. Semigroup a => a -> a -> a
<> String -> Mod OptionFields Text
forall (f :: * -> *) a. String -> Mod f a
Opt.help String
help
  where
    help :: String
help = String
"Delimiter between words (default: space)"

argsP :: Parser Args
argsP :: Parser Args
argsP =
  Maybe Int -> Maybe Text -> Args
Args (Maybe Int -> Maybe Text -> Args)
-> Parser (Maybe Int) -> Parser (Maybe Text -> Args)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser (Maybe Int)
numberP Parser (Maybe Text -> Args) -> Parser (Maybe Text) -> Parser Args
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser (Maybe Text)
delimiterP

parserInfo :: Opt.InfoMod a
parserInfo :: InfoMod a
parserInfo =
  String -> InfoMod a
forall a. String -> InfoMod a
Opt.header
  String
"Generates random English words. Useful for password generation."

getArgs :: IO Args
getArgs :: IO Args
getArgs =
  ParserInfo Args -> IO Args
forall a. ParserInfo a -> IO a
execParser (ParserInfo Args -> IO Args) -> ParserInfo Args -> IO Args
forall a b. (a -> b) -> a -> b
$ Parser Args -> InfoMod Args -> ParserInfo Args
forall a. Parser a -> InfoMod a -> ParserInfo a
Opt.info (Parser (Args -> Args)
forall a. Parser (a -> a)
helper Parser (Args -> Args) -> Parser Args -> Parser Args
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser Args
argsP) InfoMod Args
forall a. InfoMod a
parserInfo

argsNumber :: Args -> Int
argsNumber :: Args -> Int
argsNumber =
  Int -> Maybe Int -> Int
forall a. a -> Maybe a -> a
fromMaybe Int
defaultNumber (Maybe Int -> Int) -> (Args -> Maybe Int) -> Args -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Args -> Maybe Int
argsNumberMaybe

argsDelimiter :: Args -> Text
argsDelimiter :: Args -> Text
argsDelimiter =
  Text -> Maybe Text -> Text
forall a. a -> Maybe a -> a
fromMaybe Text
defaultDelimiter (Maybe Text -> Text) -> (Args -> Maybe Text) -> Args -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Args -> Maybe Text
argsDelimiterMaybe