import xml.sax.handler

from ._Configuration import Configuration
from ._Group import Group
from ._InvalidConfigXml import InvalidConfigXml
from ._Key import Key
from ._util import (
    UNKNOWN,
    _TYPES_TAG_MAP,
)


class _CfgSaxHandler(xml.sax.handler.ContentHandler):
    def __init__(self):
        self.cfg = Configuration()
        self.current = self.cfg
        self.current_value = None
        self.parent_stack = []

    def startElement(self, name, attrs):
        if name == "group":
            self.parent_stack.append(self.current)

            if "name" not in attrs:
                raise InvalidConfigXml("Group must have a name")

            if isinstance(self.current, (Configuration, Group)):
                self.current = self.current.add_group(
                    name=attrs["name"],
                    descr=attrs.get("descr"),
                )
            else:
                raise InvalidConfigXml("Groups can only be defined inside configuration or group")

        elif name == "key":
            self.parent_stack.append(self.current)

            if "name" not in attrs:
                raise InvalidConfigXml("Group must have a name")

            if isinstance(self.current, Group):
                self.current = self.current.add_key(
                    name=attrs["name"],
                    type=UNKNOWN,
                    descr=attrs.get("descr"),
                )
            else:
                raise InvalidConfigXml("Keys can only be defined inside groups")

        elif name in _TYPES_TAG_MAP:
            if self.current.type == UNKNOWN:
                self.current.type = _TYPES_TAG_MAP[name]
            if self.current_value is None and name != "array":
                self.current_value = ""

        elif name == "config":
            if self.current != self.cfg:
                raise InvalidConfigXml("Config tag must be the root element")

            ver = attrs.get("version")
            if ver:
                self.current.version = ver

        else:
            raise InvalidConfigXml(f"Invalid tag: {name}")

    def characters(self, content):
        if self.current_value is not None:
            self.current_value += content

    def endElement(self, name):
        if self.current_value is not None and isinstance(self.current, Key):
            self.current.values.append(self.current_value)
            self.current_value = None
        elif name == "group" or name == "key":
            self.current = self.parent_stack.pop()
