class Item(IntEnum_):
    """
    This class defines all the available elements for graphol diagrams.
    """
    # PREDICATES
    ConceptNode = 65537
    AttributeNode = 65538
    RoleNode = 65539
    ValueDomainNode = 65540
    IndividualNode = 65541

    # CONSTRUCTORS
    DomainRestrictionNode = 65542
    RangeRestrictionNode = 65543
    UnionNode = 65544
    EnumerationNode = 65545
    ComplementNode = 65546
    RoleChainNode = 65547
    IntersectionNode = 65548
    RoleInverseNode = 65549
    DatatypeRestrictionNode = 65550
    DisjointUnionNode = 65551
    PropertyAssertionNode = 65552
    FacetNode = 65553

    # EDGES
    InclusionEdge = 65554
    EquivalenceEdge = 65555
    InputEdge = 65556
    MembershipEdge = 65557

    # EXTRA
    Label = 65558
    Undefined = 65559

    @property
    def realName(self):
        """
        Returns the item readable name, i.e: attribute node, concept node.
        :rtype: str
        """
        return RE_CAMEL_SPACE.sub('\g<1> \g<2>', self.name).lower()

    @property
    def shortName(self):
        """
        Returns the item short name, i.e: attribute, concept.
        :rtype: str
        """
        return rstrip(self.realName, ' node', ' edge') class Special(Enum_):
    """
    This class defines special nodes types.
    """
    Top = 'TOP'
    Bottom = 'BOTTOM' class Identity(Enum_):
    """
    This class defines graphol expression identities.
    """
    Neutral = 'Neutral'
    Concept = 'Concept'
    Role = 'Role'
    Attribute = 'Attribute'
    ValueDomain = 'Value Domain'
    Individual = 'Individual'
    Value = 'Value'
    RoleInstance = 'Role Instance'
    AttributeInstance = 'Attribute Instance'
    Facet = 'Facet'
    Unknown = 'Unknown' class OWLProfile(Enum_):
    """
    Extends Enum providing all the available OWL 2 profiles.
    """
    OWL2 = 'OWL 2'
    OWL2EL = 'OWL 2 EL'
    OWL2QL = 'OWL 2 QL'
    OWL2RL = 'OWL 2 RL' class Polygon(object):
    """
    This class is used to store shape data for Diagram item objects.
    For each object it will store:

        - Geometrical data to be drawn on screen (either QRectF, QtGui.QPolygonF or QPainterPath).
        - The QtGui.QBrush used to draw the geometrical shape.
        - The QtGui.QPen used to draw the geometrical shape.

    Note that this class is meant to be used just as a container for shape related elements
    and thus, despite its name, does not provide any geometrical functionality, which are
    instead available in the geometry of the polygon.
    """
    def __init__(self, geometry=QtGui.QPolygonF(),
         brush=QtGui.QBrush(QtCore.Qt.NoBrush),
         pen=QtGui.QPen(QtCore.Qt.NoPen)):
        """
        Initialize the polygon.
        :type geometry: T <= QRectF|QtGui.QPolygonF|QPainterPath
        :type brush: QBrush
        :type pen: QPen
        """
        self._geometry = geometry
        self._brush = brush
        self._pen = pen

    #############################################
    #   INTERFACE
    #################################

    def brush(self):
        """
        Returns the brush used to draw the shape.
        :rtype: QBrush
        """
        return self._brush

    def geometry(self):
        """
        Returns the polygon geometry.
        :rtype: T <= QRectF | QPolygonF | QPainterPath
        """
        return self._geometry

    def pen(self):
        """
        Returns the pen used to draw the shape.
        :rtype: QPen
        """
        return self._pen

    def setBrush(self, brush):
        """
        Set the brush used to draw the shape.
        :type brush: QBrush
        """
        self._brush = brush

    def setGeometry(self, geometry):
        """
        Set the shape polygon.
        :type geometry: T <= QRectF | QPolygonF | QPainterPath
        """
        self._geometry = geometry

    def setPen(self, pen):
        """
        Set the brush used to draw the shape.
        :type pen: QPen
        """
        self._pen = pen K_FUNCTIONAL = 'functional' K_INVERSE_FUNCTIONAL = 'inverseFunctional' K_ASYMMETRIC = 'asymmetric' K_IRREFLEXIVE = 'irreflexive' K_REFLEXIVE = 'reflexive' K_SYMMETRIC = 'symmetric' K_TRANSITIVE = 'transitive'
from PyQt5 import QtCore
from PyQt5 import QtGui
from eddy.core.datatypes.graphol import Item, Special, Identity
from eddy.core.datatypes.owl import OWLProfile
from eddy.core.functions.misc import snapF
from eddy.core.items.common import Polygon
from eddy.core.items.nodes.common.base import AbstractResizableNode
from eddy.core.items.nodes.common.label import NodeLabel
from eddy.core.project import K_FUNCTIONAL, K_INVERSE_FUNCTIONAL
from eddy.core.project import K_ASYMMETRIC, K_IRREFLEXIVE, K_REFLEXIVE
from eddy.core.project import K_SYMMETRIC, K_TRANSITIVE
        self.background = Polygon(createPolygon(w + 8, h + 8))
        self.selection = Polygon(createPolygon(w + 8, h + 8))
        self.polygon = Polygon(createPolygon(w, h), brush, pen)
        self.label = NodeLabel(template='role', pos=self.center, parent=self)
        self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.updateNode()
        self.updateTextPos()

    #############################################
    #   INTERFACE
    #################################

    def boundingRect(self):
        """
        Returns the shape bounding rectangle.
        :rtype: QtCore.QRectF
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.selection.geometry())
        return path.boundingRect()

    def copy(self, diagram):
        """
        Create a copy of the current item.
        :type diagram: Diagram
        """
        node = diagram.factory.create(self.type(), **{
            'id': self.id,
            'brush': self.brush(),
            'height': self.height(),
            'width': self.width()
        })
        node.setPos(self.pos())
        node.setText(self.text())
        node.setTextPos(node.mapFromScene(self.mapToScene(self.textPos())))
        return node

    def definition(self):
        """
        Returns the list of nodes which contribute to the definition of this very node.
        :rtype: set
        """
        f1 = lambda x: x.type() is Item.InputEdge
        f2 = lambda x: x.type() in {Item.DomainRestrictionNode, Item.RangeRestrictionNode}
        return self.outgoingNodes(filter_on_edges=f1, filter_on_nodes=f2)

    def height(self):
        """
        Returns the height of the shape.
        :rtype: int
        """
        polygon = self.polygon.geometry()
        return polygon[self.IndexB].y() - polygon[self.IndexT].y()

    def identity(self):
        """
        Returns the identity of the current node.
        :rtype: Identity
        """
        return Identity.Role

    def isAsymmetric(self):
        """
        Returns True if the predicate represented by this node is asymmetric, False otherwise.
        :rtype: bool
        """
        try:
            return self.project.meta(self.type(), self.text())[K_ASYMMETRIC]
        except (AttributeError, KeyError):
            return False

    def isFunctional(self):
        """
        Returns True if the predicate represented by this node is functional, else False.
        :rtype: bool
        """
        try:
            return self.project.meta(self.type(), self.text())[K_FUNCTIONAL] and \
                   self.project.profile.type() is not OWLProfile.OWL2QL
        except (AttributeError, KeyError):
            return False

    def isInverseFunctional(self):
        """
        Returns True if the predicate represented by this node is inverse functional, else False.
        :rtype: bool
        """
        try:
            return self.project.meta(self.type(), self.text())[K_INVERSE_FUNCTIONAL] and \
                   self.project.profile.type() is not OWLProfile.OWL2QL
        except (AttributeError, KeyError):
            return False

    def isIrreflexive(self):
        """
        Returns True if the predicate represented by this node is irreflexive, False otherwise.
        :rtype: bool
        """
        try:
            return self.project.meta(self.type(), self.text())[K_IRREFLEXIVE]
        except (AttributeError, KeyError):
            return False

    def isReflexive(self):
        """
        Returns True if the predicate represented by this node is reflexive, False otherwise.
        :rtype: bool
        """
        try:
            return self.project.meta(self.type(), self.text())[K_REFLEXIVE] and \
                   self.project.profile.type() is not OWLProfile.OWL2RL
        except (AttributeError, KeyError):
            return False

    def isSymmetric(self):
        """
        Returns True if the predicate represented by this node is symmetric, False otherwise.
        :rtype: bool
        """
        try:

            return self.project.meta(self.type(), self.text())[K_SYMMETRIC]