{-# LANGUAGE CPP, PatternGuards #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  Plugins.Monitors.Files
-- Copyright   :  (c) Juraj Hercek
-- License     :  BSD-style (see LICENSE)
--
-- Maintainer  :  Juraj Hercek <juhe_haskell@hck.sk>
-- Stability   :  unstable
-- Portability :  unportable
--
-- Specialized helpers to access files and their contents
--
-----------------------------------------------------------------------------

module Xmobar.Plugins.Monitors.Common.Files ( checkedDataRetrieval
                                            , checkedDataRead)
where

#if __GLASGOW_HASKELL__ < 800
import Control.Applicative
#endif

import Data.Char hiding (Space)
import Data.Function
import Data.List
import Data.Maybe
import System.Directory

import Xmobar.Plugins.Monitors.Common.Types
import Xmobar.Plugins.Monitors.Common.Parsers
import Xmobar.Plugins.Monitors.Common.Output

checkedDataRetrieval :: (Ord a, Num a)
                     => String -> [[String]] -> Maybe (String, String -> Int)
                     -> (Double -> a) -> (a -> String) -> Monitor String
checkedDataRetrieval :: forall a.
(Ord a, Num a) =>
[Char]
-> [[[Char]]]
-> Maybe ([Char], [Char] -> Int)
-> (Double -> a)
-> (a -> [Char])
-> Monitor [Char]
checkedDataRetrieval [Char]
msg [[[Char]]]
paths Maybe ([Char], [Char] -> Int)
lbl Double -> a
trans a -> [Char]
fmt =
  ([Maybe [Char]] -> [Char])
-> ReaderT MConfig IO [Maybe [Char]] -> Monitor [Char]
forall a b.
(a -> b) -> ReaderT MConfig IO a -> ReaderT MConfig IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([Char] -> Maybe [Char] -> [Char]
forall a. a -> Maybe a -> a
fromMaybe [Char]
msg (Maybe [Char] -> [Char])
-> ([Maybe [Char]] -> Maybe [Char]) -> [Maybe [Char]] -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[Char]] -> Maybe [Char]
forall a. [a] -> Maybe a
listToMaybe ([[Char]] -> Maybe [Char])
-> ([Maybe [Char]] -> [[Char]]) -> [Maybe [Char]] -> Maybe [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Maybe [Char]] -> [[Char]]
forall a. [Maybe a] -> [a]
catMaybes) (ReaderT MConfig IO [Maybe [Char]] -> Monitor [Char])
-> ReaderT MConfig IO [Maybe [Char]] -> Monitor [Char]
forall a b. (a -> b) -> a -> b
$
    ([[Char]] -> ReaderT MConfig IO (Maybe [Char]))
-> [[[Char]]] -> ReaderT MConfig IO [Maybe [Char]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM (\[[Char]]
p -> [[Char]]
-> Maybe ([Char], [Char] -> Int)
-> (Double -> a)
-> (a -> [Char])
-> ReaderT MConfig IO (Maybe [Char])
forall a.
(Ord a, Num a) =>
[[Char]]
-> Maybe ([Char], [Char] -> Int)
-> (Double -> a)
-> (a -> [Char])
-> ReaderT MConfig IO (Maybe [Char])
retrieveData [[Char]]
p Maybe ([Char], [Char] -> Int)
lbl Double -> a
trans a -> [Char]
fmt) [[[Char]]]
paths

retrieveData :: (Ord a, Num a)
             => [String] -> Maybe (String, String -> Int)
             -> (Double -> a) -> (a -> String) -> Monitor (Maybe String)
retrieveData :: forall a.
(Ord a, Num a) =>
[[Char]]
-> Maybe ([Char], [Char] -> Int)
-> (Double -> a)
-> (a -> [Char])
-> ReaderT MConfig IO (Maybe [Char])
retrieveData [[Char]]
path Maybe ([Char], [Char] -> Int)
lbl Double -> a
trans a -> [Char]
fmt = do
  pairs <- ((Int, [Char]) -> [Char]) -> [(Int, [Char])] -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
map (Int, [Char]) -> [Char]
forall a b. (a, b) -> b
snd ([(Int, [Char])] -> [[Char]])
-> ([(Int, [Char])] -> [(Int, [Char])])
-> [(Int, [Char])]
-> [[Char]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Int, [Char]) -> (Int, [Char]) -> Ordering)
-> [(Int, [Char])] -> [(Int, [Char])]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Int -> Int -> Ordering)
-> ((Int, [Char]) -> Int)
-> (Int, [Char])
-> (Int, [Char])
-> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` (Int, [Char]) -> Int
forall a b. (a, b) -> a
fst) ([(Int, [Char])] -> [[Char]])
-> ReaderT MConfig IO [(Int, [Char])]
-> ReaderT MConfig IO [[Char]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
             ((([Char], Either Int ([Char], [Char] -> Int))
 -> ReaderT MConfig IO (Int, [Char]))
-> [([Char], Either Int ([Char], [Char] -> Int))]
-> ReaderT MConfig IO [(Int, [Char])]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM ([Char], Either Int ([Char], [Char] -> Int))
-> ReaderT MConfig IO (Int, [Char])
readFiles ([([Char], Either Int ([Char], [Char] -> Int))]
 -> ReaderT MConfig IO [(Int, [Char])])
-> ReaderT
     MConfig IO [([Char], Either Int ([Char], [Char] -> Int))]
-> ReaderT MConfig IO [(Int, [Char])]
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< [[Char]]
-> Maybe ([Char], [Char] -> Int)
-> ReaderT
     MConfig IO [([Char], Either Int ([Char], [Char] -> Int))]
findFilesAndLabel [[Char]]
path Maybe ([Char], [Char] -> Int)
lbl)
  if null pairs
    then return Nothing
    else Just <$> (     parseTemplate
                    =<< mapM (showWithColors fmt . trans . read) pairs
                  )

checkedDataRead :: [[String]] -> Monitor [Double]
checkedDataRead :: [[[Char]]] -> Monitor [Double]
checkedDataRead [[[Char]]]
paths = [[Double]] -> [Double]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[Double]] -> [Double])
-> ReaderT MConfig IO [[Double]] -> Monitor [Double]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ([[Char]] -> Monitor [Double])
-> [[[Char]]] -> ReaderT MConfig IO [[Double]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM [[Char]] -> Monitor [Double]
forall {b}. Read b => [[Char]] -> ReaderT MConfig IO [b]
readData [[[Char]]]
paths
  where readData :: [[Char]] -> ReaderT MConfig IO [b]
readData [[Char]]
path = ((Int, [Char]) -> b) -> [(Int, [Char])] -> [b]
forall a b. (a -> b) -> [a] -> [b]
map ([Char] -> b
forall a. Read a => [Char] -> a
read ([Char] -> b) -> ((Int, [Char]) -> [Char]) -> (Int, [Char]) -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int, [Char]) -> [Char]
forall a b. (a, b) -> b
snd) ([(Int, [Char])] -> [b])
-> ([(Int, [Char])] -> [(Int, [Char])]) -> [(Int, [Char])] -> [b]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Int, [Char]) -> (Int, [Char]) -> Ordering)
-> [(Int, [Char])] -> [(Int, [Char])]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Int -> Int -> Ordering)
-> ((Int, [Char]) -> Int)
-> (Int, [Char])
-> (Int, [Char])
-> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` (Int, [Char]) -> Int
forall a b. (a, b) -> a
fst) ([(Int, [Char])] -> [b])
-> ReaderT MConfig IO [(Int, [Char])] -> ReaderT MConfig IO [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
                         ((([Char], Either Int ([Char], [Char] -> Int))
 -> ReaderT MConfig IO (Int, [Char]))
-> [([Char], Either Int ([Char], [Char] -> Int))]
-> ReaderT MConfig IO [(Int, [Char])]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM ([Char], Either Int ([Char], [Char] -> Int))
-> ReaderT MConfig IO (Int, [Char])
readFiles ([([Char], Either Int ([Char], [Char] -> Int))]
 -> ReaderT MConfig IO [(Int, [Char])])
-> ReaderT
     MConfig IO [([Char], Either Int ([Char], [Char] -> Int))]
-> ReaderT MConfig IO [(Int, [Char])]
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< [[Char]]
-> Maybe ([Char], [Char] -> Int)
-> ReaderT
     MConfig IO [([Char], Either Int ([Char], [Char] -> Int))]
findFilesAndLabel [[Char]]
path Maybe ([Char], [Char] -> Int)
forall a. Maybe a
Nothing)

-- | Represents the different types of path components
data Comp = Fix String
          | Var [String]
          deriving Int -> Comp -> ShowS
[Comp] -> ShowS
Comp -> [Char]
(Int -> Comp -> ShowS)
-> (Comp -> [Char]) -> ([Comp] -> ShowS) -> Show Comp
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Comp -> ShowS
showsPrec :: Int -> Comp -> ShowS
$cshow :: Comp -> [Char]
show :: Comp -> [Char]
$cshowList :: [Comp] -> ShowS
showList :: [Comp] -> ShowS
Show

-- | Used to represent parts of file names separated by slashes and spaces
data CompOrSep = Slash
               | Space
               | Comp String
               deriving (CompOrSep -> CompOrSep -> Bool
(CompOrSep -> CompOrSep -> Bool)
-> (CompOrSep -> CompOrSep -> Bool) -> Eq CompOrSep
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: CompOrSep -> CompOrSep -> Bool
== :: CompOrSep -> CompOrSep -> Bool
$c/= :: CompOrSep -> CompOrSep -> Bool
/= :: CompOrSep -> CompOrSep -> Bool
Eq, Int -> CompOrSep -> ShowS
[CompOrSep] -> ShowS
CompOrSep -> [Char]
(Int -> CompOrSep -> ShowS)
-> (CompOrSep -> [Char])
-> ([CompOrSep] -> ShowS)
-> Show CompOrSep
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> CompOrSep -> ShowS
showsPrec :: Int -> CompOrSep -> ShowS
$cshow :: CompOrSep -> [Char]
show :: CompOrSep -> [Char]
$cshowList :: [CompOrSep] -> ShowS
showList :: [CompOrSep] -> ShowS
Show)

-- | Function to turn a list of of strings into a list of path components
pathComponents :: [String] -> [Comp]
pathComponents :: [[Char]] -> [Comp]
pathComponents = [CompOrSep] -> [Comp]
joinComps ([CompOrSep] -> [Comp])
-> ([[Char]] -> [CompOrSep]) -> [[Char]] -> [Comp]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [CompOrSep] -> [CompOrSep]
forall a. Int -> [a] -> [a]
drop Int
2 ([CompOrSep] -> [CompOrSep])
-> ([[Char]] -> [CompOrSep]) -> [[Char]] -> [CompOrSep]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [CompOrSep] -> [[CompOrSep]] -> [CompOrSep]
forall a. [a] -> [[a]] -> [a]
intercalate [CompOrSep
Space] ([[CompOrSep]] -> [CompOrSep])
-> ([[Char]] -> [[CompOrSep]]) -> [[Char]] -> [CompOrSep]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Char] -> [CompOrSep]) -> [[Char]] -> [[CompOrSep]]
forall a b. (a -> b) -> [a] -> [b]
map [Char] -> [CompOrSep]
splitParts
  where
    splitParts :: [Char] -> [CompOrSep]
splitParts [Char]
p | ([Char]
l, Char
_:[Char]
r) <- (Char -> Bool) -> [Char] -> ([Char], [Char])
forall a. (a -> Bool) -> [a] -> ([a], [a])
break (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'/') [Char]
p = [Char] -> CompOrSep
Comp [Char]
l CompOrSep -> [CompOrSep] -> [CompOrSep]
forall a. a -> [a] -> [a]
: CompOrSep
Slash CompOrSep -> [CompOrSep] -> [CompOrSep]
forall a. a -> [a] -> [a]
: [Char] -> [CompOrSep]
splitParts [Char]
r
                 | Bool
otherwise                    = [[Char] -> CompOrSep
Comp [Char]
p]

    joinComps :: [CompOrSep] -> [Comp]
joinComps = ([CompOrSep] -> [CompOrSep] -> [Comp])
-> ([CompOrSep], [CompOrSep]) -> [Comp]
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry [CompOrSep] -> [CompOrSep] -> [Comp]
joinComps' (([CompOrSep], [CompOrSep]) -> [Comp])
-> ([CompOrSep] -> ([CompOrSep], [CompOrSep]))
-> [CompOrSep]
-> [Comp]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (CompOrSep -> Bool) -> [CompOrSep] -> ([CompOrSep], [CompOrSep])
forall a. (a -> Bool) -> [a] -> ([a], [a])
partition CompOrSep -> Bool
isComp

    isComp :: CompOrSep -> Bool
isComp (Comp [Char]
_) = Bool
True
    isComp CompOrSep
_        = Bool
False

    fromComp :: CompOrSep -> [Char]
fromComp (Comp [Char]
s) = [Char]
s
    fromComp CompOrSep
_        = ShowS
forall a. HasCallStack => [Char] -> a
error [Char]
"fromComp applied to value other than (Comp _)"

    joinComps' :: [CompOrSep] -> [CompOrSep] -> [Comp]
joinComps' [CompOrSep]
cs []     = [[Char] -> Comp
Fix ([Char] -> Comp) -> [Char] -> Comp
forall a b. (a -> b) -> a -> b
$ CompOrSep -> [Char]
fromComp (CompOrSep -> [Char]) -> CompOrSep -> [Char]
forall a b. (a -> b) -> a -> b
$ [CompOrSep] -> CompOrSep
forall a. HasCallStack => [a] -> a
head [CompOrSep]
cs] -- cs should have only one element here,
                                                      -- but this keeps the pattern matching
                                                      -- exhaustive
    joinComps' [CompOrSep]
cs (CompOrSep
p:[CompOrSep]
ps) = let ([CompOrSep]
ss, [CompOrSep]
ps') = (CompOrSep -> Bool) -> [CompOrSep] -> ([CompOrSep], [CompOrSep])
forall a. (a -> Bool) -> [a] -> ([a], [a])
span (CompOrSep -> CompOrSep -> Bool
forall a. Eq a => a -> a -> Bool
== CompOrSep
p) [CompOrSep]
ps
                               ct :: Int
ct        = if [CompOrSep] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [CompOrSep]
ps' Bool -> Bool -> Bool
|| (CompOrSep
p CompOrSep -> CompOrSep -> Bool
forall a. Eq a => a -> a -> Bool
== CompOrSep
Space) then [CompOrSep] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [CompOrSep]
ss Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
                                                                       else [CompOrSep] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [CompOrSep]
ss
                               ([CompOrSep]
ls, [CompOrSep]
rs)  = Int -> [CompOrSep] -> ([CompOrSep], [CompOrSep])
forall a. Int -> [a] -> ([a], [a])
splitAt (Int
ctInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) [CompOrSep]
cs
                               c :: Comp
c         = case CompOrSep
p of
                                             CompOrSep
Space -> [[Char]] -> Comp
Var ([[Char]] -> Comp) -> [[Char]] -> Comp
forall a b. (a -> b) -> a -> b
$ (CompOrSep -> [Char]) -> [CompOrSep] -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
map CompOrSep -> [Char]
fromComp [CompOrSep]
ls
                                             CompOrSep
Slash -> [Char] -> Comp
Fix ([Char] -> Comp) -> [Char] -> Comp
forall a b. (a -> b) -> a -> b
$ [Char] -> [[Char]] -> [Char]
forall a. [a] -> [[a]] -> [a]
intercalate [Char]
"/" ([[Char]] -> [Char]) -> [[Char]] -> [Char]
forall a b. (a -> b) -> a -> b
$ (CompOrSep -> [Char]) -> [CompOrSep] -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
map CompOrSep -> [Char]
fromComp [CompOrSep]
ls
                                             CompOrSep
_     -> [Char] -> Comp
forall a. HasCallStack => [Char] -> a
error [Char]
"Should not happen"
                           in  if [CompOrSep] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [CompOrSep]
ps' then [Comp
c]
                                           else Comp
cComp -> [Comp] -> [Comp]
forall a. a -> [a] -> [a]
:[CompOrSep] -> [CompOrSep] -> [Comp]
joinComps' [CompOrSep]
rs (Int -> [CompOrSep] -> [CompOrSep]
forall a. Int -> [a] -> [a]
drop Int
ct [CompOrSep]
ps)

-- | Function to find all files matching the given path and possible label file.
-- The path must be absolute (start with a leading slash).
findFilesAndLabel :: [String] -> Maybe (String, String -> Int)
          -> Monitor [(String, Either Int (String, String -> Int))]
findFilesAndLabel :: [[Char]]
-> Maybe ([Char], [Char] -> Int)
-> ReaderT
     MConfig IO [([Char], Either Int ([Char], [Char] -> Int))]
findFilesAndLabel [[Char]]
path Maybe ([Char], [Char] -> Int)
lbl  =  [Maybe ([Char], Either Int ([Char], [Char] -> Int))]
-> [([Char], Either Int ([Char], [Char] -> Int))]
forall a. [Maybe a] -> [a]
catMaybes
                   ([Maybe ([Char], Either Int ([Char], [Char] -> Int))]
 -> [([Char], Either Int ([Char], [Char] -> Int))])
-> ReaderT
     MConfig IO [Maybe ([Char], Either Int ([Char], [Char] -> Int))]
-> ReaderT
     MConfig IO [([Char], Either Int ([Char], [Char] -> Int))]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (     ((Int, [Char])
 -> ReaderT
      MConfig IO (Maybe ([Char], Either Int ([Char], [Char] -> Int))))
-> [(Int, [Char])]
-> ReaderT
     MConfig IO [Maybe ([Char], Either Int ([Char], [Char] -> Int))]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM (Int, [Char])
-> ReaderT
     MConfig IO (Maybe ([Char], Either Int ([Char], [Char] -> Int)))
forall {a}.
(a, [Char])
-> ReaderT
     MConfig IO (Maybe ([Char], Either a ([Char], [Char] -> Int)))
addLabel ([(Int, [Char])]
 -> ReaderT
      MConfig IO [Maybe ([Char], Either Int ([Char], [Char] -> Int))])
-> ([[Char]] -> [(Int, [Char])])
-> [[Char]]
-> ReaderT
     MConfig IO [Maybe ([Char], Either Int ([Char], [Char] -> Int))]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Int] -> [[Char]] -> [(Int, [Char])]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int
0..] ([[Char]] -> [(Int, [Char])])
-> ([[Char]] -> [[Char]]) -> [[Char]] -> [(Int, [Char])]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[Char]] -> [[Char]]
forall a. Ord a => [a] -> [a]
sort
                         ([[Char]]
 -> ReaderT
      MConfig IO [Maybe ([Char], Either Int ([Char], [Char] -> Int))])
-> ReaderT MConfig IO [[Char]]
-> ReaderT
     MConfig IO [Maybe ([Char], Either Int ([Char], [Char] -> Int))]
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< [Comp] -> [Char] -> ReaderT MConfig IO [[Char]]
recFindFiles ([[Char]] -> [Comp]
pathComponents [[Char]]
path) [Char]
"/"
                       )
  where
    addLabel :: (a, [Char])
-> ReaderT
     MConfig IO (Maybe ([Char], Either a ([Char], [Char] -> Int)))
addLabel (a
i, [Char]
f) = ReaderT
  MConfig IO (Maybe ([Char], Either a ([Char], [Char] -> Int)))
-> (([Char], [Char] -> Int)
    -> ReaderT
         MConfig IO (Maybe ([Char], Either a ([Char], [Char] -> Int))))
-> Maybe ([Char], [Char] -> Int)
-> ReaderT
     MConfig IO (Maybe ([Char], Either a ([Char], [Char] -> Int)))
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Maybe ([Char], Either a ([Char], [Char] -> Int))
-> ReaderT
     MConfig IO (Maybe ([Char], Either a ([Char], [Char] -> Int)))
forall a. a -> ReaderT MConfig IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe ([Char], Either a ([Char], [Char] -> Int))
 -> ReaderT
      MConfig IO (Maybe ([Char], Either a ([Char], [Char] -> Int))))
-> Maybe ([Char], Either a ([Char], [Char] -> Int))
-> ReaderT
     MConfig IO (Maybe ([Char], Either a ([Char], [Char] -> Int)))
forall a b. (a -> b) -> a -> b
$ ([Char], Either a ([Char], [Char] -> Int))
-> Maybe ([Char], Either a ([Char], [Char] -> Int))
forall a. a -> Maybe a
Just ([Char]
f, a -> Either a ([Char], [Char] -> Int)
forall a b. a -> Either a b
Left a
i))
                            (([Char]
 -> ([Char] -> Int)
 -> ReaderT
      MConfig IO (Maybe ([Char], Either a ([Char], [Char] -> Int))))
-> ([Char], [Char] -> Int)
-> ReaderT
     MConfig IO (Maybe ([Char], Either a ([Char], [Char] -> Int)))
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry ([Char]
-> [Char]
-> ([Char] -> Int)
-> ReaderT
     MConfig IO (Maybe ([Char], Either a ([Char], [Char] -> Int)))
forall {b} {a}.
[Char]
-> [Char]
-> b
-> ReaderT MConfig IO (Maybe ([Char], Either a ([Char], b)))
justIfExists [Char]
f))
                            Maybe ([Char], [Char] -> Int)
lbl

    justIfExists :: [Char]
-> [Char]
-> b
-> ReaderT MConfig IO (Maybe ([Char], Either a ([Char], b)))
justIfExists [Char]
f [Char]
s b
t = let f' :: [Char]
f' = Int -> ShowS
forall a. Int -> [a] -> [a]
take ([Char] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Char]
f Int -> Int -> Int
forall a. Num a => a -> a -> a
- [Char] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Char]
s) [Char]
f [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ [Char]
s
                         in  Maybe ([Char], Either a ([Char], b))
-> Maybe ([Char], Either a ([Char], b))
-> Bool
-> Maybe ([Char], Either a ([Char], b))
forall a. a -> a -> Bool -> a
ifthen (([Char], Either a ([Char], b))
-> Maybe ([Char], Either a ([Char], b))
forall a. a -> Maybe a
Just ([Char]
f, ([Char], b) -> Either a ([Char], b)
forall a b. b -> Either a b
Right ([Char]
f', b
t))) Maybe ([Char], Either a ([Char], b))
forall a. Maybe a
Nothing (Bool -> Maybe ([Char], Either a ([Char], b)))
-> ReaderT MConfig IO Bool
-> ReaderT MConfig IO (Maybe ([Char], Either a ([Char], b)))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO Bool -> ReaderT MConfig IO Bool
forall a. IO a -> Monitor a
io ([Char] -> IO Bool
doesFileExist [Char]
f')

    recFindFiles :: [Comp] -> [Char] -> ReaderT MConfig IO [[Char]]
recFindFiles [] [Char]
d  =  [[Char]] -> [[Char]] -> Bool -> [[Char]]
forall a. a -> a -> Bool -> a
ifthen [[Char]
d] []
                      (Bool -> [[Char]])
-> ReaderT MConfig IO Bool -> ReaderT MConfig IO [[Char]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO Bool -> ReaderT MConfig IO Bool
forall a. IO a -> Monitor a
io (if [Char] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Char]
d then Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False else [Char] -> IO Bool
doesFileExist [Char]
d)
    recFindFiles [Comp]
ps [Char]
d  =  ReaderT MConfig IO [[Char]]
-> ReaderT MConfig IO [[Char]]
-> Bool
-> ReaderT MConfig IO [[Char]]
forall a. a -> a -> Bool -> a
ifthen ([Comp] -> [Char] -> ReaderT MConfig IO [[Char]]
recFindFiles' [Comp]
ps [Char]
d) ([[Char]] -> ReaderT MConfig IO [[Char]]
forall a. a -> ReaderT MConfig IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [])
                      (Bool -> ReaderT MConfig IO [[Char]])
-> ReaderT MConfig IO Bool -> ReaderT MConfig IO [[Char]]
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO Bool -> ReaderT MConfig IO Bool
forall a. IO a -> Monitor a
io (if [Char] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Char]
d then Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True else [Char] -> IO Bool
doesDirectoryExist [Char]
d)

    recFindFiles' :: [Comp] -> [Char] -> ReaderT MConfig IO [[Char]]
recFindFiles' []         [Char]
_  =  [Char] -> ReaderT MConfig IO [[Char]]
forall a. HasCallStack => [Char] -> a
error [Char]
"Should not happen"
    recFindFiles' (Fix [Char]
p:[Comp]
ps) [Char]
d  =  [Comp] -> [Char] -> ReaderT MConfig IO [[Char]]
recFindFiles [Comp]
ps ([Char]
d [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ [Char]
"/" [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ [Char]
p)
    recFindFiles' (Var [[Char]]
p:[Comp]
ps) [Char]
d  =  [[[Char]]] -> [[Char]]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
                               ([[[Char]]] -> [[Char]])
-> ReaderT MConfig IO [[[Char]]] -> ReaderT MConfig IO [[Char]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ((([Char] -> ReaderT MConfig IO [[Char]])
-> [[Char]] -> ReaderT MConfig IO [[[Char]]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM ([Comp] -> [Char] -> ReaderT MConfig IO [[Char]]
recFindFiles [Comp]
ps
                                           ([Char] -> ReaderT MConfig IO [[Char]])
-> ShowS -> [Char] -> ReaderT MConfig IO [[Char]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (\[Char]
f -> [Char]
d [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ [Char]
"/" [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ [Char]
f))
                                      ([[Char]] -> ReaderT MConfig IO [[[Char]]])
-> ([[Char]] -> [[Char]])
-> [[Char]]
-> ReaderT MConfig IO [[[Char]]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Char] -> Bool) -> [[Char]] -> [[Char]]
forall a. (a -> Bool) -> [a] -> [a]
filter ([[Char]] -> [Char] -> Bool
matchesVar [[Char]]
p))
                                     ([[Char]] -> ReaderT MConfig IO [[[Char]]])
-> ReaderT MConfig IO [[Char]] -> ReaderT MConfig IO [[[Char]]]
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO [[Char]] -> ReaderT MConfig IO [[Char]]
forall a. IO a -> Monitor a
io ([Char] -> IO [[Char]]
getDirectoryContents [Char]
d)
                                   )

    matchesVar :: [[Char]] -> [Char] -> Bool
matchesVar []     [Char]
_  = Bool
False
    matchesVar [[Char]
v]    [Char]
f  = [Char]
v [Char] -> [Char] -> Bool
forall a. Eq a => a -> a -> Bool
== [Char]
f
    matchesVar ([Char]
v:[[Char]]
vs) [Char]
f  = let f' :: [Char]
f'  = Int -> ShowS
forall a. Int -> [a] -> [a]
drop ([Char] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Char]
v) [Char]
f
                               f'' :: [Char]
f'' = (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
dropWhile Char -> Bool
isDigit [Char]
f'
                           in  [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
and [ [Char]
v [Char] -> [Char] -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` [Char]
f
                                   , Bool -> Bool
not ([Char] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Char]
f')
                                   , Char -> Bool
isDigit ([Char] -> Char
forall a. HasCallStack => [a] -> a
head [Char]
f')
                                   , [[Char]] -> [Char] -> Bool
matchesVar [[Char]]
vs [Char]
f''
                                   ]

-- | Function to read the contents of the given file(s)
readFiles :: (String, Either Int (String, String -> Int))
          -> Monitor (Int, String)
readFiles :: ([Char], Either Int ([Char], [Char] -> Int))
-> ReaderT MConfig IO (Int, [Char])
readFiles ([Char]
fval, Either Int ([Char], [Char] -> Int)
flbl) = (,) (Int -> [Char] -> (Int, [Char]))
-> ReaderT MConfig IO Int
-> ReaderT MConfig IO ([Char] -> (Int, [Char]))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Int -> ReaderT MConfig IO Int)
-> (([Char], [Char] -> Int) -> ReaderT MConfig IO Int)
-> Either Int ([Char], [Char] -> Int)
-> ReaderT MConfig IO Int
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either Int -> ReaderT MConfig IO Int
forall a. a -> ReaderT MConfig IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (\([Char]
f, [Char] -> Int
ex) -> ([Char] -> Int) -> Monitor [Char] -> ReaderT MConfig IO Int
forall a b.
(a -> b) -> ReaderT MConfig IO a -> ReaderT MConfig IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Char] -> Int
ex
                                                            (Monitor [Char] -> ReaderT MConfig IO Int)
-> Monitor [Char] -> ReaderT MConfig IO Int
forall a b. (a -> b) -> a -> b
$ IO [Char] -> Monitor [Char]
forall a. IO a -> Monitor a
io (IO [Char] -> Monitor [Char]) -> IO [Char] -> Monitor [Char]
forall a b. (a -> b) -> a -> b
$ [Char] -> IO [Char]
readFile [Char]
f) Either Int ([Char], [Char] -> Int)
flbl
                             ReaderT MConfig IO ([Char] -> (Int, [Char]))
-> Monitor [Char] -> ReaderT MConfig IO (Int, [Char])
forall a b.
ReaderT MConfig IO (a -> b)
-> ReaderT MConfig IO a -> ReaderT MConfig IO b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> IO [Char] -> Monitor [Char]
forall a. IO a -> Monitor a
io ([Char] -> IO [Char]
readFile [Char]
fval)

-- | Function that captures if-then-else
ifthen :: a -> a -> Bool -> a
ifthen :: forall a. a -> a -> Bool -> a
ifthen a
thn a
els Bool
cnd = if Bool
cnd then a
thn else a
els