-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/


-- | A library to manage application settings (INI file-like)
--   
--   A library to deal with application settings.
--   
--   This library deals with read-write application settings. You will have
--   to specify the settings that your application uses, their name, types
--   and default values.
--   
--   Setting types must implement the <a>Read</a> and <a>Show</a>
--   typeclasses.
--   
--   The settings are saved in a file in an INI-like key-value format
--   (without sections).
--   
--   Reading and updating settings is done in pure code, the IO monad is
--   only used to load settings and save them to disk. It is advised for
--   the user to create a module in your project holding settings handling.
--   
--   You can then declare settings:
--   
--   <pre>
--   fontSize :: Setting Double
--   fontSize = Setting "fontSize" 14
--   
--   dateFormat :: Setting String
--   dateFormat = Setting "dateFormat" "%x"
--   
--   backgroundColor :: Setting (Int, Int, Int)
--   backgroundColor = Setting "backcolor" (255, 0, 0)
--   </pre>
--   
--   Optionally you can declare the list of all your settings, in that case
--   the application will also save the default values in the configuration
--   file, but commented out:
--   
--   <pre>
--   fontSize=16
--   # dateFormat="%x"
--   # backcolor=(255,0,0)
--   </pre>
--   
--   If you do not specify the list of settings, only the first line would
--   be present in the configuration file.
--   
--   With an ordinary setting, one row in the configuration file means one
--   setting. That setting may of course be a list for instance. This setup
--   works very well for shorter lists like [1,2,3], however if you have a
--   list of more complex items, you will get very long lines and a
--   configuration file very difficult to edit by hand.
--   
--   For these special cases there is also the <a>ListSetting</a>
--   constructor:
--   
--   <pre>
--   testList :: Setting [String]
--   testList = ListSetting "testList" ["list1", "list2", "list3"]
--   </pre>
--   
--   Now the configuration file looks like that:
--   
--   <pre>
--   testList_1="list1"
--   testList_2="list2"
--   testList_3="list3"
--   </pre>
--   
--   Which is much more handy for big lists. An empty list is represented
--   like so:
--   
--   <pre>
--   testList=
--   </pre>
--   
--   There is also another technique that you can use if you have too long
--   lines: you can put line breaks in the setting values if you start the
--   following lines with a leading space, like so:
--   
--   <pre>
--   testList=["list1",
--    "list2", "list3"]
--   </pre>
--   
--   In that case don't use the ListSetting option. Any character after the
--   the leading space in the next lines will go in the setting value. Note
--   that the library will automatically wrap setting values longer than 80
--   characters when saving.
--   
--   Once we declared the settings, we can read the configuration from disk
--   (and your settings module should export your wrapper around the
--   function offered by this library):
--   
--   <pre>
--   readResult &lt;- try $ readSettings (AutoFromAppName "test")
--   case readResult of
--   	Right (conf, GetSetting getSetting) -&gt; do
--   		let textSize = getSetting fontSize
--   		saveSettings emptyDefaultConfig (AutoFromAppName "test") conf
--   	Left (x :: SomeException) -&gt; error "Error reading the config file!"
--   </pre>
--   
--   <a>AutoFromAppName</a> specifies where to save the configuration file.
--   And we've already covered the getSetting in this snippet, see the
--   <a>readSettings</a> documentation for further information.
--   
--   You can also look at the tests of the library on the github project
--   for sample use.
@package app-settings
@version 0.2.0.11

module Data.AppSettings

-- | The in-memory configuration data.
type Conf = Map String SettingInfo

-- | Information about the default configuration. Contains all the settings
--   (that you declare using <a>getDefaultConfig</a>) and their default
--   values. It is useful when you save a configuration file, if you give
--   this information to <a>saveSettings</a>, it will save default options
--   in the configuration file in a commented form, as a form of
--   documentation to a user who would edit the configuration file. However
--   this is completely optional, you can give <a>emptyDefaultConfig</a> if
--   you don't want this behaviour.
newtype DefaultConfig
DefaultConfig :: Conf -> DefaultConfig

-- | The type of a setting. It contains the setting name (key in the
--   configuration file) and its default value.
--   
--   It is advised to have a module in your project handling settings. In
--   this module, you'd have all the settings declared at the toplevel, and
--   exported. The rest of the application can then do
--   
--   <pre>
--   getSetting &lt;setting&gt;
--   setSetting &lt;conf&gt; &lt;setting&gt; &lt;value&gt;
--   </pre>
--   
--   and so on.
--   
--   <a>Setting</a> declares a simple setting. A value for that setting
--   will be stored in the configuration file in a single line.
--   
--   <a>ListSetting</a> however declares a list setting. While it is
--   perfectly fine to store lists using the usual Setting constructor, if
--   you have a list of more complex items, you will get very long lines
--   and a configuration file very difficult to edit or review by hand.
--   
--   The ListSetting will store settings using one line per item in the
--   list:
--   
--   <pre>
--   testList :: Setting [String]
--   testList = ListSetting "testList" ["list1", "list2", "list3"]
--   </pre>
--   
--   Now the configuration file looks like that:
--   
--   <pre>
--   testList_1="list1"
--   testList_2="list2"
--   testList_3="list3"
--   </pre>
--   
--   Also note that an empty ListSetting is stored like so:
--   
--   <pre>
--   testList=
--   </pre>
data Setting a
[Setting] :: String -> a -> Setting a
[ListSetting] :: (Read a, Show a) => String -> [a] -> Setting [a]
newtype GetSetting
GetSetting :: (forall a. Read a => Setting a -> a) -> GetSetting

-- | see the <a>getDefaultConfig</a> documentation.
setting :: (Show a) => Setting a -> State Conf ()

-- | Used in combination with <a>setting</a> to register settings.
--   Registering settings is optional, see <a>DefaultConfig</a>.
--   
--   <pre>
--   defaultSettings :: DefaultConfig
--   defaultSettings = getDefaultConfig $ do
--       setting &lt;setting1&gt;
--       setting &lt;setting2&gt;
--   </pre>
getDefaultConfig :: State Conf () -> DefaultConfig

-- | Default configuration containing no options. It's fine to give that to
--   <a>saveSettings</a> if you don't want default settings being written
--   to the configuration file in commented form (see <a>DefaultConfig</a>)
emptyDefaultConfig :: DefaultConfig

-- | Where to look for or store the configuration file.
data FileLocation

-- | Automatically build the location based on the application name. It
--   will be ~/.&lt;app name&gt;/config.ini.
AutoFromAppName :: String -> FileLocation

-- | Absolute path to a location on disk.
Path :: FilePath -> FileLocation

-- | Read settings from disk. Because it is doing file I/O it is smart to
--   wrap the call with a <tt>try</tt>, as I/O exceptions can be thrown.
--   Also, the function will throw a <a>ParseException</a> if the file is
--   not properly formatted. NOTE that if the file is properly formatted in
--   general, but a value is stored in an invalid format (for instance
--   "hello" for a Double), you will get no error and get the default value
--   for that setting when you attempt to read it.
--   
--   This function returns a pair. The first element is the configuration
--   itself, which you can use to save back or modify the configuration.
--   The second element is a function wrapped in the <a>GetSetting</a>
--   newtype. This function allows you to read a configuration option
--   simply by giving that option (without that callback you'd have to call
--   getSetting settings &lt;setting&gt;, so the callback lets you save a
--   parameter). There is no such shortcut for <a>setSetting</a> though, as
--   it's normally used less often and in other contexts, it is probably OK
--   to have that extra parameter for the setSetting.
--   
--   Example of use:
--   
--   <pre>
--   readResult &lt;- try $ readSettings (Path "my.config")
--   case readResult of
--    Right (conf, GetSetting getSetting) -&gt; do
--        let textSize = getSetting fontSize
--        saveSettings emptyDefaultConfig (Path "my.config") conf
--    Left (x :: SomeException) -&gt; error "Error reading the config file!"
--   </pre>
readSettings :: FileLocation -> IO (Conf, GetSetting)

-- | The configuration file is in an invalid format.
data ParseException

-- | It is advised to run the save within a try call because it does disk
--   I/O, otherwise the call is straightforward.
saveSettings :: DefaultConfig -> FileLocation -> Conf -> IO ()

-- | Change the value of a setting. You'll have to call <a>saveSettings</a>
--   so that the change is written to disk.
setSetting :: (Show a) => Conf -> Setting a -> a -> Conf

-- | Most of the time you can use the second function you get from
--   <tt>readSettings</tt>, wrapped in a <tt>GetSetting</tt> newtype,
--   however sometimes it's nicer to just pass a single <a>Conf</a> to
--   other functions if you're going to read or write to the configuration.
--   The GetSetting lets you only read.
getSetting' :: (Read a) => Conf -> Setting a -> a
instance GHC.Show.Show Data.AppSettings.GetSetting
