import os
import sys
import configparser


class ConfigSection(object):
    """
    A thin wrapper over a ConfigParser's SectionProxy object,
    that tries to infer the types of values, and makes them available as attributes
    Currently int/float/str are supported.
    """

    def __init__(self, config, section_proxy):
        self.config = config
        self.name = section_proxy.name
        self.d = {}  # key value dict where the value is typecast to int/float/str

        for k, v in section_proxy.items():
            if v in ("True", "False"):
                self.d[k] = eval(v)
                continue

            try:
                v = int(v)
            except ValueError:
                try:
                    v = float(v)
                except ValueError:
                    # We interpret a missing value as None, and a "" as the empty string
                    if v.startswith('"') and v.endswith('"'):
                        v = v[1:-1]
                    elif v == "":
                        v = None
                    self.d[k] = v
                else:
                    self.d[k] = v
            else:
                self.d[k] = v

    def __setattr__(self, key, value):
        if key in ("config", "name", "d"):
            return super(ConfigSection, self).__setattr__(key, value)
        else:
            self.d[key] = value

    def __getattr__(self, item):
        if item not in ("config", "name", "d"):
            config_value = self.d[item]
            # If an environment variable exists with name <CONFIG_NAME>_<SECTION>_<ITEM>, use it
            env_varname = "_".join(
                [str(x).upper() for x in [self.config.name, self.name, item]]
            )
            if env_var := os.getenv(env_varname):
                return type(config_value)(env_var)
            return config_value

    def items(self):
        return self.d.items()


class Config(object):
    def __init__(self, name, filenames):
        self.name = name
        self.config = configparser.ConfigParser(inline_comment_prefixes="#")
        self.init_from_files(filenames)

    def init_from_files(self, filenames):
        self.config.read(filenames)
        self._read_sections()

    def read(self, filename):
        self.config.read(filename)
        self._read_sections()

    def _read_sections(self):
        for section in self.config.sections():
            setattr(self, section, ConfigSection(self, self.config[section]))

    def sections(self):
        return self.config.sections()


def show_config():
    global config
    print("hgan configuration\n------------------")
    config.config.write(sys.stdout)


config_file = os.path.join(os.path.dirname(__file__), "configuration.ini")
config = Config("hgan", config_file)
