from __future__ import absolute_import, print_function

# Standard modules
import logging

import xml.etree.ElementTree as ET

from ast import literal_eval
from qtpy import QtGui, QtCore, QtWidgets
from qtpy.QtCore import Qt

# Custom modules
from .canvas.block import Block
from .. import base
from .canvas.flowgraph import FlowgraphScene, Flowgraph
from .canvas.colors import LIGHT_FLOWGRAPH_BACKGROUND_COLOR, DARK_FLOWGRAPH_BACKGROUND_COLOR

from ...core.generator import Generator

# Logging
log = logging.getLogger(f"grc.application.{__name__}")

DEFAULT_MAX_X = 400
DEFAULT_MAX_Y = 300


class FlowgraphView(
    QtWidgets.QGraphicsView, base.Component
):  # added base.Component so it can see platform
    def __init__(self, parent, platform, filename=None):
        super(FlowgraphView, self).__init__()
        self.setParent(parent)
        self.setAlignment(Qt.AlignLeft | Qt.AlignTop)

        self.setScene(FlowgraphScene(self, platform))

        self.scalefactor = 0.8
        self.scale(self.scalefactor, self.scalefactor)

        self.setSceneRect(0, 0, DEFAULT_MAX_X, DEFAULT_MAX_Y)
        if filename is not None:
            self.readFile(filename)
        else:
            self.initEmpty()

        self.fitInView(self.scene().sceneRect(), QtCore.Qt.KeepAspectRatio)
        if self.app.theme == "dark":
            self.setBackgroundBrush(QtGui.QBrush(DARK_FLOWGRAPH_BACKGROUND_COLOR))
        else:
            self.setBackgroundBrush(QtGui.QBrush(LIGHT_FLOWGRAPH_BACKGROUND_COLOR))

        self.isPanning = False
        self.mousePressed = False

        self.setDragMode(self.RubberBandDrag)

        self.generator = None
        self.process = None

    def createActions(self, actions):
        log.debug("Creating actions")

    def contextMenuEvent(self, event):
        super(FlowgraphView, self).contextMenuEvent(event)

    def createMenus(self, actions, menus):
        log.debug("Creating menus")

    def createToolbars(self, actions, toolbars):
        log.debug("Creating toolbars")

    def get_generator(self) -> Generator:
        return self.generator

    def process_is_done(self) -> bool:
        if self.process is None:
            return True
        else:
            return (False if self.process.returncode is None else True)

    def readFile(self, filename):
        tree = ET.parse(filename)

        for xml_block in tree.findall("block"):
            attrib = {}
            params = []
            block_key = xml_block.find("key").text

            for param in xml_block.findall("param"):
                key = param.find("key").text
                value = param.find("value").text
                if key.startswith("_"):
                    attrib[key] = literal_eval(value)
                else:
                    params.append((key, value))

            # Find block in tree so that we can pull out label
            try:
                block = self.platform.blocks[block_key]

                new_block = Block(block_key, block.label, attrib, params)
                self.scene.addItem(new_block)
                self.newElement.emit(new_block)
            except:
                log.warning("Block '{}' was not found".format(block_key))

        # This part no longer works now that we are using a Scene with GraphicsItems, but I'm sure there's still some way to do it
        # bounds = self.scene.itemsBoundingRect()
        # self.setSceneRect(bounds)
        # self.fitInView(bounds)

    def initEmpty(self):
        self.setSceneRect(0, 0, DEFAULT_MAX_X, DEFAULT_MAX_Y)

    def zoom(self, factor: float, anchor=QtWidgets.QGraphicsView.AnchorViewCenter):
        new_scalefactor = self.scalefactor * factor

        if new_scalefactor > 0.25 and new_scalefactor < 2.5:
            self.scalefactor = new_scalefactor
            self.setTransformationAnchor(anchor)
            self.setResizeAnchor(anchor)
            self.scale(factor, factor)

    def zoomOriginal(self):
        # TODO: Original scale factor as a constant?
        self.zoom(0.8 / self.scalefactor)

    def wheelEvent(self, event):
        # TODO: Support multi touch drag and drop for scrolling through the view
        if event.modifiers() == Qt.ControlModifier:
            factor = 1.1 if event.angleDelta().y() > 0 else (1.0 / 1.1)
            self.zoom(factor, anchor=QtWidgets.QGraphicsView.AnchorUnderMouse)

            # if new_scalefactor > 0.25 and new_scalefactor < 2.5:
            #     self.scalefactor = new_scalefactor
            #     self.setTransformationAnchor(QtWidgets.QGraphicsView.NoAnchor)
            #     self.setResizeAnchor(QtWidgets.QGraphicsView.NoAnchor)

            #     old_pos = self.mapToScene(event.pos())

            #     self.scale(factor, factor)
            #     new_pos = self.mapToScene(event.pos())

            #     delta = new_pos - old_pos
            #     self.translate(delta.x(), delta.y())

        elif event.modifiers() == Qt.ShiftModifier:
            self.horizontalScrollBar().setValue(
                self.horizontalScrollBar().value() - event.angleDelta().y())
        else:
            QtWidgets.QGraphicsView.wheelEvent(self, event)

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.mousePressed = True
            # This will pass the mouse move event to the scene
            super(FlowgraphView, self).mousePressEvent(event)

        elif event.button() == Qt.MiddleButton:
            self.isPanning = True
            self.dragPos = event.pos()
            self.setCursor(Qt.ClosedHandCursor)
            event.accept()

    def mouseMoveEvent(self, event):
        if self.isPanning:
            new_pos = event.pos()
            diff = new_pos - self.dragPos
            self.dragPos = new_pos
            self.horizontalScrollBar().setValue(
                self.horizontalScrollBar().value() - diff.x()
            )
            self.verticalScrollBar().setValue(
                self.verticalScrollBar().value() - diff.y()
            )
            event.accept()
        else:
            # This will pass the mouse move event to the scene
            super(FlowgraphView, self).mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.mousePressed = False

        elif event.button() == Qt.MiddleButton:
            self.isPanning = False
            self.setCursor(Qt.ArrowCursor)
            event.accept()

        super(FlowgraphView, self).mouseReleaseEvent(event)

    def keyPressEvent(self, event):
        super(FlowgraphView, self).keyPressEvent(event)

    def keyReleaseEvent(self, event):
        super(FlowgraphView, self).keyPressEvent(event)

    def mouseDoubleClickEvent(self, event):
        # This will pass the double click event to the scene
        super(FlowgraphView, self).mouseDoubleClickEvent(event)
