__authors__ = ["Bioinformatics Laboratory, University of Ljubljana", "H.Payno"]
__license__ = "[GNU GPL v3+]: https://www.gnu.org/licenses/gpl-3.0.en.html"
__date__ = "29/05/2017"


from xml.etree.ElementTree import parse
from .parser import (
    _scheme,
    _node,
    _link,
    _nxNodeProperty,
    _nxRelation,
    _nxLink,
    _nxNode,
)
import logging
from .scheme import Node, Scheme
from .parser import Parser

logger = logging.getLogger(__name__)


class MomlParser(Parser):
    """This is a dictionnary to convert an OrangeWidget into a core process."""

    @staticmethod
    def scheme_load(file_, load_handlers=True):
        """

        :param file_: file containing the scheme definition
        :param bool load_handlers: try to load the handlers of each node. Used
                                   to make sure the process won't fail
        :return: :class:`Scheme`
        """
        desc = MomlParser.parse_moml_stream(file_)
        scheme = Scheme.from_desc(desc)
        if load_handlers is True:
            scheme.load_handlers()
        return scheme

    @staticmethod
    def parse_moml_stream(stream):
        doc = parse(stream)
        scheme = MomlParser.parse_moml_etree(doc)
        return scheme

    @staticmethod
    def parse_moml_etree(tree):
        def convertToOrangeLinks(nx_links, nx_relations):
            def getLink(_id):
                if _id not in links:
                    links[_id] = {"id": _id}
                return links[_id]

            links = {}
            # convert nx (.omlm) liks and relations to orange links
            for nx_link in nx_links:
                link = getLink(nx_link.relation)
                # TODO: for now some port / link type are not managed
                if nx_link.port in ("In", "Out", "No mesh defined"):
                    logger.warning(nx_link.port + " not managed yet")
                    continue
                else:
                    node_id, input_output = nx_link.port.split(".", -1)
                    if input_output.lower() in ("output", "other", "true"):
                        link["source_node_id"] = node_id
                    else:
                        link["sink_node_id"] = node_id

            for relation in nx_relations:
                assert relation.id in links
                links[relation.id]["source_channel"] = relation.class_
                links[relation.id]["sink_channel"] = relation.class_
                links[relation.id]["properties"] = relation.properties

            orangeLinks = []
            for linkid, link in links.items():
                # TODO: this condition is due from the case that some link are
                #  not managed yet.
                if "source_node_id" not in link or "sink_node_id" not in link:
                    continue
                l = _link(
                    id=link["id"],
                    source_node_id=link["source_node_id"],
                    sink_node_id=link["sink_node_id"],
                    source_channel=link["source_channel"],
                    sink_channel=link["sink_channel"],
                    enabled=True,
                )
                orangeLinks.append(l)

            return orangeLinks

        nodes, nx_links, nx_relations = [], [], []

        # Collect all nodes
        for node in tree.findall(".//entity"):
            node_id = node.get("name")
            node_class = node.get("class")
            node_properties = []
            for property in node.findall("property"):
                _property = _nxNodeProperty(
                    name=property.get("name"),
                    class_=property.get("class"),
                    value=property.get("value"),
                )
                node_properties.append(_property)
            nodes.append(
                _nxNode(
                    id=node_id,
                    class_=node_class,
                    properties=node_properties,
                    data=None,
                    qualified_name=node_class,
                )
            )

        # collect all nx links
        for link in tree.findall("link"):
            _my_link = _nxLink(port=link.get("port"), relation=link.get("relation"))
            nx_links.append(_my_link)

        # collect all nx relations
        for relation in tree.findall("relation"):
            relation_properties = []
            for property in relation.findall("property"):
                _property = _nxNodeProperty(
                    name=property.get("name"),
                    class_=property.get("class"),
                    value=property.get("value"),
                )
                relation_properties.append(_property)

            _relation = _nxRelation(
                id=relation.get("name"),
                class_=relation.get("class"),
                properties=relation_properties,
            )
            nx_relations.append(_relation)

        links = convertToOrangeLinks(nx_links=nx_links, nx_relations=nx_relations)

        return _scheme(
            version="nx 0.1",
            title=("undefined"),
            description=None,
            nodes=nodes,
            links=links,
            annotations=None,
        )
