import collections


def _xml_tree_to_dict(node, ignore_tags=None, omit_timing=True):
    """
    Translates the tree under a provided node mapping to a dictionary/list
    representation. XML tag attributes are placed in the dictionary with an
    ``@`` prefix.

    .. note:: In addition to the provided ignore tags, this filters a subset of
    timing metadata such as ``frame`` and ``string`` elements within timecode
    elements.

    .. warning:: This scheme does not allow for leaf elements to have
    attributes.  for the moment this doesn't seem to be an issue.

    :param node: The root xml element to express childeren of in the
        dictionary.
    :param ignore_tags: A collection of tagnames to skip when converting.
    :param omit_timing: If ``True``, omits timing-specific tags.

    :return: The dictionary representation.
    """
    if node.tag == "timecode":
        additional_ignore_tags = {"frame", "string"}
    else:
        additional_ignore_tags = tuple()

    out_dict = collections.OrderedDict()

    # Handle the attributes
    out_dict.update(
        collections.OrderedDict(
            ("@{}".format(k), v) for k, v in node.attrib.items()
        )
    )

    # Now traverse the child tags
    encountered_tags = set()
    list_tags = set()
    for info_node in node:
        # Skip tags we were asked to omit
        node_tag = info_node.tag
        if ignore_tags and node_tag in ignore_tags:
            continue

        # Skip some special case tags related to timing information
        if node_tag in additional_ignore_tags:
            continue

        # If there are children, make this a sub-dictionary by recursing
        if len(info_node):
            node_value = _xml_tree_to_dict(info_node)
        else:
            node_value = info_node.text

        # If we've seen this node before, then treat it as a list
        if node_tag in list_tags:
            # We've established that this tag is a list, append to that
            out_dict[node_tag].append(node_value)
        elif node_tag in encountered_tags:
            # This appears to be a list we didn't know about, convert
            out_dict[node_tag] = [
                out_dict[node_tag], node_value
            ]
            list_tags.add(node_tag)
        else:
            # Store the value
            out_dict[node_tag] = node_value
            encountered_tags.add(node_tag)

    return out_dict