# -----------------------------------------------------------------------------
# Copyright (c) 2014--, The American Gut Development Team.
#
# Distributed under the terms of the BSD 3-clause License.
#
# The full license is in the file LICENSE, distributed with this software.
# -----------------------------------------------------------------------------

from os.path import join, dirname, abspath, exists, isfile
from os import environ
from functools import partial

from future import standard_library
with standard_library.hooks():
    from configparser import (ConfigParser, NoOptionError,
                              MissingSectionHeaderError)


class ConfigurationManager(object):
    """Holds the configuration information

    Parameters
    ----------
    conf_fp: str, optional
        Filepath to the configuration file. Default: ag_config.txt

    Attributes
    ----------
    test_environment : bool
        Whether we are in a test environment or not
    base_data_dir : str
        Path to the base directorys where all data file are stored
    user : str
        The postgres user
    password : str
        The postgres password for the previous user
    database : str
        The postgres database to connect to
    host : str
        The host where the database lives
    port : int
        The port used to connect to the postgres database in the previous host
    goodpassword : str
        The correct password for the test account
    badpassword : str
        The password used for testing on the test account
    redis_host : str
        The host on which redis is running
    redis_port : int
        The port that redis is running on
    redis_db_id : int
        The ID of the redis database

    Raises
    ------
    IOError
        If the AG_CONFIG environment variable is set, but does not point to an
        existing file

    Notes
    -----
    - The environment variable AG_CONFIG is checked for a path to the config
      file. If the environment variable is not set, the default config file is
      used.
    """
    def __init__(self):
        conf_fp = environ.get('AG_CONFIG') or join(dirname(abspath(__file__)),
                                                   '../ag_config.txt')

        if not isfile(conf_fp):
            raise IOError("The configuration file %s is not an existing file")

        # Parse the configuration file
        config = ConfigParser()
        with open(conf_fp, 'U') as conf_file:
            config.readfp(conf_file)

        _expected_sections = {'main', 'postgres', 'test', 'redis'}
        if set(config.sections()) != _expected_sections:
            missing = _expected_sections - set(config.sections())
            raise MissingSectionHeaderError("Missing: %r" % missing)

        self._get_main(config)
        self._get_postgres(config)
        self._get_test(config)
        self._get_redis(config)

    def _get_main(self, config):
        """Get the configuration of the main section"""
        get = partial(config.get, 'main')
        getboolean = partial(config.getboolean, 'main')

        self.project_name = get('NAME')
        self.project_shorthand = get('SHORTHAND')
        self.test_environment = getboolean('TEST_ENVIRONMENT')
        self.base_data_dir = get('BASE_DATA_DIR')
        self.locale = get('LOCALE')

        if not exists(self.base_data_dir):
            raise IOError("Directory %s does not exist!" % self.base_data_dir)

    def _get_postgres(self, config):
        """Get the configuration of the postgres section"""
        get = partial(config.get, 'postgres')
        getint = partial(config.getint, 'postgres')

        self.user = get('USER')
        try:
            self.password = get('PASSWORD')
        except NoOptionError as e:
            if self.test_environment:
                self.password = None
            else:
                raise e
        self.database = get('DATABASE')
        self.host = get('HOST')
        self.port = getint('PORT')

    def _get_test(self, config):
        """Get the configuration of the test section"""
        get = partial(config.get, 'test')

        self.goodpassword = get('GOODPASSWORD')
        self.badpassword = get('BADPASSWORD')

    def _get_redis(self, config):
        """Get the configuration of the redis section"""
        get = partial(config.get, 'redis')
        getint = partial(config.getint, 'redis')

        self.redis_host = get('HOST')
        self.redis_port = getint('PORT')
        self.redis_db_id = getint('DB_ID')


AMGUT_CONFIG = ConfigurationManager()

@@ -624,33 +624,392 @@
     
+Error as ConfigParser_Error)%0A%0A%0Aclass 
 Missing
+Config
 Section
-HeaderError
+(ConfigParser_Error):%0A    %22%22%22Exception when the config file is missing a required section%22%22%22%0A    def __init__(self, section):%0A        super(MissingConfigSection, self).__init__('Missing section(s): %25r' %25%0A                                                   (section,))%0A        self.section = section%0A        self.args = (section,
 )%0A%0A%0A
@@ -2669,18 +2669,20 @@
 on file 
+'
 %25s
+'
  is not 
@@ -2684,16 +2684,45 @@
  not an 
+%22%0A                          %22
 existing
@@ -2727,16 +2727,26 @@
 ng file%22
+ %25 conf_fp
 )%0A%0A     
@@ -2966,69 +2966,9 @@
 s'%7D%0A
-        if set(config.sections()) != _expected_sections:%0A    
+%0A
     
@@ -3025,16 +3025,36 @@
 ions())%0A
+        if missing:%0A
         
@@ -3074,51 +3074,40 @@
 sing
+Config
 Section
-HeaderError(%22Missing: %25r%22 %25 
+(', '.join(
 missing)
 %0A%0A  
@@ -3102,16 +3102,17 @@
 missing)
+)
 %0A%0A      

Fix error type on missing section