from collections import OrderedDict
import os

from coalib.parsing.LineParser import LineParser
from coalib.settings.Setting import Setting
from coalib.settings.Section import Section


class ConfParser:
    def __init__(self,
                 key_value_delimiters=('=',),
                 comment_seperators=('#',),
                 key_delimiters=(',', ' '),
                 section_name_surroundings=None):
        section_name_surroundings = section_name_surroundings or {"[": "]"}

        self.line_parser = LineParser(key_value_delimiters,
                                      comment_seperators,
                                      key_delimiters,
                                      section_name_surroundings)

        # Declare it
        self.sections = None
        self.__rand_helper = None
        self.__init_sections()

    def parse(self, input_data, overwrite=False):
        """
        Parses the input and adds the new data to the existing.

        :param input_data: filename
        :param overwrite:  behaves like reparse if this is True
        :return:           the settings dictionary
        """
        if os.path.isdir(input_data):
            input_data = os.path.join(input_data, ".coafile")

        with open(input_data, "r", encoding='utf-8') as _file:
            lines = _file.readlines()

        if overwrite:
            self.__init_sections()

        self.__parse_lines(lines, input_data)

        return self.sections

    def get_section(self, name, create_if_not_exists=False):
        key = self.__refine_key(name)
        sec = self.sections.get(key, None)
        if sec is not None:
            return sec

        if not create_if_not_exists:
            raise IndexError

        retval = self.sections[key] = Section(str(name),
                                              self.sections["default"])
        return retval

    @staticmethod
    def __refine_key(key):
        return str(key).lower().strip()

    def __add_comment(self, section, comment, origin):
        key = "comment" + str(self.__rand_helper)
        self.__rand_helper += 1
        section.append(Setting(key, comment, origin))

    def __parse_lines(self, lines, origin):
        current_section_name = "default"
        current_section = self.get_section(current_section_name)
        current_keys = []

        for line in lines:
            section_name, keys, value, comment = self.line_parser.parse(line)

            if comment != "":
                self.__add_comment(current_section, comment, origin)

            if section_name != "":
                current_section_name = section_name
                current_section = self.get_section(current_section_name, True)
                current_keys = []
                continue

            if comment == "" and keys == [] and value == "":
                self.__add_comment(current_section, "", origin)
                continue

            if keys != []:
                current_keys = keys

            for section_override, key in current_keys:
                if key == "":
                    continue

                if section_override == "":
                    current_section.add_or_create_setting(
                        Setting(key, value, origin),
                        allow_appending=(keys == []))
                else:
                    self.get_section(
                        section_override,
                        True).add_or_create_setting(
                            Setting(key, value, origin),
                            allow_appending=(keys == []))

    def __init_sections(self):
        self.sections = OrderedDict()
        self.sections["default"] = Section("Default")
        self.__rand_helper = 0

@@ -988,16 +988,20 @@
 ut_data:
+ The
  filenam
@@ -997,24 +997,39 @@
 The filename
+ to parse from.
 %0A        :pa
@@ -1048,95 +1048,479 @@
 e:  
-behaves like reparse if this is True%0A        :return:           the settings dictionary
+If True, wipes all existing Settings inside this%0A                           instance and adds only the newly parsed ones. If%0A                           False, adds the newly parsed data to the existing one%0A                           (and overwrites already existing keys with the newly%0A                           parsed values).%0A        :return:           A dictionary with (lowercase) section names as keys%0A                           and their Setting objects as values.
 %0A   

Improve parse() documentation