# -*- coding: utf-8 -*-
"""
Various XML utilities
"""
from typing import Dict
from xml.etree import ElementTree


def _conv_name(x: str) -> str:
    """
    If this XML tree has an xmlns attribute, then etree will add it
    to the beginning of the tag, like: "{http://path}tag".
    """
    if "}" in x:
        comps = x.split("}")
        name = comps[1]
        return name
    return x


def _to_dict(xmltree: ElementTree) -> Dict:
    """
    Converts an XML ElementTree to a dictionary that only contains items.
    This is the default behavior in version 2017.7. This will default to prevent
    unexpected parsing issues on modules dependent on this.
    """
    # If this object has no children, the for..loop below will return nothing
    # for it, so just return a single dict representing it.
    if not xmltree:
        name = _conv_name(xmltree.tag)
        return {name: xmltree.text}

    xmldict = {}
    for item in xmltree:
        name = _conv_name(item.tag)

        if name not in xmldict:
            if item:
                xmldict[name] = _to_dict(item)
            else:
                xmldict[name] = item.text
        else:
            # If a tag appears more than once in the same place, convert it to
            # a list. This may require that the caller watch for such a thing
            # to happen, and behave accordingly.
            if not isinstance(xmldict[name], list):
                xmldict[name] = [xmldict[name]]
            xmldict[name].append(_to_dict(item))
    return xmldict


def _to_full_dict(xmltree: ElementTree):
    """
    Returns the full XML dictionary including attributes.
    """
    xmldict = {}

    for attrName, attrValue in xmltree.attrib.items():
        xmldict[attrName] = attrValue

    if not xmltree:
        if not xmldict:
            # If we don't have attributes, we should return the value as a string
            # ex: <entry>test</entry>
            return xmltree.text
        elif xmltree.text:
            # XML allows for empty sets with attributes, so we need to make sure that capture this.
            # ex: <entry name="test"/>
            xmldict[_conv_name(xmltree.tag)] = xmltree.text

    for item in xmltree:
        name = _conv_name(item.tag)

        if name not in xmldict:
            xmldict[name] = _to_full_dict(item)
        else:
            # If a tag appears more than once in the same place, convert it to
            # a list. This may require that the caller watch for such a thing
            # to happen, and behave accordingly.
            if not isinstance(xmldict[name], list):
                xmldict[name] = [xmldict[name]]

            xmldict[name].append(_to_full_dict(item))

    return xmldict


def to_dict(xmltree: ElementTree, attr: bool = False):
    """
    Convert an XML tree into a dict. The tree that is passed in must be an
    ElementTree object.
    Args:
        xmltree: An ElementTree object.
        attr: If true, attributes will be parsed. If false, they will be ignored.

    """
    if attr:
        return _to_full_dict(xmltree)
    else:
        return _to_dict(xmltree)
