# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 GNS3 Technologies Inc.
#
# 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/>.

"""
Base class for shape items (Rectangle, ellipse etc.).
"""

import xml.etree.ElementTree as ET
from ..qt import QtCore, QtGui, QtWidgets, QtSvg
from .drawing_item import DrawingItem
from .utils import colorFromSvg

import logging
log = logging.getLogger(__name__)


class ShapeItem(DrawingItem):

    # Map QT stroke to SVG style
    QT_DASH_TO_SVG = {
        QtCore.Qt.SolidLine: "",
        QtCore.Qt.NoPen: None,
        QtCore.Qt.DashLine: "25, 25",
        QtCore.Qt.DotLine:  "5, 25",
        QtCore.Qt.DashDotLine:  "5, 25, 25",
        QtCore.Qt.DashDotDotLine: "25, 25, 5, 25, 5"
    }


    """
    Base class to draw shapes on the scene.
    """

    def __init__(self, width=200, height=200, svg=None, **kws):

        super().__init__(svg=svg, **kws)
        self.setAcceptHoverEvents(True)
        self._border = 5
        self._edge = None

        if svg is None:
            self.setRect(0, 0, width, height)
            pen = QtGui.QPen(QtCore.Qt.black, 2, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)
            self.setPen(pen)
            brush = QtGui.QBrush(QtGui.QColor(255, 255, 255, 255))  # default color is white and not transparent
            self.setBrush(brush)
        else:
            self.fromSvg(svg)
        if self._id is None:
            self.create()

    def mousePressEvent(self, event):
        """
        Handles all mouse press events.

        :param event: QMouseEvent instance
        """

        self.update()
        if event.pos().x() > (self.rect().right() - self._border):
            self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, False)
            self._edge = "right"

        elif event.pos().x() < (self.rect().left() + self._border):
            self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, False)
            self._edge = "left"

        elif event.pos().y() < (self.rect().top() + self._border):
            self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, False)
            self._edge = "top"

        elif event.pos().y() > (self.rect().bottom() - self._border):
            self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, False)
            self._edge = "bottom"

        QtWidgets.QGraphicsItem.mousePressEvent(self, event)

    def mouseReleaseEvent(self, event):
        """
        Handles all mouse release events.

        :param: QMouseEvent instance
        """

        self.update()
        self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable)
        self._edge = None
        QtWidgets.QGraphicsItem.mouseReleaseEvent(self, event)

    def mouseMoveEvent(self, event):
        """
        Handles all mouse move events.

        :param event: QMouseEvent instance
        """

        self.update()
        if self._edge:
            r = self.rect()
            scenePos = event.scenePos()

            if self._edge == "top":
                diff = self.y() - scenePos.y()
                if r.height() - diff > 0:
                    self.setPos(self.x(), scenePos.y())
                    self.setRect(0, 0, self.rect().width(), self.rect().height() + diff)
                else:
                    self._edge = "bottom"
                    self.setPos(self.x(), self.y() + self.rect().height())
                    self.setRect(0, 0, self.rect().width(), diff - self.rect().height())
            elif self._edge == "left":
                diff = self.x() - scenePos.x()
                if r.width() - diff > 0:
                    self.setPos(scenePos.x(), self.y())
                    self.setRect(0, 0, r.width() + diff, self.rect().height())
                else:
                    self._edge = "right"
                    self.setPos(self.x() + self.rect().width(), self.y())
                    self.setRect(0, 0, diff - self.rect().width(), self.rect().height())
            elif self._edge == "bottom":
                if r.height() > 0:
                    pos = self.mapFromScene(scenePos)
                    self.setRect(0, 0, self.rect().width(), pos.y())
                else:
                    self.setRect(0, 0, self.rect().width(), abs(scenePos.y() - self.y()))
                    self.setPos(self.x(), scenePos.y())
                    self._edge = "top"
            elif self._edge == "right":
                if r.width() > 0:
                    pos = self.mapFromScene(scenePos)
                    self.setRect(0, 0, pos.x(), self.rect().height())
                else:
                    self.setRect(0, 0, abs(scenePos.x() - self.x()), self.rect().height())
                    self.setPos(scenePos.x(), self.y())
                    self._edge = "left"

        QtWidgets.QGraphicsItem.mouseMoveEvent(self, event)

    def hoverMoveEvent(self, event):
        """
        Handles all hover move events.

        :param event: QGraphicsSceneHoverEvent instance
        """

        # objects on the background layer don't need cursors
        if self.zValue() >= 0:
            if event.pos().x() > (self.rect().right() - self._border):
                self._graphics_view.setCursor(QtCore.Qt.SizeHorCursor)
            elif event.pos().x() < (self.rect().left() + self._border):
                self._graphics_view.setCursor(QtCore.Qt.SizeHorCursor)
            elif event.pos().y() < (self.rect().top() + self._border):
                self._graphics_view.setCursor(QtCore.Qt.SizeVerCursor)
            elif event.pos().y() > (self.rect().bottom() - self._border):
                self._graphics_view.setCursor(QtCore.Qt.SizeVerCursor)
            else:
                self._graphics_view.setCursor(QtCore.Qt.SizeAllCursor)

    def hoverLeaveEvent(self, event):
        """
        Handles all hover leave events.

        :param event: QGraphicsSceneHoverEvent instance
        """

        # objects on the background layer don't need cursors
        if self.zValue() >= 0:
            self._graphics_view.setCursor(QtCore.Qt.ArrowCursor)

    def _styleSvg(self, element):
        """
        Add style from the shape item to the SVG element that we will
        export
        """
        style = ""
        pen = self.pen()
        element.set("fill", "#{}".format(hex(self.brush().color().rgba())[4:]))
        element.set("fill-opacity", str(self.brush().color().alphaF()))

        dasharray = self.QT_DASH_TO_SVG[pen.style()]
        if dasharray is None: # No border to the element
            return element
        elif dasharray == "":
            pass # Solid line
        else:
            element.set("stroke-dasharray", dasharray)
        element.set("stroke-width", str(pen.width()))
        element.set("stroke", "#" + hex(pen.color().rgba())[4:])
        return element

    def fromSvg(self, svg):
        """
        Import element informations from an SVG
        """
        svg = ET.fromstring(svg)
        width = float(svg.get("width", self.rect().width()))
        height = float(svg.get("height", self.rect().height()))
        self.setRect(0, 0, width, height)

        pen = QtGui.QPen()
        brush = QtGui.QBrush(QtCore.Qt.SolidPattern)

        if len(svg):
            if svg[0].get("stroke-width"):
                pen.setWidth(int(svg[0].get("stroke-width")))
            if svg[0].get("stroke"):
                pen.setColor(colorFromSvg(svg[0].get("stroke")))
            if svg[0].get("fill"):
                new_color = colorFromSvg(svg[0].get("fill"))
                color = brush.color()
                color.setBlue(new_color.blue())
                color.setRed(new_color.red())
                color.setGreen(new_color.green())
                brush.setColor(color)
            if svg[0].get("fill-opacity"):
                color = brush.color()
                color.setAlphaF(float(svg[0].get("fill-opacity")))
                brush.setColor(color)

            # Map SVG stroke style (border of the element to the Qt version)
            if not svg[0].get("stroke"):
                pen.setStyle(QtCore.Qt.NoPen)
            else:
                pen.setStyle(QtCore.Qt.SolidLine)
                stroke = svg[0].get("stroke-dasharray")
                if stroke:
                    for (qt_stroke, svg_stroke) in self.QT_DASH_TO_SVG.items():
                         if svg_stroke == stroke:
                            pen.setStyle(qt_stroke)

        self.setPen(pen)
        self.setBrush(brush)
        self.update()
