packages feed

haxparse-0.1.0.0: src/HaxParse/Options.hs

{-# OPTIONS_GHC -fno-warn-orphans #-}

module HaxParse.Options (
  OutputType(..),
  Opts(..),
  TimeFormat(..),
  fullOpts
) where

import Data.Char
import Data.List.Split
import HaxParse.AST        hiding (Left, Right)
import Options.Applicative

data OutputType = Plain | JSON deriving Show

data TimeFormat = Frame | Second | Both deriving Show

type EventFilter = Action -> Bool

instance Show EventFilter where show _ = "(filter)"

data Opts = Opts { outputType  :: OutputType
                 , showRoom    :: Bool
                 , showDiscs   :: Bool
                 , showPlayers :: Bool
                 , showEvents  :: Bool
                 , timeFormat  :: TimeFormat
                 , file        :: FilePath
                 , eventTypes  :: [EventFilter]
                 } deriving Show

outputTypeReader :: String -> Either ParseError OutputType
outputTypeReader s
    | map toLower s == "json" = Right JSON
    | map toLower s == "plain" = Right Plain
    | otherwise = Left . ErrorMsg $ "unknown output type " ++ s

eventTypeReader :: String -> Either ParseError [EventFilter]
eventTypeReader evs = sequence . map (fmap (. actEvent) . eventTypeReaderSingle . trim) $ splitOn "," evs
    where trim = dropWhile isSpace . reverse . dropWhile isSpace . reverse

eventTypeReaderSingle :: String -> Either ParseError (Event -> Bool)
eventTypeReaderSingle s
    | map toLower s `elem` ["new-player", "np"]     = Right isNewPlayer
    | map toLower s `elem` ["departure", "d"]       = Right isDeparture
    | map toLower s `elem` ["change-avatar", "ca"]  = Right isChangeAvatar
    | map toLower s `elem` ["chat", "c"]            = Right isChat
    | map toLower s `elem` ["start-match", "start"] = Right isStartMatch
    | map toLower s `elem` ["stop-match", "stop"]   = Right isStopMatch
    | map toLower s `elem` ["team-change", "tc"]    = Right isTeamChange
    | map toLower s `elem` ["disc-move", "m"]       = Right isDiscMove
    | map toLower s `elem` ["ping-broadcast", "p"]  = Right isPingBroadcast
    | map toLower s `elem` ["time-update", "t"]     = Right isTimeUpdate
    | otherwise = Left . ErrorMsg $ "unknown event type " ++ s

timeFormatReader :: String -> Either ParseError TimeFormat
timeFormatReader x
    | map toLower x == "frame" = Right Frame
    | map toLower x == "second" = Right Second
    | map toLower x == "both" = Right Both
    | otherwise = Left . ErrorMsg $ "unknown time format " ++ x

opts :: Parser Opts
opts = Opts <$> nullOption ( long "output-type"
                          <> short 'o'
                          <> metavar "TYPE"
                          <> help "Set output type: one of plain [default], json"
                          <> reader outputTypeReader
                          <> value Plain )
            <*> switch ( long "show-room"
                      <> short 'r'
                      <> help "Dump room information"
                      <> value False )
            <*> switch ( long "show-discs"
                      <> short 'd'
                      <> help "Dump disc information"
                      <> value False )
            <*> switch ( long "show-players"
                      <> short 'p'
                      <> help "Dump player information"
                      <> value False )
            <*> switch ( long "show-events"
                      <> short 'e'
                      <> help "Dump event information"
                      <> value False )
            <*> nullOption ( long "time-format"
                          <> short 't'
                          <> metavar "FORMAT"
                          <> help "Change timestamp format: frame, second, or both"
                          <> reader timeFormatReader
                          <> value Frame )
            <*> argument str (metavar "FILE")
            <*> nullOption ( long "event-types"
                          <> short 'f'
                          <> metavar "TYPE"
                          <> help "Filter events by type: new-player (np), departure (d), change-avatar (ca), chat (c), start-match (start), stop-match (stop), team-change (tc), disc-move (m), ping-broadcast (p), time-update (t). This option implies --show-events."
                          <> reader eventTypeReader
                          <> value [] )

fullOpts :: ParserInfo Opts
fullOpts = info (helper <*> opts)
                (fullDesc <> progDesc "Parse .hbr files.")