import json
from typing import (
    List,
    Optional,
)
from xml.sax import saxutils

from ._Key import Key
from ._util import (
    _by_name,
    _by_path,
)


class Group(object):
    def __init__(
        self,
        name: str = None,
        descr: str = None,
    ):
        self.name = name
        self.descr = descr

        self.keys: List[Key] = []
        self.groups: List["Group"] = []

    def group(self, name) -> Optional["Group"]:
        return _by_name(self.groups, name)

    def key(self, name) -> "Key":
        return _by_name(self.keys, name)

    def key_value(self, keyname, default=None) -> Optional[str]:
        key = _by_name(self.keys, keyname)
        return default if key is None else key.value()

    def find_group(self, path: str) -> Optional["Group"]:
        return _by_path(self, path)

    def find_key(self, path) -> Optional[Key]:
        return _by_path(self, path, is_key=True)

    def find_value(self, path, default=None) -> Optional[str]:
        key = _by_path(self, path, is_key=True)
        return default if key is None else key.value()

    def find_values(self, path) -> Optional[List[str]]:
        key = _by_path(self, path, is_key=True)
        return None if key is None else key.values

    def add_group(
        self,
        name: str,
        descr: Optional[str] = None,
    ) -> "Group":

        grp = Group(
            name=name,
            descr=descr,
        )
        self.groups.append(grp)
        return grp

    def add_key(
        self,
        name: str,
        type: int,
        descr: Optional[str] = None,
    ):
        key = Key(
            name=name,
            type=type,
            descr=descr,
        )
        self.keys.append(key)
        return key

    def __str__(self):
        return json.dumps(
            {
                "name": self.name,
                "descr": self.descr,
            }
        )

    def __eq__(self, other):
        if not isinstance(other, Group):
            return False

        a = (
                self.name == other.name and
                sorted(self.groups) == sorted(other.groups) and
                sorted(self.keys) == sorted(other.keys)
        )
        return a

    def __lt__(self, other):
        return self.name < other.name

    def write(self, out, level):
        out.write('%s<group' % ("\t" * level))
        if self.name is not None:
            out.write(' name=%s' % saxutils.quoteattr(self.name))
        if self.descr is not None:
            out.write(' descr=%s' % saxutils.quoteattr(self.descr))
        out.write('>\n')
        for group in self.groups:
            group.write(out, level + 1)
        for key in self.keys:
            key.write(out, level + 1)
        out.write('%s</group>\n' % ("\t" * level))
