module HsKu.Config where

import Data.List
import Data.Maybe
import Data.Map (Map, assocs, fromList)
import Text.ParserCombinators.ReadP
import System.Environment

type    Config  = Map String (Map String String)
newtype Ini     = Ini {Ini -> Config
sections :: Config} deriving Ini -> Ini -> Bool
(Ini -> Ini -> Bool) -> (Ini -> Ini -> Bool) -> Eq Ini
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Ini -> Ini -> Bool
== :: Ini -> Ini -> Bool
$c/= :: Ini -> Ini -> Bool
/= :: Ini -> Ini -> Bool
Eq

instance Show Ini where
  show :: Ini -> String
show = [String] -> String
unlines ([String] -> String) -> (Ini -> [String]) -> Ini -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((String, Map String String) -> String)
-> [(String, Map String String)] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String, Map String String) -> String
section ([(String, Map String String)] -> [String])
-> (Ini -> [(String, Map String String)]) -> Ini -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Config -> [(String, Map String String)]
forall k a. Map k a -> [(k, a)]
assocs (Config -> [(String, Map String String)])
-> (Ini -> Config) -> Ini -> [(String, Map String String)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ini -> Config
sections
    where section :: (String, Map String String) -> String
section (String
name, Map String String
sec) = String
"[" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
name String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"]\n" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Map String String -> String
pairs Map String String
sec
          pairs :: Map String String -> String
pairs               = [String] -> String
unlines ([String] -> String)
-> (Map String String -> [String]) -> Map String String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((String, String) -> String) -> [(String, String)] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String, String) -> String
pair ([(String, String)] -> [String])
-> (Map String String -> [(String, String)])
-> Map String String
-> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map String String -> [(String, String)]
forall k a. Map k a -> [(k, a)]
assocs
          pair :: (String, String) -> String
pair (String
k, String
v)         = String
k String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" = " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
v

instance Read Ini where
  readsPrec :: Int -> ReadS Ini
readsPrec Int
_ = ReadP Ini -> ReadS Ini
forall a. ReadP a -> ReadS a
readP_to_S ReadP Ini
parser
    where parser :: ReadP Ini
parser  = Config -> Ini
Ini (Config -> Ini)
-> ([(String, Map String String)] -> Config)
-> [(String, Map String String)]
-> Ini
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(String, Map String String)] -> Config
forall k a. Ord k => [(k, a)] -> Map k a
fromList ([(String, Map String String)] -> Ini)
-> ReadP [(String, Map String String)] -> ReadP Ini
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ReadP (String, Map String String)
-> ReadP [(String, Map String String)]
forall a. ReadP a -> ReadP [a]
many ReadP (String, Map String String)
section
          section :: ReadP (String, Map String String)
section = do  String
name  <- ShowS
trim ShowS -> ReadP String -> ReadP String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ReadP Char -> ReadP String -> ReadP String -> ReadP String
forall open close a.
ReadP open -> ReadP close -> ReadP a -> ReadP a
between (Char -> ReadP Char
char Char
'[')
                                                  (Char -> ReadP Char
char Char
']' ReadP Char -> ReadP String -> ReadP String
forall a b. ReadP a -> ReadP b -> ReadP b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ReadP String
nls)
                                                  (String -> ReadP String
no String
"=\n]")
                        [(String, String)]
pairs <- ReadP (String, String) -> ReadP [(String, String)]
forall a. ReadP a -> ReadP [a]
many ReadP (String, String)
pair
                        (String, Map String String) -> ReadP (String, Map String String)
forall a. a -> ReadP a
forall (m :: * -> *) a. Monad m => a -> m a
return (String
name, [(String, String)] -> Map String String
forall k a. Ord k => [(k, a)] -> Map k a
fromList [(String, String)]
pairs)
          pair :: ReadP (String, String)
pair    = do  String
key <- ShowS
trim ShowS -> ReadP String -> ReadP String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> ReadP String
no String
"\n[="
                        String
val <- ShowS
trim ShowS -> ReadP String -> ReadP String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ReadP Char -> ReadP String -> ReadP String -> ReadP String
forall open close a.
ReadP open -> ReadP close -> ReadP a -> ReadP a
between (Char -> ReadP Char
char Char
'=') ReadP String
nls (String -> ReadP String
no String
"\n")
                        (String, String) -> ReadP (String, String)
forall a. a -> ReadP a
forall (m :: * -> *) a. Monad m => a -> m a
return (String
key, String
val)
          nls :: ReadP String
nls     = (Char -> Bool) -> ReadP String
munch1 (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\n')
          no :: String -> ReadP String
no      = (Char -> Bool) -> ReadP String
munch1 ((Char -> Bool) -> ReadP String)
-> (String -> Char -> Bool) -> String -> ReadP String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> String -> Bool) -> String -> Char -> Bool
forall a b c. (a -> b -> c) -> b -> a -> c
flip Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem :: String -> ReadP String
          trim :: ShowS
trim    = (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
' ') ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
dropWhileEnd (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
' ')

loadConfig :: IO Config
loadConfig :: IO Config
loadConfig = do
  String
configFileName <- String -> Maybe String -> String
forall a. a -> Maybe a -> a
fromMaybe String
"config.ini" (Maybe String -> String) -> IO (Maybe String) -> IO String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO (Maybe String)
lookupEnv String
"HSKU_CONFIG_FILE"
  Ini -> Config
sections (Ini -> Config) -> (String -> Ini) -> String -> Config
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Ini
forall a. Read a => String -> a
read (String -> Config) -> IO String -> IO Config
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO String
readFile String
configFileName