# cython: language_level=2

"""
The ``Z`` Element factory for generating XML documents.
"""

def toxml(tag, *cs, **v):
    ats = str.join("", [f' {a}="{b}"' for a, b in v.items()])
    res = f"<{tag}{ats}"
    miolo = ""

    if len(cs) == 1 and isinstance(cs[0], (list, set, tuple)):
        for ele in cs[0]:
            miolo += toxml(tag, ele, v)
        return miolo

    for c in cs:
        if isinstance(c, (list, set, tuple)):
            for ele in c:
                miolo += toxml("item", ele)

        elif isinstance(c, dict):
            for key, ele in c.items():
                miolo += toxml(key, ele)
            # miolo = toxml(tag, miolo)

        else:
            miolo = f"{miolo} {c}" if miolo else c

    if miolo is not None and len(miolo) > 0:
        res += f">{miolo}</{tag}>"
    else:
        res += "/>"
    return res


from functools import partial

class ElementMaker(object):

    def __init__(self, typemap=None, makeelement=None):
#                 namespace=None, 
#                 nsmap=None, 
#        if namespace is not None:
#            self._namespace = '{' + namespace + '}'
#        else:
#            self._namespace = None
#
#        if nsmap:
#            self._nsmap = dict(nsmap)
#        else:
#            self._nsmap = None

        if makeelement is not None:
            assert callable(makeelement)
            self._makeelement = makeelement
        else:
            self._makeelement =  toxml # FIXME: ET.Element

        # initialize type map for this element factory

        if typemap:
            typemap = dict(typemap)
        else:
            typemap = {}

        def add_text(elem, item):
            elem.text = (elem.text or "") + item

        if str not in typemap:
            typemap[str] = add_text

        def add_dict(elem, item):
            attrib = elem.attrib
            for k, v in item.items():
                if isinstance(v, basestring):
                    attrib[k] = v
                else:
                    attrib[k] = typemap[type(v)](None, v)
        if dict not in typemap:
            typemap[dict] = add_dict

        self._typemap = typemap

    def __call__(self, tag, *children, **attrib):
        typemap = self._typemap

#        if self._namespace is not None and tag[0] != '{':
#            tag = self._namespace + tag

        return self._makeelement(tag , *children, **attrib)  ## FIXME

    def __getattr__(self, tag):
        return partial(self, tag)

Z = ElementMaker()
