# -*- coding: utf-8 -*-

##########################################################################
#                                                                        #
#  Eddy: a graphical editor for the specification of Graphol ontologies  #
#  Copyright (C) 2015 Daniele Pantaleone <danielepantaleone@me.com>      #
#                                                                        #
#  This program is free software: you can redistribute it and/or modify  #
#  it under the terms of the GNU General Public License as published by  #
#  the Free Software Foundation, either version 3 of the License, or     #
#  (at your option) any later version.                                   #
#                                                                        #
#  This program is distributed in the hope that it will be useful,       #
#  but WITHOUT ANY WARRANTY; without even the implied warranty of        #
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the          #
#  GNU General Public License for more details.                          #
#                                                                        #
#  You should have received a copy of the GNU General Public License     #
#  along with this program. If not, see <http://www.gnu.org/licenses/>.  #
#                                                                        #
#  #####################                          #####################  #
#                                                                        #
#  Graphol is developed by members of the DASI-lab group of the          #
#  Dipartimento di Ingegneria Informatica, Automatica e Gestionale       #
#  A.Ruberti at Sapienza University of Rome: http://www.dis.uniroma1.it  #
#                                                                        #
#     - Domenico Lembo <lembo@dis.uniroma1.it>                           #
#     - Valerio Santarelli <santarelli@dis.uniroma1.it>                  #
#     - Domenico Fabio Savo <savo@dis.uniroma1.it>                       #
#     - Daniele Pantaleone <pantaleone@dis.uniroma1.it>                  #
#     - Marco Console <console@dis.uniroma1.it>                          #
#                                                                        #
##########################################################################


import math

from PyQt5 import QtCore
from PyQt5 import QtGui

from eddy.core.datatypes.graphol import Identity, Item
from eddy.core.datatypes.owl import Datatype
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.regex import RE_VALUE


class IndividualNode(AbstractResizableNode):
    """
    This class implements the 'Individual' node.
    """
    IndexLT = 0
    IndexLB = 1
    IndexBL = 2
    IndexBR = 3
    IndexRB = 4
    IndexRT = 5
    IndexTR = 6
    IndexTL = 7
    IndexEE = 8

    DefaultBrush = QtGui.QBrush(QtGui.QColor(252, 252, 252, 255))
    DefaultPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(0, 0, 0, 255)), 1.0, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)
    Identities = {Identity.Individual, Identity.Value}
    Type = Item.IndividualNode

    def __init__(self, width=60, height=60, brush=None, **kwargs):
        """
        Initialize the node.
        :type width: int
        :type height: int
        :type brush: QBrush
        """
        super().__init__(**kwargs)

        w = max(width, 60)
        h = max(height, 60)
        brush = brush or IndividualNode.DefaultBrush
        pen = IndividualNode.DefaultPen

        createPolygon = lambda x, y: QtGui.QPolygonF([
            QtCore.QPointF(-(x / 2), -((y / (1 + math.sqrt(2))) / 2)),
            QtCore.QPointF(-(x / 2), +((y / (1 + math.sqrt(2))) / 2)),
            QtCore.QPointF(-((x / (1 + math.sqrt(2))) / 2), +(y / 2)),
            QtCore.QPointF(+((x / (1 + math.sqrt(2))) / 2), +(y / 2)),
            QtCore.QPointF(+(x / 2), +((y / (1 + math.sqrt(2))) / 2)),
            QtCore.QPointF(+(x / 2), -((y / (1 + math.sqrt(2))) / 2)),
            QtCore.QPointF(+((x / (1 + math.sqrt(2))) / 2), -(y / 2)),
            QtCore.QPointF(-((x / (1 + math.sqrt(2))) / 2), -(y / 2)),
            QtCore.QPointF(-(x / 2), -((y / (1 + math.sqrt(2))) / 2)),
        ])

        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='individual', pos=self.center, parent=self)
        self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.updateNode()
        self.updateTextPos()

    #############################################
    #   PROPERTIES
    #################################

    @property
    def datatype(self):
        """
        Returns the datatype associated with this node.
        :rtype: Datatype
        """
        match = RE_VALUE.match(self.text())
        if match:
            return Datatype.valueOf(match.group('datatype'))
        return None

    @property
    def value(self):
        """
        Returns the value value associated with this node.
        :rtype: str
        """
        match = RE_VALUE.match(self.text())
        if match:
            return match.group('value')
        return None

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

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

    @staticmethod
    def compose(value, datatype):
        """
        Compose the value string.
        :type value: str
        :type datatype: Datatype
        :return: str
        """
        return '"{0}"^^{1}'.format(value.strip('"'), datatype.value)

    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 height(self):
        """
        Returns the height of the shape.
        :rtype: int
        """
        polygon = self.polygon.geometry()
        return polygon[self.IndexTR].y() - polygon[self.IndexBR].y()

    def identity(self):
        """
        Returns the identity of the current node.
        :rtype: Identity
        """
        match = RE_VALUE.match(self.text())
        if match:
            return Identity.Value
        return Identity.Individual

    def paint(self, painter, option, widget=None):
        """
        Paint the node in the diagram.
        :type painter: QPainter
        :type option: QStyleOptionGraphicsItem
        :type widget: QWidget
        """
        # SET THE RECT THAT NEEDS TO BE REPAINTED
        painter.setClipRect(option.exposedRect)
        # SELECTION AREA
        painter.setPen(self.selection.pen())
        painter.setBrush(self.selection.brush())
        painter.drawPolygon(self.selection.geometry())
        # SYNTAX VALIDATION
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setPen(self.background.pen())
        painter.setBrush(self.background.brush())
        painter.drawPolygon(self.background.geometry())
        # ITEM SHAPE
        painter.setPen(self.polygon.pen())
        painter.setBrush(self.polygon.brush())
        painter.drawPolygon(self.polygon.geometry())
        # RESIZE HANDLES
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        for polygon in self.handles:
            painter.setPen(polygon.pen())
            painter.setBrush(polygon.brush())
            painter.drawEllipse(polygon.geometry())

    def painterPath(self):
        """
        Returns the current shape as QtGui.QPainterPath (used for collision detection).
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.polygon.geometry())
        return path

    def resize(self, mousePos):
        """
        Handle the interactive resize of the shape.
        :type mousePos: QtCore.QPointF
        """
        snap = self.session.action('toggle_grid').isChecked()
        size = self.diagram.GridSize
        moved = self.label.isMoved()

        background = self.background.geometry()
        selection = self.selection.geometry()
        polygon = self.polygon.geometry()
        
        R = QtCore.QRectF(self.boundingRect())
        D = QtCore.QPointF(0, 0)

        mbrh = 68
        mbrw = 68

        self.prepareGeometryChange()

        if self.mp_Handle == self.HandleTL:

            fromX = self.mp_Bound.left()
            fromY = self.mp_Bound.top()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, -4, snap)
            toY = snapF(toY, size, -4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setLeft(toX)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            newSideY = (R.height() - 4 * 2) / (1 + math.sqrt(2))
            newSideX = (R.width() - 4 * 2) / (1 + math.sqrt(2))
            newLeftRightBottomY = (R.y() + R.height() / 2) + newSideY / 2
            newLeftRightTopY = (R.y() + R.height() / 2) - newSideY / 2
            newTopBottomLeftX = (R.x() + R.width() / 2) - newSideX / 2
            newTopBottomRightX = (R.x() + R.width() / 2) + newSideX / 2

            selection[self.IndexLT] = QtCore.QPointF(R.left(), newLeftRightTopY)
            selection[self.IndexLB] = QtCore.QPointF(R.left(), newLeftRightBottomY)
            selection[self.IndexRT] = QtCore.QPointF(R.right(), newLeftRightTopY)
            selection[self.IndexRB] = QtCore.QPointF(R.right(), newLeftRightBottomY)
            selection[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, R.top())
            selection[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, R.top())
            selection[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, R.bottom())
            selection[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, R.bottom())
            selection[self.IndexEE] = QtCore.QPointF(R.left(), newLeftRightTopY)
            
            background[self.IndexLT] = QtCore.QPointF(R.left(), newLeftRightTopY)
            background[self.IndexLB] = QtCore.QPointF(R.left(), newLeftRightBottomY)
            background[self.IndexRT] = QtCore.QPointF(R.right(), newLeftRightTopY)
            background[self.IndexRB] = QtCore.QPointF(R.right(), newLeftRightBottomY)
            background[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, R.top())
            background[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, R.top())
            background[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, R.bottom())
            background[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, R.bottom())
            background[self.IndexEE] = QtCore.QPointF(R.left(), newLeftRightTopY)

            polygon[self.IndexLT] = QtCore.QPointF(R.left() + 4, newLeftRightTopY)
            polygon[self.IndexLB] = QtCore.QPointF(R.left() + 4, newLeftRightBottomY)
            polygon[self.IndexRT] = QtCore.QPointF(R.right() - 4, newLeftRightTopY)
            polygon[self.IndexRB] = QtCore.QPointF(R.right() - 4, newLeftRightBottomY)
            polygon[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, R.top() + 4)
            polygon[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, R.top() + 4)
            polygon[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, R.bottom() - 4)
            polygon[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, R.bottom() - 4)
            polygon[self.IndexEE] = QtCore.QPointF(R.left() + 4, newLeftRightTopY)

        elif self.mp_Handle == self.HandleTM:

            fromY = self.mp_Bound.top()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toY = snapF(toY, size, -4, snap)
            D.setY(toY - fromY)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            newSide = (R.height() - 4 * 2) / (1 + math.sqrt(2))
            newLeftRightBottomY = (R.y() + R.height() / 2) + newSide / 2
            newLeftRightTopY = (R.y() + R.height() / 2) - newSide / 2
            
            selection[self.IndexTL] = QtCore.QPointF(background[self.IndexTL].x(), R.top())
            selection[self.IndexTR] = QtCore.QPointF(background[self.IndexTR].x(), R.top())
            selection[self.IndexLB] = QtCore.QPointF(background[self.IndexLB].x(), newLeftRightBottomY)
            selection[self.IndexRB] = QtCore.QPointF(background[self.IndexRB].x(), newLeftRightBottomY)
            selection[self.IndexLT] = QtCore.QPointF(background[self.IndexLT].x(), newLeftRightTopY)
            selection[self.IndexRT] = QtCore.QPointF(background[self.IndexRT].x(), newLeftRightTopY)
            selection[self.IndexEE] = QtCore.QPointF(background[self.IndexEE].x(), newLeftRightTopY)
            
            background[self.IndexTL] = QtCore.QPointF(background[self.IndexTL].x(), R.top())
            background[self.IndexTR] = QtCore.QPointF(background[self.IndexTR].x(), R.top())
            background[self.IndexLB] = QtCore.QPointF(background[self.IndexLB].x(), newLeftRightBottomY)
            background[self.IndexRB] = QtCore.QPointF(background[self.IndexRB].x(), newLeftRightBottomY)
            background[self.IndexLT] = QtCore.QPointF(background[self.IndexLT].x(), newLeftRightTopY)
            background[self.IndexRT] = QtCore.QPointF(background[self.IndexRT].x(), newLeftRightTopY)
            background[self.IndexEE] = QtCore.QPointF(background[self.IndexEE].x(), newLeftRightTopY)
            
            polygon[self.IndexTL] = QtCore.QPointF(polygon[self.IndexTL].x(), R.top() + 4)
            polygon[self.IndexTR] = QtCore.QPointF(polygon[self.IndexTR].x(), R.top() + 4)
            polygon[self.IndexLB] = QtCore.QPointF(polygon[self.IndexLB].x(), newLeftRightBottomY)
            polygon[self.IndexRB] = QtCore.QPointF(polygon[self.IndexRB].x(), newLeftRightBottomY)
            polygon[self.IndexLT] = QtCore.QPointF(polygon[self.IndexLT].x(), newLeftRightTopY)
            polygon[self.IndexRT] = QtCore.QPointF(polygon[self.IndexRT].x(), newLeftRightTopY)
            polygon[self.IndexEE] = QtCore.QPointF(polygon[self.IndexEE].x(), newLeftRightTopY)

        elif self.mp_Handle == self.HandleTR:

            fromX = self.mp_Bound.right()
            fromY = self.mp_Bound.top()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, +4, snap)
            toY = snapF(toY, size, -4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setRight(toX)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())
            if R.height() < mbrh:
                D.setY(D.y() - mbrh + R.height())
                R.setTop(R.top() - mbrh + R.height())

            newSideY = (R.height() - 4 * 2) / (1 + math.sqrt(2))
            newSideX = (R.width() - 4 * 2) / (1 + math.sqrt(2))
            newLeftRightBottomY = (R.y() + R.height() / 2) + newSideY / 2
            newLeftRightTopY = (R.y() + R.height() / 2) - newSideY / 2
            newTopBottomLeftX = (R.x() + R.width() / 2) - newSideX / 2
            newTopBottomRightX = (R.x() + R.width() / 2) + newSideX / 2
            
            selection[self.IndexLT] = QtCore.QPointF(R.left(), newLeftRightTopY)
            selection[self.IndexLB] = QtCore.QPointF(R.left(), newLeftRightBottomY)
            selection[self.IndexRT] = QtCore.QPointF(R.right(), newLeftRightTopY)
            selection[self.IndexRB] = QtCore.QPointF(R.right(), newLeftRightBottomY)
            selection[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, R.top())
            selection[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, R.top())
            selection[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, R.bottom())
            selection[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, R.bottom())
            selection[self.IndexEE] = QtCore.QPointF(R.left(), newLeftRightTopY)
            
            background[self.IndexLT] = QtCore.QPointF(R.left(), newLeftRightTopY)
            background[self.IndexLB] = QtCore.QPointF(R.left(), newLeftRightBottomY)
            background[self.IndexRT] = QtCore.QPointF(R.right(), newLeftRightTopY)
            background[self.IndexRB] = QtCore.QPointF(R.right(), newLeftRightBottomY)
            background[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, R.top())
            background[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, R.top())
            background[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, R.bottom())
            background[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, R.bottom())
            background[self.IndexEE] = QtCore.QPointF(R.left(), newLeftRightTopY)
            
            polygon[self.IndexLT] = QtCore.QPointF(R.left() + 4, newLeftRightTopY)
            polygon[self.IndexLB] = QtCore.QPointF(R.left() + 4, newLeftRightBottomY)
            polygon[self.IndexRT] = QtCore.QPointF(R.right() - 4, newLeftRightTopY)
            polygon[self.IndexRB] = QtCore.QPointF(R.right() - 4, newLeftRightBottomY)
            polygon[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, R.top() + 4)
            polygon[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, R.top() + 4)
            polygon[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, R.bottom() - 4)
            polygon[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, R.bottom() - 4)
            polygon[self.IndexEE] = QtCore.QPointF(R.left() + 4, newLeftRightTopY)

        elif self.mp_Handle == self.HandleML:

            fromX = self.mp_Bound.left()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toX = snapF(toX, size, -4, snap)
            D.setX(toX - fromX)
            R.setLeft(toX)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())

            newSide = (R.width() - 4 * 2) / (1 + math.sqrt(2))
            newTopBottomLeftX = (R.x() + R.width() / 2) - newSide / 2
            newTopBottomRightX = (R.x() + R.width() / 2) + newSide / 2

            selection[self.IndexLT] = QtCore.QPointF(R.left(), selection[self.IndexLT].y())
            selection[self.IndexLB] = QtCore.QPointF(R.left(), selection[self.IndexLB].y())
            selection[self.IndexEE] = QtCore.QPointF(R.left(), selection[self.IndexEE].y())
            selection[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, selection[self.IndexTL].y())
            selection[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, selection[self.IndexTR].y())
            selection[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, selection[self.IndexBL].y())
            selection[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, selection[self.IndexBR].y())
            
            background[self.IndexLT] = QtCore.QPointF(R.left(), background[self.IndexLT].y())
            background[self.IndexLB] = QtCore.QPointF(R.left(), background[self.IndexLB].y())
            background[self.IndexEE] = QtCore.QPointF(R.left(), background[self.IndexEE].y())
            background[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, background[self.IndexTL].y())
            background[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, background[self.IndexTR].y())
            background[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, background[self.IndexBL].y())
            background[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, background[self.IndexBR].y())
            
            polygon[self.IndexLT] = QtCore.QPointF(R.left() + 4, polygon[self.IndexLT].y())
            polygon[self.IndexLB] = QtCore.QPointF(R.left() + 4, polygon[self.IndexLB].y())
            polygon[self.IndexEE] = QtCore.QPointF(R.left() + 4, polygon[self.IndexEE].y())
            polygon[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, polygon[self.IndexTL].y())
            polygon[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, polygon[self.IndexTR].y())
            polygon[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, polygon[self.IndexBL].y())
            polygon[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, polygon[self.IndexBR].y())

        elif self.mp_Handle == self.HandleMR:

            fromX = self.mp_Bound.right()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toX = snapF(toX, size, +4, snap)
            D.setX(toX - fromX)
            R.setRight(toX)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())

            newSide = (R.width() - 4 * 2) / (1 + math.sqrt(2))
            newTopBottomRightX = (R.x() + R.width() / 2) + newSide / 2
            newTopBottomLeftX = (R.x() + R.width() / 2) - newSide / 2

            selection[self.IndexRT] = QtCore.QPointF(R.right(), selection[self.IndexRT].y())
            selection[self.IndexRB] = QtCore.QPointF(R.right(), selection[self.IndexRB].y())
            selection[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, selection[self.IndexTL].y())
            selection[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, selection[self.IndexTR].y())
            selection[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, selection[self.IndexBL].y())
            selection[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, selection[self.IndexBR].y())
            
            background[self.IndexRT] = QtCore.QPointF(R.right(), background[self.IndexRT].y())
            background[self.IndexRB] = QtCore.QPointF(R.right(), background[self.IndexRB].y())
            background[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, background[self.IndexTL].y())
            background[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, background[self.IndexTR].y())
            background[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, background[self.IndexBL].y())
            background[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, background[self.IndexBR].y())
            
            polygon[self.IndexRT] = QtCore.QPointF(R.right() - 4, polygon[self.IndexRT].y())
            polygon[self.IndexRB] = QtCore.QPointF(R.right() - 4, polygon[self.IndexRB].y())
            polygon[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, polygon[self.IndexTL].y())
            polygon[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, polygon[self.IndexTR].y())
            polygon[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, polygon[self.IndexBL].y())
            polygon[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, polygon[self.IndexBR].y())

        elif self.mp_Handle == self.HandleBL:

            fromX = self.mp_Bound.left()
            fromY = self.mp_Bound.bottom()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, -4, snap)
            toY = snapF(toY, size, +4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setLeft(toX)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() - mbrw + R.width())
                R.setLeft(R.left() - mbrw + R.width())
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            newSideY = (R.height() - 4 * 2) / (1 + math.sqrt(2))
            newSideX = (R.width() - 4 * 2) / (1 + math.sqrt(2))
            newLeftRightBottomY = (R.y() + R.height() / 2) + newSideY / 2
            newLeftRightTopY = (R.y() + R.height() / 2) - newSideY / 2
            newTopBottomLeftX = (R.x() + R.width() / 2) - newSideX / 2
            newTopBottomRightX = (R.x() + R.width() / 2) + newSideX / 2

            selection[self.IndexLT] = QtCore.QPointF(R.left(), newLeftRightTopY)
            selection[self.IndexLB] = QtCore.QPointF(R.left(), newLeftRightBottomY)
            selection[self.IndexRT] = QtCore.QPointF(R.right(), newLeftRightTopY)
            selection[self.IndexRB] = QtCore.QPointF(R.right(), newLeftRightBottomY)
            selection[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, R.top())
            selection[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, R.top())
            selection[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, R.bottom())
            selection[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, R.bottom())
            selection[self.IndexEE] = QtCore.QPointF(R.left(), newLeftRightTopY)

            background[self.IndexLT] = QtCore.QPointF(R.left(), newLeftRightTopY)
            background[self.IndexLB] = QtCore.QPointF(R.left(), newLeftRightBottomY)
            background[self.IndexRT] = QtCore.QPointF(R.right(), newLeftRightTopY)
            background[self.IndexRB] = QtCore.QPointF(R.right(), newLeftRightBottomY)
            background[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, R.top())
            background[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, R.top())
            background[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, R.bottom())
            background[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, R.bottom())
            background[self.IndexEE] = QtCore.QPointF(R.left(), newLeftRightTopY)
            
            polygon[self.IndexLT] = QtCore.QPointF(R.left() + 4, newLeftRightTopY)
            polygon[self.IndexLB] = QtCore.QPointF(R.left() + 4, newLeftRightBottomY)
            polygon[self.IndexRT] = QtCore.QPointF(R.right() - 4, newLeftRightTopY)
            polygon[self.IndexRB] = QtCore.QPointF(R.right() - 4, newLeftRightBottomY)
            polygon[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, R.top() + 4)
            polygon[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, R.top() + 4)
            polygon[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, R.bottom() - 4)
            polygon[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, R.bottom() - 4)
            polygon[self.IndexEE] = QtCore.QPointF(R.left() + 4, newLeftRightTopY)

        elif self.mp_Handle == self.HandleBM:

            fromY = self.mp_Bound.bottom()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toY = snapF(toY, size, +4, snap)
            D.setY(toY - fromY)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            newSide = (R.height() - 4 * 2) / (1 + math.sqrt(2))
            newLeftRightTopY = (R.y() + R.height() / 2) - newSide / 2
            newLeftRightBottomY = (R.y() + R.height() / 2) + newSide / 2

            selection[self.IndexBL] = QtCore.QPointF(selection[self.IndexBL].x(), R.bottom())
            selection[self.IndexBR] = QtCore.QPointF(selection[self.IndexBR].x(), R.bottom())
            selection[self.IndexLB] = QtCore.QPointF(selection[self.IndexLB].x(), newLeftRightBottomY)
            selection[self.IndexRB] = QtCore.QPointF(selection[self.IndexRB].x(), newLeftRightBottomY)
            selection[self.IndexLT] = QtCore.QPointF(selection[self.IndexLT].x(), newLeftRightTopY)
            selection[self.IndexRT] = QtCore.QPointF(selection[self.IndexRT].x(), newLeftRightTopY)
            selection[self.IndexEE] = QtCore.QPointF(selection[self.IndexEE].x(), newLeftRightTopY)
            
            background[self.IndexBL] = QtCore.QPointF(background[self.IndexBL].x(), R.bottom())
            background[self.IndexBR] = QtCore.QPointF(background[self.IndexBR].x(), R.bottom())
            background[self.IndexLB] = QtCore.QPointF(background[self.IndexLB].x(), newLeftRightBottomY)
            background[self.IndexRB] = QtCore.QPointF(background[self.IndexRB].x(), newLeftRightBottomY)
            background[self.IndexLT] = QtCore.QPointF(background[self.IndexLT].x(), newLeftRightTopY)
            background[self.IndexRT] = QtCore.QPointF(background[self.IndexRT].x(), newLeftRightTopY)
            background[self.IndexEE] = QtCore.QPointF(background[self.IndexEE].x(), newLeftRightTopY)
            
            polygon[self.IndexBL] = QtCore.QPointF(polygon[self.IndexBL].x(), R.bottom() - 4)
            polygon[self.IndexBR] = QtCore.QPointF(polygon[self.IndexBR].x(), R.bottom() - 4)
            polygon[self.IndexLB] = QtCore.QPointF(polygon[self.IndexLB].x(), newLeftRightBottomY)
            polygon[self.IndexRB] = QtCore.QPointF(polygon[self.IndexRB].x(), newLeftRightBottomY)
            polygon[self.IndexLT] = QtCore.QPointF(polygon[self.IndexLT].x(), newLeftRightTopY)
            polygon[self.IndexRT] = QtCore.QPointF(polygon[self.IndexRT].x(), newLeftRightTopY)
            polygon[self.IndexEE] = QtCore.QPointF(polygon[self.IndexEE].x(), newLeftRightTopY)

        elif self.mp_Handle == self.HandleBR:

            fromX = self.mp_Bound.right()
            fromY = self.mp_Bound.bottom()
            toX = fromX + mousePos.x() - self.mp_Pos.x()
            toY = fromY + mousePos.y() - self.mp_Pos.y()
            toX = snapF(toX, size, +4, snap)
            toY = snapF(toY, size, +4, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setRight(toX)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.width() < mbrw:
                D.setX(D.x() + mbrw - R.width())
                R.setRight(R.right() + mbrw - R.width())
            if R.height() < mbrh:
                D.setY(D.y() + mbrh - R.height())
                R.setBottom(R.bottom() + mbrh - R.height())

            newSideY = (R.height() - 4 * 2) / (1 + math.sqrt(2))
            newSideX = (R.width() - 4 * 2) / (1 + math.sqrt(2))
            newLeftRightBottomY = (R.y() + R.height() / 2) + newSideY / 2
            newLeftRightTopY = (R.y() + R.height() / 2) - newSideY / 2
            newTopBottomLeftX = (R.x() + R.width() / 2) - newSideX / 2
            newTopBottomRightX = (R.x() + R.width() / 2) + newSideX / 2

            selection[self.IndexLT] = QtCore.QPointF(R.left(), newLeftRightTopY)
            selection[self.IndexLB] = QtCore.QPointF(R.left(), newLeftRightBottomY)
            selection[self.IndexRT] = QtCore.QPointF(R.right(), newLeftRightTopY)
            selection[self.IndexRB] = QtCore.QPointF(R.right(), newLeftRightBottomY)
            selection[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, R.top())
            selection[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, R.top())
            selection[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, R.bottom())
            selection[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, R.bottom())
            selection[self.IndexEE] = QtCore.QPointF(R.left(), newLeftRightTopY)

            background[self.IndexLT] = QtCore.QPointF(R.left(), newLeftRightTopY)
            background[self.IndexLB] = QtCore.QPointF(R.left(), newLeftRightBottomY)
            background[self.IndexRT] = QtCore.QPointF(R.right(), newLeftRightTopY)
            background[self.IndexRB] = QtCore.QPointF(R.right(), newLeftRightBottomY)
            background[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, R.top())
            background[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, R.top())
            background[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, R.bottom())
            background[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, R.bottom())
            background[self.IndexEE] = QtCore.QPointF(R.left(), newLeftRightTopY)
            
            polygon[self.IndexLT] = QtCore.QPointF(R.left() + 4, newLeftRightTopY)
            polygon[self.IndexLB] = QtCore.QPointF(R.left() + 4, newLeftRightBottomY)
            polygon[self.IndexRT] = QtCore.QPointF(R.right() - 4, newLeftRightTopY)
            polygon[self.IndexRB] = QtCore.QPointF(R.right() - 4, newLeftRightBottomY)
            polygon[self.IndexTL] = QtCore.QPointF(newTopBottomLeftX, R.top() + 4)
            polygon[self.IndexTR] = QtCore.QPointF(newTopBottomRightX, R.top() + 4)
            polygon[self.IndexBL] = QtCore.QPointF(newTopBottomLeftX, R.bottom() - 4)
            polygon[self.IndexBR] = QtCore.QPointF(newTopBottomRightX, R.bottom() - 4)
            polygon[self.IndexEE] = QtCore.QPointF(R.left() + 4, newLeftRightTopY)

        self.background.setGeometry(background)
        self.selection.setGeometry(selection)
        self.polygon.setGeometry(polygon)

        self.updateNode(selected=True, handle=self.mp_Handle, anchors=(self.mp_Data, D))
        self.updateTextPos(moved=moved)

    def setIdentity(self, identity):
        """
        Set the identity of the current node.
        :type identity: Identity
        """
        pass

    def setText(self, text):
        """
        Set the label text: will additionally block label editing if a literal is being.
        :type text: str
        """
        self.label.setEditable(RE_VALUE.match(text) is None)
        self.label.setText(text)
        self.label.setAlignment(QtCore.Qt.AlignCenter)

    def setTextPos(self, pos):
        """
        Set the label position.
        :type pos: QPointF
        """
        self.label.setPos(pos)

    def shape(self):
        """
        Returns the shape of this item as a QPainterPath in local coordinates.
        :rtype: QPainterPath
        """
        path = QtGui.QPainterPath()
        path.addPolygon(self.polygon.geometry())
        for polygon in self.handles:
            path.addEllipse(polygon.geometry())
        return path

    def text(self):
        """
        Returns the label text.
        :rtype: str
        """
        return self.label.text()

    def textPos(self):
        """
        Returns the current label position in item coordinates.
        :rtype: QPointF
        """
        return self.label.pos()

    def updateTextPos(self, *args, **kwargs):
        """
        Update the label position.
        """
        self.label.updatePos(*args, **kwargs)

    def width(self):
        """
        Returns the width of the shape.
        :rtype: int
        """
        polygon = self.polygon.geometry()
        return polygon[self.IndexRT].x() - polygon[self.IndexLT].x()

    def __repr__(self):
        """
        Returns repr(self).
        """
        return '{0}:{1}:{2}'.format(self.__class__.__name__, self.text(), self.id)