# Path: panflute/containers.py
# class ListContainer(MutableSequence):
#     """
#     Wrapper around a list, to track the elements' parents.
#     **This class shouldn't be instantiated directly by users,
#     but by the elements that contain it**.
# 
#     :param args: elements contained in the list--like object
#     :param oktypes: type or tuple of types that are allowed as items
#     :type oktypes: ``type`` | ``tuple``
#     :param parent: the parent element
#     :type parent: ``Element``
#     :param container: None, unless the element is not part of its .parent.content (this is the case for table headers for instance, which are not retrieved with table.content but with table.header)
#     :type container: ``str`` | None
#     """
#     # Based on http://stackoverflow.com/a/3488283
#     # See also https://docs.python.org/3/library/collections.abc.html
# 
#     __slots__ = ['list', 'oktypes', 'parent', 'location']
# 
#     def __init__(self, *args, oktypes=object, parent=None):
#         self.oktypes = oktypes
#         self.parent = parent
#         self.location = None  # Cannot be set through __init__
# 
#         self.list = []
#         self.extend(args)  # self.oktypes must be set first
# 
#     def __contains__(self, item):
#         return item in self.list
# 
#     def __len__(self):
#         return len(self.list)
# 
#     def __getitem__(self, i):
#         if isinstance(i, int):
#             return attach(self.list[i], self.parent, self.location)
#         else:
#             newlist = self.list.__getitem__(i)
#             obj = ListContainer(*newlist,
#                                 oktypes=self.oktypes, parent=self.parent)
#             obj.location = self.location
#             return obj
# 
#     def __delitem__(self, i):
#         del self.list[i]
# 
#     def __setitem__(self, i, v):
#         if isinstance(i, slice):
#             v = (check_type(x, self.oktypes) for x in v)
#         else:
#             v = check_type(v, self.oktypes)
#         self.list[i] = v
# 
#     def insert(self, i, v):
#         v = check_type(v, self.oktypes)
#         self.list.insert(i, v)
# 
#     def __str__(self):
#         return self.__repr__()
# 
#     def __repr__(self):
#         return 'ListContainer({})'.format(' '.join(repr(x) for x in self.list))
# 
#     def to_json(self):
#         return [to_json_wrapper(item) for item in self.list]
# 
# class DictContainer(MutableMapping):
#     """
#     Wrapper around a dict, to track the elements' parents.
#     **This class shouldn't be instantiated directly by users,
#     but by the elements that contain it**.
# 
#     :param args: elements contained in the dict--like object
#     :param oktypes: type or tuple of types that are allowed as items
#     :type oktypes: ``type`` | ``tuple``
#     :param parent: the parent element
#     :type parent: ``Element``
#     """
# 
#     __slots__ = ['dict', 'oktypes', 'parent', 'location']
# 
#     def __init__(self, *args, oktypes=object, parent=None, **kwargs):
#         self.oktypes = oktypes
#         self.parent = parent
#         self.location = None
# 
#         self.dict = dict()
#         self.update(args)  # Must be a sequence of tuples
#         self.update(kwargs)  # Order of kwargs is not preserved
# 
#     def __contains__(self, item):
#         return item in self.dict
# 
#     def __len__(self):
#         return len(self.dict)
# 
#     def __getitem__(self, k):
#         return attach(self.dict[k], self.parent, self.location)
# 
#     def __delitem__(self, k):
#         del self.dict[k]
# 
#     def __setitem__(self, k, v):
#         v = check_type(v, self.oktypes)
#         self.dict[k] = v
# 
#     def __str__(self):
#         return self.__repr__()
# 
#     def __repr__(self):
#         return 'DictContainer({})'.format(' '.join(repr(x) for x in self.dict))
# 
#     def __iter__(self):
#         return self.dict.__iter__()
# 
#     def to_json(self):
#         return {k: to_json_wrapper(v) for k, v in self.dict.items()}
# 
# Path: panflute/utils.py
# def check_type(value, oktypes):
#     # This allows 'Space' instead of 'Space()'
#     if callable(value):
#         value = value()
# 
#     if isinstance(value, oktypes):
#         return value
# 
#     # Invalid type
#     caller = get_caller_name()
#     tag = type(value).__name__
#     msg = '\n\nElement "{}" received "{}" but expected {}\n'.format(caller, tag, oktypes)
#     raise TypeError(msg)
# 
# def encode_dict(tag, content):
#     return {
#         "t": tag,
#         "c": content,
#     }


from operator import attrgetter
from collections.abc import MutableSequence, MutableMapping
from itertools import chain
from .containers import ListContainer, DictContainer
from .utils import check_type, encode_dict  # check_group
    # Base methods
    # ---------------------------
    # Should be overridden except for trivial elements (Space, Null, etc.)

    def __repr__(self):
        # This is just a convenience method
        # Override it for more complex elements

        extra = []
        for key in self.__slots__:
            if not key.startswith('_') and key != 'text':
                val = getattr(self, key)
                if val not in ([], dict(), ''):
                    extra.append([key, val])

        if extra:
            extra = ('{}={}'.format(k, repr(v)) for k, v in extra)
            extra = '; ' + ', '.join(x for x in extra)
        else:
            extra = ''

        if '_content' in self.__slots__:
            content = ' '.join(repr(x) for x in self.content)
            return '{}({}{})'.format(self.tag, content, extra)
        elif 'text' in self.__slots__:
            return '{}({}{})'.format(self.tag, self.text, extra)
        else:
            return self.tag

    def to_json(self):

# Path: panflute/containers.py
# class ListContainer(MutableSequence):
#     """
#     Wrapper around a list, to track the elements' parents.
#     **This class shouldn't be instantiated directly by users,
#     but by the elements that contain it**.
# 
#     :param args: elements contained in the list--like object
#     :param oktypes: type or tuple of types that are allowed as items
#     :type oktypes: ``type`` | ``tuple``
#     :param parent: the parent element
#     :type parent: ``Element``
#     :param container: None, unless the element is not part of its .parent.content (this is the case for table headers for instance, which are not retrieved with table.content but with table.header)
#     :type container: ``str`` | None
#     """
#     # Based on http://stackoverflow.com/a/3488283
#     # See also https://docs.python.org/3/library/collections.abc.html
# 
#     __slots__ = ['list', 'oktypes', 'parent', 'location']
# 
#     def __init__(self, *args, oktypes=object, parent=None):
#         self.oktypes = oktypes
#         self.parent = parent
#         self.location = None  # Cannot be set through __init__
# 
#         self.list = []
#         self.extend(args)  # self.oktypes must be set first
# 
#     def __contains__(self, item):
#         return item in self.list
# 
#     def __len__(self):
#         return len(self.list)
# 
#     def __getitem__(self, i):
#         if isinstance(i, int):
#             return attach(self.list[i], self.parent, self.location)
#         else:
#             newlist = self.list.__getitem__(i)
#             obj = ListContainer(*newlist,
#                                 oktypes=self.oktypes, parent=self.parent)
#             obj.location = self.location
#             return obj
# 
#     def __delitem__(self, i):
#         del self.list[i]
# 
#     def __setitem__(self, i, v):
#         if isinstance(i, slice):
#             v = (check_type(x, self.oktypes) for x in v)
#         else:
#             v = check_type(v, self.oktypes)
#         self.list[i] = v
# 
#     def insert(self, i, v):
#         v = check_type(v, self.oktypes)
#         self.list.insert(i, v)
# 
#     def __str__(self):
#         return self.__repr__()
# 
#     def __repr__(self):
#         return 'ListContainer({})'.format(' '.join(repr(x) for x in self.list))
# 
#     def to_json(self):
#         return [to_json_wrapper(item) for item in self.list]
# 
# class DictContainer(MutableMapping):
#     """
#     Wrapper around a dict, to track the elements' parents.
#     **This class shouldn't be instantiated directly by users,
#     but by the elements that contain it**.
# 
#     :param args: elements contained in the dict--like object
#     :param oktypes: type or tuple of types that are allowed as items
#     :type oktypes: ``type`` | ``tuple``
#     :param parent: the parent element
#     :type parent: ``Element``
#     """
# 
#     __slots__ = ['dict', 'oktypes', 'parent', 'location']
# 
#     def __init__(self, *args, oktypes=object, parent=None, **kwargs):
#         self.oktypes = oktypes
#         self.parent = parent
#         self.location = None
# 
#         self.dict = dict()
#         self.update(args)  # Must be a sequence of tuples
#         self.update(kwargs)  # Order of kwargs is not preserved
# 
#     def __contains__(self, item):
#         return item in self.dict
# 
#     def __len__(self):
#         return len(self.dict)
# 
#     def __getitem__(self, k):
#         return attach(self.dict[k], self.parent, self.location)
# 
#     def __delitem__(self, k):
#         del self.dict[k]
# 
#     def __setitem__(self, k, v):
#         v = check_type(v, self.oktypes)
#         self.dict[k] = v
# 
#     def __str__(self):
#         return self.__repr__()
# 
#     def __repr__(self):
#         return 'DictContainer({})'.format(' '.join(repr(x) for x in self.dict))
# 
#     def __iter__(self):
#         return self.dict.__iter__()
# 
#     def to_json(self):
#         return {k: to_json_wrapper(v) for k, v in self.dict.items()}
# 
# Path: panflute/utils.py
# def check_type(value, oktypes):
#     # This allows 'Space' instead of 'Space()'
#     if callable(value):
#         value = value()
# 
#     if isinstance(value, oktypes):
#         return value
# 
#     # Invalid type
#     caller = get_caller_name()
#     tag = type(value).__name__
#     msg = '\n\nElement "{}" received "{}" but expected {}\n'.format(caller, tag, oktypes)
#     raise TypeError(msg)
# 
# def encode_dict(tag, content):
#     return {
#         "t": tag,
#         "c": content,
#     }


# Path: panflute/base.py
from operator import attrgetter
from collections.abc import MutableSequence, MutableMapping
from itertools import chain
from .containers import ListContainer, DictContainer
from .utils import check_type, encode_dict  # check_group

    # Base methods
    # ---------------------------
    # Should be overridden except for trivial elements (Space, Null, etc.)

    def __repr__(self):
        # This is just a convenience method
        # Override it for more complex elements

        extra = []
        for key in self.__slots__:
            if not key.startswith('_') and key != 'text':
                val = getattr(self, key)
                if val not in ([], dict(), ''):
                    extra.append([key, val])

        if extra:
            extra = ('{}={}'.format(k, repr(v)) for k, v in extra)
            extra = '; ' + ', '.join(x for x in extra)
        else:
            extra = ''

        if '_content' in self.__slots__:
            content = ' '.join(repr(x) for x in self.content)
            return '{}({}{})'.format(self.tag, content, extra)
        elif 'text' in self.__slots__:
            return '{}({}{})'.format(self.tag, self.text, extra)
        else:
            return self.tag

    def to_json(self):

        return encode_dict(self.tag, self._slots_to_json())