{-# LANGUAGE LambdaCase #-}

module Language.EFLINT.Options where

import Language.EFLINT.Util

import Control.Monad (when)

import System.Directory
import System.IO.Unsafe
import Data.IORef

type Options = IORef OptionsStruct

data OptionsStruct = OptionsStruct {
        OptionsStruct -> [FilePath]
include_paths   :: [FilePath]
      , OptionsStruct -> [FilePath]
included_files  :: [FilePath]
      , OptionsStruct -> Maybe FilePath
filepath        :: Maybe FilePath
      , OptionsStruct -> [Bool]
input           :: [Bool] 
      , OptionsStruct -> Bool
ignore_scenario :: Bool
      , OptionsStruct -> Bool
debug           :: Bool
      , OptionsStruct -> Bool
accept_phrases  :: Bool
      , OptionsStruct -> Bool
test_mode       :: Bool
      }

find :: (OptionsStruct -> a) -> Options -> a
find :: forall a. (OptionsStruct -> a) -> Options -> a
find OptionsStruct -> a
proj = OptionsStruct -> a
proj forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. IO a -> a
unsafePerformIO forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. IORef a -> IO a
readIORef

defaultOptionsStruct :: OptionsStruct
defaultOptionsStruct = OptionsStruct {
    include_paths :: [FilePath]
include_paths   = []
  , included_files :: [FilePath]
included_files  = []
  , filepath :: Maybe FilePath
filepath        = forall a. Maybe a
Nothing
  , input :: [Bool]
input           = [] 
  , ignore_scenario :: Bool
ignore_scenario = Bool
False
  , debug :: Bool
debug           = Bool
False
  , test_mode :: Bool
test_mode       = Bool
False 
  , accept_phrases :: Bool
accept_phrases  = Bool
False
  }

is_in_test_mode :: Options -> IO Bool
is_in_test_mode :: Options -> IO Bool
is_in_test_mode Options
opts = OptionsStruct -> Bool
test_mode forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. IORef a -> IO a
readIORef Options
opts

run_options :: [String] -> IO Options
run_options :: [FilePath] -> IO Options
run_options [FilePath]
args = do
  Options
ref <- forall a. a -> IO (IORef a)
newIORef OptionsStruct
defaultOptionsStruct 
  [FilePath] -> Options -> IO ()
run_options' [FilePath]
args Options
ref 
  forall (m :: * -> *) a. Monad m => a -> m a
return Options
ref
 where
  run_options' :: [FilePath] -> Options -> IO ()
run_options' [] Options
opts = forall (m :: * -> *) a. Monad m => a -> m a
return ()
  run_options' (FilePath
"--ignore-scenario":[FilePath]
args) Options
opts = do
    forall a. IORef a -> (a -> a) -> IO ()
modifyIORef Options
opts (\OptionsStruct
os -> OptionsStruct
os { ignore_scenario :: Bool
ignore_scenario = Bool
True } )
    [FilePath] -> Options -> IO ()
run_options' [FilePath]
args Options
opts 
  run_options' (FilePath
"--debug":[FilePath]
args) Options
opts = do
    forall a. IORef a -> (a -> a) -> IO ()
modifyIORef Options
opts (\OptionsStruct
os -> OptionsStruct
os { debug :: Bool
debug = Bool
True })
    [FilePath] -> Options -> IO ()
run_options' [FilePath]
args Options
opts 
  run_options' (FilePath
"--test-mode":[FilePath]
args) Options
opts = do -- errors and failed queries only
    forall a. IORef a -> (a -> a) -> IO ()
modifyIORef Options
opts (\OptionsStruct
os -> OptionsStruct
os { test_mode :: Bool
test_mode = Bool
True })
    [FilePath] -> Options -> IO ()
run_options' [FilePath]
args Options
opts 
  run_options' (FilePath
"--accept-phrases":[FilePath]
args) Options
opts = do
    forall a. IORef a -> (a -> a) -> IO ()
modifyIORef Options
opts (\OptionsStruct
os -> OptionsStruct
os { accept_phrases :: Bool
accept_phrases = Bool
True })
    [FilePath] -> Options -> IO ()
run_options' [FilePath]
args Options
opts 
  run_options' (FilePath
"-i":(FilePath
sdir:[FilePath]
args)) Options
opts = FilePath -> Options -> IO ()
add_include_path FilePath
sdir Options
opts forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> [FilePath] -> Options -> IO ()
run_options' [FilePath]
args Options
opts
  run_options' (FilePath
_:[FilePath]
args) Options
opts = [FilePath] -> Options -> IO ()
run_options' [FilePath]
args Options
opts

add_include_path :: String -> Options -> IO () 
add_include_path :: FilePath -> Options -> IO ()
add_include_path FilePath
fp Options
opts = FilePath -> IO Bool
doesDirectoryExist FilePath
fp forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Bool
False -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
    Bool
True  -> forall a. IORef a -> (a -> a) -> IO ()
modifyIORef Options
opts (\OptionsStruct
os -> OptionsStruct
os {include_paths :: [FilePath]
include_paths = OptionsStruct -> [FilePath]
include_paths OptionsStruct
os forall a. [a] -> [a] -> [a]
++ [FilePath
fp] })

add_include :: String -> Options -> IO ()
add_include :: FilePath -> Options -> IO ()
add_include FilePath
fp Options
opts = FilePath -> IO Bool
doesFileExist FilePath
fp forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Bool
False -> forall (m :: * -> *) a. Monad m => a -> m a
return () 
    Bool
True  -> forall a. IORef a -> (a -> a) -> IO ()
modifyIORef Options
opts (\OptionsStruct
os -> OptionsStruct
os {included_files :: [FilePath]
included_files = OptionsStruct -> [FilePath]
included_files OptionsStruct
os forall a. [a] -> [a] -> [a]
++ [FilePath
fp] })

has_been_included :: FilePath -> Options -> Bool
has_been_included :: FilePath -> Options -> Bool
has_been_included FilePath
file Options
opts = forall a. IO a -> a
unsafePerformIO forall a b. (a -> b) -> a -> b
$ do 
  [FilePath]
dirs <- OptionsStruct -> [FilePath]
include_paths forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. IORef a -> IO a
readIORef Options
opts
  [FilePath]
files <- OptionsStruct -> [FilePath]
included_files forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. IORef a -> IO a
readIORef Options
opts
  [FilePath] -> FilePath -> IO [FilePath]
find_included_file [FilePath]
dirs FilePath
file forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    []        -> forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
    (FilePath
file:[FilePath]
_)  -> forall (m :: * -> *) a. Monad m => a -> m a
return (FilePath
file forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [FilePath]
files)

add_filepath :: FilePath -> Options -> IO ()
add_filepath :: FilePath -> Options -> IO ()
add_filepath FilePath
fp Options
opts = do forall a. IORef a -> (a -> a) -> IO ()
modifyIORef Options
opts (\OptionsStruct
os -> OptionsStruct
os { filepath :: Maybe FilePath
filepath = forall a. a -> Maybe a
Just FilePath
fp })

add_input :: [String] -> Options -> IO ()
add_input :: [FilePath] -> Options -> IO ()
add_input [FilePath]
ss Options
opts = forall a. IORef a -> (a -> a) -> IO ()
modifyIORef Options
opts (\OptionsStruct
os -> OptionsStruct
os { input :: [Bool]
input = forall a b. (a -> b) -> [a] -> [b]
map FilePath -> Bool
readAssignmentMaybe [FilePath]
ss })

consume_input :: Options -> IO (Maybe Bool)
consume_input :: Options -> IO (Maybe Bool)
consume_input Options
opts = do 
  OptionsStruct
optss <- forall a. IORef a -> IO a
readIORef Options
opts
  case OptionsStruct -> [Bool]
input OptionsStruct
optss of 
    [] -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
    [Bool]
bs -> do forall a. IORef a -> (a -> a) -> IO ()
modifyIORef Options
opts (\OptionsStruct
os -> OptionsStruct
os { input :: [Bool]
input = forall a. [a] -> [a]
tail [Bool]
bs }) 
             forall (m :: * -> *) a. Monad m => a -> m a
return (forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a. [a] -> a
head [Bool]
bs)

readAssignmentMaybe :: String -> Bool
readAssignmentMaybe :: FilePath -> Bool
readAssignmentMaybe FilePath
s = case FilePath
s of
                FilePath
"True"  -> Bool
True 
                FilePath
"true"  -> Bool
True 
                FilePath
"t"     -> Bool
True 
                FilePath
"T"     -> Bool
True 
                FilePath
"y"     -> Bool
True 
                FilePath
"Y"     -> Bool
True 
                FilePath
"False" -> Bool
False
                FilePath
"false" -> Bool
False 
                FilePath
"f"     -> Bool
False 
                FilePath
"F"     -> Bool
False 
                FilePath
"N"     -> Bool
False 
                FilePath
"n"     -> Bool
False 
                FilePath
_       -> Bool
False

verbosity :: Options -> Level -> IO () -> IO ()
verbosity :: Options -> Level -> IO () -> IO ()
verbosity Options
opts Level
loc_level IO ()
m = do 
  Level
limit <- OptionsStruct -> Level
limitM forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. IORef a -> IO a
readIORef Options
opts
  forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Level
loc_level forall a. Ord a => a -> a -> Bool
<= Level
limit) IO ()
m
  where limitM :: OptionsStruct -> Level
limitM OptionsStruct
opts  | OptionsStruct -> Bool
debug     OptionsStruct
opts  = Level
Verbose
                     | OptionsStruct -> Bool
test_mode OptionsStruct
opts  = Level
TestMode
                     | Bool
otherwise       = Level
Default

data Level = TestMode | Default | Verbose deriving (Eq Level
Level -> Level -> Bool
Level -> Level -> Ordering
Level -> Level -> Level
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Level -> Level -> Level
$cmin :: Level -> Level -> Level
max :: Level -> Level -> Level
$cmax :: Level -> Level -> Level
>= :: Level -> Level -> Bool
$c>= :: Level -> Level -> Bool
> :: Level -> Level -> Bool
$c> :: Level -> Level -> Bool
<= :: Level -> Level -> Bool
$c<= :: Level -> Level -> Bool
< :: Level -> Level -> Bool
$c< :: Level -> Level -> Bool
compare :: Level -> Level -> Ordering
$ccompare :: Level -> Level -> Ordering
Ord, Int -> Level
Level -> Int
Level -> [Level]
Level -> Level
Level -> Level -> [Level]
Level -> Level -> Level -> [Level]
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: Level -> Level -> Level -> [Level]
$cenumFromThenTo :: Level -> Level -> Level -> [Level]
enumFromTo :: Level -> Level -> [Level]
$cenumFromTo :: Level -> Level -> [Level]
enumFromThen :: Level -> Level -> [Level]
$cenumFromThen :: Level -> Level -> [Level]
enumFrom :: Level -> [Level]
$cenumFrom :: Level -> [Level]
fromEnum :: Level -> Int
$cfromEnum :: Level -> Int
toEnum :: Int -> Level
$ctoEnum :: Int -> Level
pred :: Level -> Level
$cpred :: Level -> Level
succ :: Level -> Level
$csucc :: Level -> Level
Enum, Level -> Level -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Level -> Level -> Bool
$c/= :: Level -> Level -> Bool
== :: Level -> Level -> Bool
$c== :: Level -> Level -> Bool
Eq)