from lxml.etree import Element, SubElement, tostring

from pyuntl import UNTL_XML_ORDER, HIGHWIRE_ORDER


XSI = 'http://www.w3.org/2001/XMLSchema-instance'

# Namespaces for the DC XML.
DC_NAMESPACES = {
    'oai_dc': 'http://www.openarchives.org/OAI/2.0/oai_dc/',
    'dc': 'http://purl.org/dc/elements/1.1/',
    'xsi': XSI,
}


class MetadataGeneratorException(Exception):
    """Base exception for Metadata Generation."""

    def __init__(self, value):
        self.value = value

    def __str__(self):
        return '%s' % (self.value,)


def py2dict(elements):
    """Convert a Python object into a Python dictionary."""
    metadata_dict = {}
    # Loop through all elements in the Python object.
    for element in elements.children:
        # Start an empty element list if an entry for the element
        # list hasn't been made in the dictionary.
        if element.tag not in metadata_dict:
            metadata_dict[element.tag] = []
        element_dict = {}
        if hasattr(element, 'qualifier') and element.qualifier is not None:
            element_dict['qualifier'] = element.qualifier
        # Set the element's content as a dictionary
        # of children elements.
        if element.children:
            child_dict = {}
            for child in element.children:
                if child.content is not None:
                    child_dict[child.tag] = child.content
            element_dict['content'] = child_dict
        # Set element content that is not children.
        elif element.content is not None:
            if element.content.strip() != '':
                element_dict['content'] = element.content
        # Append the dictionary to the element list
        # if the element has content or children.
        if element_dict.get('content', False):
            metadata_dict[element.tag].append(element_dict)

    return metadata_dict


def pydict2xml(filename, metadata_dict, **kwargs):
    """Create an XML file.

    Takes a path to where the XML file should be created
    and a metadata dictionary.
    """
    try:
        f = open(filename, 'wb')
        f.write(pydict2xmlstring(metadata_dict, **kwargs))
        f.close()
    except:
        raise MetadataGeneratorException(
            'Failed to create an XML file. Filename: %s' % filename
        )


def pydict2xmlstring(metadata_dict, **kwargs):
    """Create an XML string from a metadata dictionary."""
    ordering = kwargs.get('ordering', UNTL_XML_ORDER)
    root_label = kwargs.get('root_label', 'metadata')
    root_namespace = kwargs.get('root_namespace', None)
    elements_namespace = kwargs.get('elements_namespace', None)
    namespace_map = kwargs.get('namespace_map', None)
    root_attributes = kwargs.get('root_attributes', None)
    # Set any root namespace and namespace map.
    if root_namespace and namespace_map:
        root = Element(root_namespace + root_label, nsmap=namespace_map)
    elif namespace_map:
        root = Element(root_label, nsmap=namespace_map)
    else:
        root = Element(root_label)
    # Set any root element attributes.
    if root_attributes:
        for key, value in root_attributes.items():
            root.attrib[key] = value
    # Create an XML structure from field list.
    for metadata_key in ordering:
        if metadata_key in metadata_dict:
            for element in metadata_dict[metadata_key]:
                if 'content' in element and 'qualifier' in element:
                    create_dict_subelement(
                        root,
                        metadata_key,
                        element['content'],
                        attribs={'qualifier': element['qualifier']},
                        namespace=elements_namespace,
                    )
                elif 'content' in element and 'role' in element:
                    create_dict_subelement(
                        root,
                        metadata_key,
                        element['content'],
                        attribs={'role': element['role']},
                        namespace=elements_namespace,
                    )
                elif 'content' in element and 'scheme' in element:
                    create_dict_subelement(
                        root,
                        metadata_key,
                        element['content'],
                        attribs={'scheme': element['scheme']},
                        namespace=elements_namespace,
                    )
                elif 'content' in element:
                    create_dict_subelement(
                        root,
                        metadata_key,
                        element['content'],
                        namespace=elements_namespace,
                    )
    # Create the XML tree.
    return b'<?xml version="1.0" encoding="UTF-8"?>\n' + tostring(
        root,
        encoding='UTF-8',
        xml_declaration=False,
        pretty_print=True
    )


def create_dict_subelement(root, subelement, content, **kwargs):
    """Create a XML subelement from a Python dictionary."""
    attribs = kwargs.get('attribs', None)