-- |
-- Module    : Data.Ini
-- Copyright : 2011-2014 Magnus Therning
-- License   : BSD3
--
-- A representation of configuration options.  It consists of /sections/,
-- each which can contain 0 or more /options/.  Each options is a /key/,
-- /value/ pair.
--
-- This module contains the API for constructing, manipulating, and querying
-- configurations.
module Data.Ini where

-- {{{1 imports
import qualified Data.Map as M
import Data.Maybe

import Data.Ini.Types

-- {{{1 configurations
-- | Constructs an empty configuration.
emptyConfig :: Config
emptyConfig :: Config
emptyConfig = Config
forall k a. Map k a
M.empty

-- {{{1 sections
-- | Returns @True@ iff the configuration has a section with that name.
hasSection :: SectionName -> Config -> Bool
hasSection :: SectionName -> Config -> Bool
hasSection = SectionName -> Config -> Bool
forall k a. Ord k => k -> Map k a -> Bool
M.member

-- | Returns the section with the given name if it exists in the configuration.
getSection :: SectionName -> Config -> Maybe Section
getSection :: SectionName -> Config -> Maybe Section
getSection = SectionName -> Config -> Maybe Section
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup

-- | Returns a list of the names of all section.
sections :: Config -> [SectionName]
sections :: Config -> [SectionName]
sections = Config -> [SectionName]
forall k a. Map k a -> [k]
M.keys

-- | Removes the section if it exists.
delSection :: SectionName -> Config -> Config
delSection :: SectionName -> Config -> Config
delSection = SectionName -> Config -> Config
forall k a. Ord k => k -> Map k a -> Map k a
M.delete

-- {{{1 options
-- | Returns @True@ if the names section has the option.
hasOption :: SectionName -> OptionName -> Config -> Bool
hasOption :: SectionName -> SectionName -> Config -> Bool
hasOption sn :: SectionName
sn on :: SectionName
on cfg :: Config
cfg = Maybe SectionName -> Bool
forall a. Maybe a -> Bool
isJust (Maybe SectionName -> Bool) -> Maybe SectionName -> Bool
forall a b. (a -> b) -> a -> b
$ SectionName -> Config -> Maybe Section
getSection SectionName
sn Config
cfg Maybe Section
-> (Section -> Maybe SectionName) -> Maybe SectionName
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= SectionName -> Section -> Maybe SectionName
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup SectionName
on

-- | Returns the value of the option, if it exists.
getOption :: SectionName -> OptionName -> Config -> Maybe OptionValue
getOption :: SectionName -> SectionName -> Config -> Maybe SectionName
getOption sn :: SectionName
sn on :: SectionName
on cfg :: Config
cfg = SectionName -> Config -> Maybe Section
getSection SectionName
sn Config
cfg Maybe Section
-> (Section -> Maybe SectionName) -> Maybe SectionName
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= SectionName -> Section -> Maybe SectionName
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup SectionName
on

-- | Returns a list of all options in the section.
options ::  SectionName -> Config -> [OptionName]
options :: SectionName -> Config -> [SectionName]
options sn :: SectionName
sn cfg :: Config
cfg = [SectionName]
-> (Section -> [SectionName]) -> Maybe Section -> [SectionName]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] Section -> [SectionName]
forall k a. Map k a -> [k]
M.keys (SectionName -> Config -> Maybe Section
getSection SectionName
sn Config
cfg)

-- | Sets the value of the option, adding it if it doesn't exist.
setOption :: SectionName -> OptionName -> OptionValue -> Config -> Config
setOption :: SectionName -> SectionName -> SectionName -> Config -> Config
setOption sn :: SectionName
sn on :: SectionName
on ov :: SectionName
ov cfg :: Config
cfg = Config -> (Section -> Config) -> Maybe Section -> Config
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (SectionName -> Section -> Config -> Config
forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert SectionName
sn Section
new_s Config
cfg) (\ sec :: Section
sec -> SectionName -> Section -> Config -> Config
forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert SectionName
sn (SectionName -> SectionName -> Section -> Section
forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert SectionName
on SectionName
ov Section
sec) Config
cfg) Maybe Section
s
    where
        s :: Maybe Section
s = SectionName -> Config -> Maybe Section
getSection SectionName
sn Config
cfg
        new_s :: Section
new_s = SectionName -> SectionName -> Section -> Section
forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert SectionName
on SectionName
ov Section
forall k a. Map k a
M.empty

-- | Removes the option if it exists.  Empty sections are pruned.
delOption :: SectionName -> OptionName -> Config -> Config
delOption :: SectionName -> SectionName -> Config -> Config
delOption sn :: SectionName
sn on :: SectionName
on cfg :: Config
cfg = if Bool
sEmptyAfterDelete
        then SectionName -> Config -> Config
forall k a. Ord k => k -> Map k a -> Map k a
M.delete SectionName
sn Config
cfg
        else Config -> (Section -> Config) -> Maybe Section -> Config
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Config
cfg (\ sec :: Section
sec -> SectionName -> Section -> Config -> Config
forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert SectionName
sn (SectionName -> Section -> Section
forall k a. Ord k => k -> Map k a -> Map k a
M.delete SectionName
on Section
sec) Config
cfg) Maybe Section
s
    where
        s :: Maybe Section
s = SectionName -> Config -> Maybe Section
getSection SectionName
sn Config
cfg
        sEmptyAfterDelete :: Bool
sEmptyAfterDelete = Bool -> (Section -> Bool) -> Maybe Section -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
True (\ sec :: Section
sec -> Section
forall k a. Map k a
M.empty Section -> Section -> Bool
forall a. Eq a => a -> a -> Bool
== SectionName -> Section -> Section
forall k a. Ord k => k -> Map k a -> Map k a
M.delete SectionName
on Section
sec) Maybe Section
s

-- | Returns all options and their values of a section.
allItems :: SectionName -> Config -> [(OptionName, OptionValue)]
allItems :: SectionName -> Config -> [(SectionName, SectionName)]
allItems sn :: SectionName
sn cfg :: Config
cfg = [(SectionName, SectionName)]
-> (Section -> [(SectionName, SectionName)])
-> Maybe Section
-> [(SectionName, SectionName)]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] Section -> [(SectionName, SectionName)]
forall k a. Map k a -> [(k, a)]
M.toList (SectionName -> Config -> Maybe Section
getSection SectionName
sn Config
cfg)