from io import BytesIO
from xml.etree import ElementTree as ET

from staff.lib.serializers import BaseSerializer


class XMLSerializer(BaseSerializer):
    def serialize(self, *args, **kwargs):
        tags = self.entities or tuple()
        level = 0
        content_elem = ET.Element(self._get_tag(tags, level))
        self._xml_serialize(content_elem, self.data, tags, level)

        tree = ET.ElementTree(content_elem)

        f = BytesIO()
        tree.write(f, 'UTF-8', xml_declaration=True)
        return f.getvalue()

    def _xml_serialize(self, parent_elem, data, tags, level):
        level += 1
        if isinstance(data, list) or isinstance(data, tuple):
            self._xml_serialize_list(parent_elem, data, tags, level)
        elif isinstance(data, dict):
            self._xml_serialize_dict(parent_elem, data, tags, level)
        elif isinstance(data, bool):
            parent_elem.text = '1' if data else '0'
        elif data is None:
            parent_elem.text = ''
        else:
            parent_elem.text = str(data)

    def _xml_serialize_list(self, parent_elem, data_list, tags, level):
        for i in data_list:
            item_elem = ET.Element(self._get_tag(tags, level))
            parent_elem.append(item_elem)
            self._xml_serialize(item_elem, i, tags, level)

    def _xml_serialize_dict(self, parent_elem, data_dict, tags, level):
        for k, v in data_dict.items():
            key_elem = ET.Element(k)
            parent_elem.append(key_elem)
            self._xml_serialize(key_elem, v, tags, level)

    def _get_tag(self, tags, level):
        if len(tags) > level:
            return tags[level]
        else:
            if level:
                return 'item'
            else:
                return 'content'
