module Network.URI.XDG.Ini(INI, parseIni, iniLookup, iniLookupLocalized) where

import Data.Char (isSpace, toLower)
import Data.List (dropWhile, dropWhileEnd)

type INI = [(String, [(String, String)])]

parseIni :: String -> INI
parseIni :: String -> INI
parseIni String
source = [String] -> INI
parseIni' ([String] -> INI) -> [String] -> INI
forall a b. (a -> b) -> a -> b
$ (String -> Bool) -> [String] -> [String]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (String -> Bool) -> String -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Bool
isComment) ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map String -> String
strip ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ String -> [String]
lines String
source

strip :: String -> String
strip String
cs = (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
dropWhile Char -> Bool
isSpace (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
dropWhileEnd Char -> Bool
isSpace (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower String
cs
strip2 :: (String, String) -> (String, String)
strip2 (String
a, String
b) = (String -> String
strip String
a, String -> String
strip String
b)

isComment :: String -> Bool
isComment (Char
'#':String
_) = Bool
True
isComment String
"" = Bool
True
isComment String
_ = Bool
False

parseIni' :: [String] -> INI
parseIni' ((Char
'[':String
cs):[String]
lines) | Char
']':String
header <- String -> String
forall a. [a] -> [a]
reverse String
cs =
    let ([(String, String)]
keys, [String]
rest) = [String] -> ([(String, String)], [String])
parseKeys [String]
lines in (String -> String
strip (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ String -> String
forall a. [a] -> [a]
reverse String
header, [(String, String)]
keys) (String, [(String, String)]) -> INI -> INI
forall a. a -> [a] -> [a]
: [String] -> INI
parseIni' [String]
rest
parseIni' [String]
_ = []

parseKeys :: [String] -> ([(String, String)], [String])
parseKeys :: [String] -> ([(String, String)], [String])
parseKeys lines :: [String]
lines@((Char
'[':String
_):[String]
_) = ([], [String]
lines)
parseKeys (String
line:[String]
lines) =
    let ([(String, String)]
keys, [String]
rest) = [String] -> ([(String, String)], [String])
parseKeys [String]
lines in ((String, String) -> (String, String)
strip2 (String -> (String, String)
parseKey String
line) (String, String) -> [(String, String)] -> [(String, String)]
forall a. a -> [a] -> [a]
: [(String, String)]
keys, [String]
rest)
parseKeys [] = ([], [])

parseKey :: String -> (String, String)
parseKey (Char
'=':String
as) = ([], String
as)
parseKey (Char
a:String
as) = let (String
x, String
y) = String -> (String, String)
parseKey String
as in (Char
aChar -> String -> String
forall a. a -> [a] -> [a]
:String
x, String
y)
parseKey [] = ([], [])

---

iniLookup :: String -> String -> INI -> Maybe String
iniLookup :: String -> String -> INI -> Maybe String
iniLookup String
group String
key INI
ini = String -> INI -> Maybe [(String, String)]
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup String
group INI
ini Maybe [(String, String)]
-> ([(String, String)] -> Maybe String) -> Maybe String
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= String -> [(String, String)] -> Maybe String
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup String
key

iniLookupLocalized :: [String] -> String -> String -> INI -> Maybe String
iniLookupLocalized :: [String] -> String -> String -> INI -> Maybe String
iniLookupLocalized (String
locale:[String]
locales) String
group String
key INI
ini
    | Just String
ret <- String -> String -> INI -> Maybe String
iniLookup String
group (String
key String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"[" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
locale' String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"]") INI
ini = String -> Maybe String
forall a. a -> Maybe a
Just String
ret
    | Bool
otherwise = [String] -> String -> String -> INI -> Maybe String
iniLookupLocalized [String]
locales String
group String
key INI
ini
    where locale' :: String
locale' = (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
dash2under String
locale
iniLookupLocalized [] String
group String
key INI
ini = String -> String -> INI -> Maybe String
iniLookup String
group String
key INI
ini

dash2under :: Char -> Char
dash2under Char
'-' = Char
'_'
dash2under Char
c = Char
c