#!/usr/bin/env python3
import contextlib

import PySide6.QtWidgets as Qw
import PySide6.QtGui as Qg
import PySide6.QtCore as Qc

import Window1
import ui_utils
import xasy2asy as x2a

from xasyTransform import xasyTransform as xT


class AnotherWindow(Qw.QWidget):
    def __init__(self, shape, parent: "Window1.MainWindow1"):
        super().__init__()
        self.shape = shape
        self.parent = parent
        self.newShape = self.shape
        self.layout = Qw.QVBoxLayout(self)

        # Initialize tab screen
        self.tabs = Qw.QTabWidget()
        self.fillTab = Qw.QWidget()
        self.lineTab = Qw.QWidget()
        self.arrowTab = Qw.QWidget()
        self.othersTab = Qw.QWidget()
        self.tabs.resize(300,200)
        self.fillTab.layout = Qw.QVBoxLayout(self.fillTab)
        self.lineTab.layout = Qw.QVBoxLayout(self.lineTab)
        self.arrowTab.layout = Qw.QVBoxLayout(self.arrowTab)
        self.othersTab.layout = Qw.QVBoxLayout(self.othersTab)
        self.tabs.addTab(self.fillTab,"Fill Options")
        self.tabs.addTab(self.lineTab,"Line Options")
        self.tabs.addTab(self.arrowTab,"Arrow Options")
        self.tabs.addTab(self.othersTab,"Misc. Options")

        self.layout.addWidget(self.tabs)
        self.setLayout(self.layout)
        self.setWindowTitle("Shape Options Window")

        self.label = Qw.QLabel("Fill:")
        self.fillTab.layout.addWidget(self.label)
        self.fillButton = Qw.QComboBox()
        self.fillButton.addItem("Unfilled")
        self.fillButton.addItem("Filled")
        self.fillButton.currentIndexChanged.connect(self.fillChange)
        self.fillTab.layout.addWidget(self.fillButton)

        if isinstance(self.shape, x2a.asyArrow):
            self.colorButton = Qw.QPushButton("Set Line Colour")
            self.colorButton.clicked.connect(self.pickColor)
            self.fillTab.layout.addWidget(self.colorButton)

            self.colorButton = Qw.QPushButton("Set Fill Colour")
            self.colorButton.clicked.connect(self.pickFillColor)
            self.fillTab.layout.addWidget(self.colorButton)

        elif isinstance(self.shape, x2a.xasyShape):
            self.colorButton = Qw.QPushButton("Set Colour")
            self.colorButton.clicked.connect(self.pickColor)
            self.fillTab.layout.addWidget(self.colorButton)

        self.label = Qw.QLabel("Reflection:")
        self.othersTab.layout.addWidget(self.label)
        self.reflectionButton = Qw.QComboBox()
        self.reflectionButton.addItem("None")
        self.reflectionButton.addItem("Horizontal")
        self.reflectionButton.addItem("Vertical")
        self.reflectionButton.currentIndexChanged.connect(self.reflectionChange)
        self.othersTab.layout.addWidget(self.reflectionButton)

        self.label = Qw.QLabel("Opacity:")
        self.othersTab.layout.addWidget(self.label)
        self.opacityBox = Qw.QLineEdit()
        self.othersTab.layout.addWidget(self.opacityBox)
        self.opacityBox.setPlaceholderText(str(self.shape.pen.opacity))

        self.label = Qw.QLabel("Arrowhead:")
        self.arrowTab.layout.addWidget(self.label)
        self.arrowheadButton = Qw.QComboBox()
        self.arrowList = ["None","Arrow","ArcArrow"]
        for arrowMode in self.arrowList:
            self.arrowheadButton.addItem(arrowMode)
        self.arrowheadButton.currentIndexChanged.connect(self.arrowheadChange)
        self.arrowTab.layout.addWidget(self.arrowheadButton)

        self.label = Qw.QLabel("Line Style:")
        self.lineTab.layout.addWidget(self.label)
        self.linestyleButton = Qw.QComboBox()
        self.lineList = ["solid","dashed","dotted","dashdotted"]

        for lineMode in self.lineList:
            self.linestyleButton.addItem(lineMode)
        self.linestyleButton.currentIndexChanged.connect(self.linestyleChange)
        self.lineTab.layout.addWidget(self.linestyleButton)
        self.linestyleButton.setCurrentIndex(self.lineList.index(self.shape.pen.style))

        self.label = Qw.QLabel("Line Cap Style:")
        self.lineTab.layout.addWidget(self.label)
        self.lineCapStyleButton = Qw.QComboBox()
        self.lineCapListStrings = ["extendcap","flatcap","roundcap"] #Is there a way to pull these directly
        self.lineCapList = [Qc.Qt.PenCapStyle.SquareCap,Qc.Qt.PenCapStyle.FlatCap,Qc.Qt.PenCapStyle.RoundCap]

        for lineMode in self.lineCapListStrings:
            self.lineCapStyleButton.addItem(lineMode)
        self.lineCapStyleButton.currentIndexChanged.connect(self.lineCapStyleChange)
        self.lineTab.layout.addWidget(self.lineCapStyleButton)
        self.lineCapStyleButton.setCurrentIndex(self.lineCapList.index(self.shape.pen.capStyle))

        #TODO: Make this a function.
        if not isinstance(self.shape, x2a.xasyShape):
            self.fillButton.setCurrentIndex(int(self.shape.arrowSettings["fill"]))
            if isinstance(self.shape, x2a.asyArrow):
                self.arrowheadButton.setCurrentIndex(int(self.shape.arrowSettings["active"]))
            else:
                self.arrowheadButton.setDisabled(True)
        else:
            self.fillButton.setCurrentIndex(int(self.shape.path.fill))

        if isinstance(self.shape, x2a.asyArrow) and self.shape.arrowSettings["active"]: #Make these all a list or something.
            self.label = Qw.QLabel("Arrow Style:")
            self.arrowTab.layout.addWidget(self.label)
            self.arrowstyleButton = Qw.QComboBox()
            for arrowStyle in self.shape.arrowStyleList:
                self.arrowstyleButton.addItem(arrowStyle if arrowStyle else "(default)")
            self.arrowstyleButton.currentIndexChanged.connect(self.arrowstyleChange)
            self.arrowTab.layout.addWidget(self.arrowstyleButton)

            self.label = Qw.QLabel("Arrow Size:")
            self.arrowTab.layout.addWidget(self.label)
            self.arrowSizeBox = Qw.QLineEdit()
            self.arrowTab.layout.addWidget(self.arrowSizeBox)
            self.arrowSizeBox.setPlaceholderText(self.getInfo("DefaultHead.size(currentpen)"))

            self.label = Qw.QLabel("Arrow Angle:")
            self.arrowTab.layout.addWidget(self.label)
            self.arrowAngleBox = Qw.QLineEdit()
            self.arrowTab.layout.addWidget(self.arrowAngleBox)
            self.arrowAngleBox.setPlaceholderText(self.getInfo("arrowangle"))

            self.label = Qw.QLabel("Arrow Fill:")
            self.arrowTab.layout.addWidget(self.label)
            self.arrowFillButton = Qw.QComboBox()
            for arrowFillStyle in self.shape.arrowFillList:
                self.arrowFillButton.addItem(arrowFillStyle if arrowFillStyle else "(default)")
            self.arrowFillButton.currentIndexChanged.connect(self.arrowFillChange)
            self.arrowTab.layout.addWidget(self.arrowFillButton)

            self.arrowstyleButton.setCurrentIndex(int(self.shape.arrowSettings["style"]))
            self.arrowFillButton.setCurrentIndex(int(self.shape.arrowSettings["fill"]))

        self.fillTab.setLayout(self.fillTab.layout)
        self.lineTab.setLayout(self.lineTab.layout)
        self.arrowTab.setLayout(self.arrowTab.layout)
        self.othersTab.setLayout(self.othersTab.layout)

        self.confirmButton = Qw.QPushButton("Render")
        self.confirmButton.clicked.connect(self.renderChanges)
        self.layout.addWidget(self.confirmButton)

    def arrowheadChange(self, i):
        #None, {Arrow, ArcArrow} x {(),(SimpleHead),(HookHead),(TeXHead)}
        if isinstance(self.shape, x2a.xasyShape):
            if i != 0:
                if isinstance(self.newShape,x2a.asyArrow):
                    self.newShape.arrowSettings["active"] = i
                else:
                    self.newShape = self.shape.arrowify(arrowhead=i)
        else:
            self.newShape.arrowSettings["active"] = i #Simplify the logic

    def arrowstyleChange(self, i):
        self.newShape.arrowSettings["style"] = i

    def linestyleChange(self, i): #I think add an attribute to asyPen
        self.shape.pen.setStyle(self.lineList[i])

    def lineCapStyleChange(self, i): #I think add an attribute to asyPen
        self.shape.pen.setCapStyle(self.lineCapList[i])

    def fillChange(self, i):
        if isinstance(self.shape, x2a.asyArrow):
            self.shape.arrowSettings["fill"] = bool(i)
        elif (self.shape.path.fill != bool(i)) and not isinstance(self.newShape, x2a.asyArrow):
            if self.newShape:
                self.newShape = self.newShape.swapFill()
        if isinstance(self.newShape, x2a.asyArrow):
            self.newShape.arrowSettings["fill"] = bool(i)

    def reflectionChange(self, i): #TODO: Modernize this.
        reflectionList = [[1,1],[1,-1],[-1,1]]
        self.parent.newTransform = xT.makeScaleTransform(*reflectionList[i], self.parent.currentAnchor).toQTransform()
        self.parent.currentlySelectedObj['selectedIndex'] = self.parent.mostRecentObject
        self.parent.releaseTransform()
        self.parent.newTransform = Qg.QTransform()

    def sizeChange(self):
        try:
            newSize = self.arrowSizeBox.text()
            self.newShape.arrowSettings["size"] = float(newSize)
        except Exception:
            return #TODO: Show error message.

    def angleChange(self): #Refactor this with the above.
        try:
            newAngle = self.arrowAngleBox.text()
            self.newShape.arrowSettings["angle"] = float(newAngle)
        except Exception:
            return #TODO: Show error message.

    def arrowFillChange(self, i): #Can I lambda this?
        self.newShape.arrowSettings["fill"] = i

    def opacityChange(self):
        newOpacity = self.opacityBox.text()
        with contextlib.suppress(Exception):
            newOpacity = int(newOpacity)
            if 0 <= newOpacity <= 255:
                self.shape.pen.setOpacity(newOpacity)
                self.newShape.pen.setOpacity(newOpacity)

    def renderChanges(self): #Pull from text boxes here.
        self.opacityChange()
        if isinstance(self.shape, x2a.asyArrow) and self.shape.arrowSettings["active"]:
            self.sizeChange()
            self.angleChange()
        elif not isinstance(self.shape, x2a.asyArrow):
            self.renderLineStyle()
        if self.newShape:
            self.parent.replaceObject(self.parent.contextWindowObject,self.newShape)
        self.parent.terminateContextWindow()

    def getInfo(self,value):
        """ Find out the size of an arbitrary Asymptote pen """
        self.asyEngine = self.parent.asyEngine
        assert isinstance(self.asyEngine, x2a.AsymptoteEngine)
        assert self.asyEngine.active

        fout = self.asyEngine.ostream
        fin = self.asyEngine.istream

        fout.write("write(_outpipe,{},endl);\n".format(value))
        fout.write(self.asyEngine.xasy)
        fout.flush()

        return fin.readline()

    def getPattern(self,pattern,path):
        """ Find out the adjusted pattern of an Asymptote pen """
        self.asyEngine = self.parent.asyEngine
        assert isinstance(self.asyEngine, x2a.AsymptoteEngine)
        assert self.asyEngine.active

        fout = self.asyEngine.ostream
        fin = self.asyEngine.istream

        fout.write(f"write(_outpipe,adjust({pattern},arclength({path}),cyclic({path})),endl);\n")
        fout.write(self.asyEngine.xasy)
        fout.flush()

        return fin.readline()

    def renderLineStyle(self):
        #Should only get called with asy shapes
        if not self.newShape:
            self.newShape=self.shape
        if not isinstance(self.newShape,x2a.asyArrow):
            rawPattern = self.getPattern(self.lineList[self.linestyleButton.currentIndex()],self.newShape.path.getCode())
        else:
            #self.newShape.updateCode() #idk if this is necessary.
            rawPattern = self.getPattern(self.lineList[self.linestyleButton.currentIndex()],self.newShape.code)

        pattern = []
        if len(rawPattern) == 5:
            pattern=[1,0]
        else:
            for value in rawPattern[2:-3].split(' '):
                pattern.append(float(value)+1)

        try:
            self.newShape.pen.setDashPattern(pattern) #pen is going to be a asyPen, add as an attribute
        except Exception:
            ui_utils.error_msgbox(self, "Pen format error")

    def pickColor(self):
        self.colorDialog = Qw.QColorDialog(x2a.asyPen.convertToQColor(self.shape.pen.color), self)
        self.colorDialog.show()
        if self.colorDialog.exec():
            self.shape.pen.setColorFromQColor(self.colorDialog.selectedColor())
            self.parent.updateFrameDispColor()

    def pickFillColor(self): #This is a copy of the above, how do you set the var as it is set?
        self.colorDialog = Qw.QColorDialog(x2a.asyPen.convertToQColor(self.shape.fillPen.color), self)
        self.colorDialog.show()
        if self.colorDialog.exec():
            self.shape.fillPen.setColorFromQColor(self.colorDialog.selectedColor())
            self.parent.updateFrameDispColor()
