from io import StringIO


class Config:
    """represents an implementation of the ConfigInterface"""

    # DEFAULT_SECTION specifies the name of a section if no name provided
    DEFAULT_SECTION = 'default'
    # DEFAULT_COMMENT defines what character(s) indicate a comment `#`
    DEFAULT_COMMENT = '#'
    # DEFAULT_COMMENT_SEM defines what alternate character(s) indicate a comment `;`
    DEFAULT_COMMENT_SEM = ';'
    # DEFAULT_MULTI_LINE_SEPARATOR defines what character indicates a multi-line content
    DEFAULT_MULTI_LINE_SEPARATOR = '\\'

    _data = dict()

    def __init__(self):
        self._data = dict()

    @staticmethod
    def new_config(conf_name):
        c = Config()
        c._parse(conf_name)
        return c

    @staticmethod
    def new_config_from_text(text):
        c = Config()
        f = StringIO(text)
        c._parse_buffer(f)
        return c

    def add_config(self, section, option, value):
        if section == '':
            section = self.DEFAULT_SECTION

        if section not in self._data.keys():
            self._data[section] = {}

        self._data[section][option] = value

    def _parse(self, fname):
        with open(fname, 'r', encoding='utf-8') as f:
            self._parse_buffer(f)

    def _parse_buffer(self, f):
        section = ''
        line_num = 0
        buf = []
        can_write = False
        while True:
            if can_write:
                self._write(section, line_num, buf)
                can_write = False
            line_num = line_num + 1

            line = f.readline()

            if not line:
                if len(buf) > 0:
                    self._write(section, line_num, buf)
                break
            line = line.strip()

            if '' == line or self.DEFAULT_COMMENT == line[0:1] or self.DEFAULT_COMMENT_SEM == line[0:1]:
                can_write = True
                continue
            elif '[' == line[0:1] and ']' == line[-1]:
                if len(buf) > 0:
                    self._write(section, line_num, buf)
                    can_write = False
                section = line[1:-1]
            else:
                p = ''
                if self.DEFAULT_MULTI_LINE_SEPARATOR == line[-1]:
                    p = line[0:-1].strip()
                    p = p + ' ' 
                else:
                    p = line
                    can_write = True
                buf.append(p)

    def _write(self, section, line_num, b):

        buf = "".join(b)
        if len(buf) <= 0:
            return
        option_val = buf.split('=', 1)

        if len(option_val) != 2:
            raise RuntimeError('parse the content error : line {} , {} = ?'.format(line_num, option_val[0]))

        option = option_val[0].strip()
        value = option_val[1].strip()

        self.add_config(section, option, value)

        del b[:]

    def set(self, key, value):
        if len(key) == 0:
            raise RuntimeError("key is empty")

        keys = key.lower().split('::')
        if len(keys) >= 2:
            section = keys[0]
            option = keys[1]
        else:
            section = ""
            option = keys[0]
        self.add_config(section, option, value)

    def get(self, key):
        """section.key or key"""

        keys = key.lower().split('::')
        if len(keys) >= 2:
            section = keys[0]
            option = keys[1]
        else:
            section = self.DEFAULT_SECTION
            option = keys[0]

        if section in self._data.keys():
            if option in self._data[section].keys():
                return self._data[section][option]
        return ''
