import logging
import re

import libxml2

p = re.compile("((https?):((//)|(\\\\))+([\w\d:#@%/;$()~_?\+-=\\\.&](#!)?)*)")
pattern = re.compile(r'\s+')
log = logging.getLogger('dli')


class DLIRelation(object):
    def __init__(self, node, ctx):

        ctx.setContextNode(node)
        nodes = ctx.xpathEval("./*[local-name()='dnetIdentifier']")
        for entity in nodes:
            self.relatedDnetId = re.sub(pattern, ' ', entity.content)

        nodes = ctx.xpathEval("./*[local-name()='entitytype']")
        for entity in nodes:
            self.relatedEntityType = re.sub(pattern, ' ', entity.content)

        nodes = ctx.xpathEval("./*[local-name()='typeOfRelation']")
        for entity in nodes:
            self.typeOfRelation = re.sub(pattern, ' ', entity.content)

        nodes = ctx.xpathEval("./*[local-name()='title']")
        for entity in nodes:
            self.related_title = re.sub(pattern, ' ', entity.content)

        nodes = ctx.xpathEval("./*[local-name()='pid']")
        for entity in nodes:
            self.targetPID = re.sub(pattern, ' ', entity.content)
            for property in entity.properties:
                if property.name == 'type':
                    self.targetPIDType = property.content
        self.authors = []
        nodes = ctx.xpathEval(".//*[local-name()='author']")
        for entity in nodes:
            self.authors.append(re.sub(pattern, ' ', entity.content).strip())
        self.relation_provenance = []

        nodes = ctx.xpathEval("./*[local-name()='relationProvenance']/*[local-name()='datasource']")
        for entity in nodes:
            rel_item = {}
            rel_item['name'] = re.sub(pattern, ' ', entity.content).strip()
            for property in entity.properties:
                if property.name == 'completionStatus':
                    rel_item['completionStatus'] = property.content
                elif property.name == 'provisionMode':
                    rel_item['provisionMode'] = property.content
                elif property.name == 'collectionDate':
                    rel_item['collectionDate'] = property.content
            self.relation_provenance.append(rel_item)


class DLIObject(object):
    def __init__(self, input_xml):
        log.debug("CREATED OBJECT")
        self.initialize_from_xml(input_xml)

    def _associate_identifier(self, ctxt):
        res = ctxt.xpathEval("./*[local-name()='dnetResourceIdentifier']")
        for node in res:
            self.identifier = node.content

    def initialize_from_xml(self, input_xml):
        log.debug("Parsing input %s" % input_xml)
        doc = libxml2.parseDoc(input_xml)
        ctxt = doc.xpathNewContext()
        res = ctxt.xpathEval("//*[local-name()='dliObject']")
        if len(res) == 0:
            log.error("Unable to create DLI object the dli_object node is null")
            return None
        dli_object_node = res[0]
        ctxt.setContextNode(dli_object_node)
        self.identifier = ""
        self.pid = ""
        self.pid_type = ""
        self.resolved_url = ""
        self.completionStatus = ""
        self.provenance_record = []
        self.objectType = "unknown"
        self.title = ""
        self.date = ""
        self.authors = []
        self.relations = []
        self._associate_identifier(ctxt)
        self._associate_local_PID(ctxt)
        self._associate_complete_status(ctxt)
        self._associate_record_provenance(ctxt)
        ctxt.setContextNode(dli_object_node)
        self._associate_type(ctxt)
        self._associate_title(ctxt)
        self._associate_date(ctxt)
        self._associate_authors(ctxt)
        ctxt.setContextNode(dli_object_node)
        self._associate_relations(ctxt, doc.xpathNewContext())
        doc.freeDoc()
        ctxt.xpathFreeContext()

    def _associate_local_PID(self, ctxt):
        res = ctxt.xpathEval("./*[local-name()='originalIdentifier']")
        for node in res:
            self.pid = node.content.strip()
            for prop in node.properties:
                if prop.name == "type":
                    self.pid_type = prop.content
                elif prop.name == "resolvedUrl":
                    self.resolved_url = prop.content
                if self.resolved_url == "#":
                    if p.match(self.pid):
                        self.resolved_url = self.pid

    def _associate_complete_status(self, ctxt):
        res = ctxt.xpathEval("./*[local-name()='completionStatus']")
        for node in res:
            self.completionStatus = node.content.strip()

    def _associate_record_provenance(self, ctxt):
        res = ctxt.xpathEval("./*[local-name()='provenance']")
        for node in res:
            ctxt.setContextNode(node)
            datasourcesInfo = ctxt.xpathEval(".//*[local-name()='datasourceInfo']")
            for datasourceInfo in datasourcesInfo:
                ctxt.setContextNode(datasourceInfo)
                datasources = ctxt.xpathEval("./*[local-name()='datasource']")
                for datasource in datasources:
                    item = {}
                    item['name'] = datasource.content.strip()
                    item['name'] = re.sub(pattern, ' ', item['name'])
                    for property in datasource.properties:
                        if property.name == "completionStatus":
                            item['completionStatus'] = property.content.strip()
                        elif property.name == "provisionMode":
                            item['provisionMode'] = property.content.strip()

                ctxt.setContextNode(node)
                collection_date_nodes = ctxt.xpathEval(".//*[local-name()='collectionDate']")
                for coll_node in collection_date_nodes:
                    item['collectionDate'] = coll_node.content
                self.provenance_record.append(item)

    def _associate_type(self, ctxt):
        res = ctxt.xpathEval("./*[local-name()='objectType']")
        for node in res:
            self.objectType = node.content.strip()
        if self.objectType == "":
            self.objectType = "unknown"

    def _associate_title(self, ctxt):
        res = ctxt.xpathEval("./*[local-name()='title']")
        for node in res:
            self.title = node.content.strip()
            self.title = re.sub(pattern, ' ', self.title)

    def _associate_date(self, ctxt):
        res = ctxt.xpathEval("./*[local-name()='date']")
        for node in res:
            self.date = node.content.strip()

    def _associate_authors(self, ctxt):
        res = ctxt.xpathEval("./*[local-name()='authors']")
        for node in res:
            ctxt.setContextNode(node)
            authors = ctxt.xpathEval("./*[local-name()='author']")
            for author in authors:
                self.authors.append(re.sub(pattern, ' ', author.content))

    def _associate_relations(self, ctxt, newCtxt):
        res = ctxt.xpathEval("//*[local-name()='relation']")
        for relation in res:
            self.relations.append(DLIRelation(relation, newCtxt))
