class RSBGDocker(DockWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Rogudator's speech bubble generator")
        mainLayout = QVBoxLayout()

        self.addOnPage = QPushButton("Add on Page")
        mainLayout.addWidget(self.addOnPage)

        previewLabel = QLabel("Preview")
        mainLayout.addWidget(previewLabel)

        self.preview = QSvgWidget(self)
        self.preview.setMinimumHeight(200)
        #self.preview.setAspectRatioMode(Qt.AspectRatioMode.KeepAspectRatio)
        mainLayout.addWidget(self.preview)

        bubbleTypes = QGroupBox()
        bubbleTypes.setTitle("Bubble type")
        bubbleTypesLayout = QHBoxLayout()
        self.squareBubble = QRadioButton(self)
        self.squareBubble.setText("Square")
        bubbleTypesLayout.addWidget(self.squareBubble)
        self.roundBubble = QRadioButton(self)
        self.roundBubble.setText("Round")
        self.roundBubble.setChecked(True)
        bubbleTypesLayout.addWidget(self.roundBubble)
        bubbleTypes.setLayout(bubbleTypesLayout)
        self.bubbleColorButton = QPushButton(self)
        self.bubbleColor = QColor("white")
        bubbleColorImage = QPixmap(32, 32)
        bubbleColorImage.fill(self.bubbleColor)
        bubbleColorIcon = QIcon(bubbleColorImage)
        self.bubbleColorButton.setIcon(bubbleColorIcon)
        self.bubbleColorButton.setFixedWidth(self.bubbleColorButton.height())
        bubbleTypesLayout.addWidget(self.bubbleColorButton)
        mainLayout.addWidget(bubbleTypes)

        outlineSize = QGroupBox("Outline")
        outlineSliderAndSpinBox = QHBoxLayout()
        self.outlineSlider = QSlider(self)
        self.outlineSlider.setMinimum(0)
        self.outlineSlider.setMaximum(10)
        self.outlineSlider.setValue(3)
        self.outlineSlider.setOrientation(Qt.Orientation.Horizontal)
        outlineSliderAndSpinBox.addWidget(self.outlineSlider)
        self.outlineSpinBox = QSpinBox(self)
        self.outlineSpinBox.setMinimum(0)
        self.outlineSpinBox.setValue(3)
        outlineSliderAndSpinBox.addWidget(self.outlineSpinBox)
        self.outlineColorButton = QPushButton(self)
        self.outlineColor = QColor("black")
        outlineColorImage = QPixmap(32, 32)
        outlineColorImage.fill(self.outlineColor)
        outlineColorIcon = QIcon(outlineColorImage)
        self.outlineColorButton.setIcon(outlineColorIcon)
        self.outlineColorButton.setFixedWidth(self.outlineColorButton.height())
        outlineSliderAndSpinBox.addWidget(self.outlineColorButton)
        outlineSize.setLayout(outlineSliderAndSpinBox)
        mainLayout.addWidget(outlineSize)

        speechGroup = QGroupBox("Speech")
        speechGroupLayout = QVBoxLayout()

        fontRow = QHBoxLayout()

        self.speechFont = QFontComboBox(self)
        fontRow.addWidget(self.speechFont)

        self.speechFontSize = QSpinBox(self)
        self.speechFontSize.setValue(14)
        self.speechFontSize.setMinimum(1)
        fontRow.addWidget(self.speechFontSize)

        self.currentFontColorButton = QPushButton(self)
        self.speechFontColor = QColor("black")
        fontColorImage = QPixmap(32, 32)
        fontColorImage.fill(self.speechFontColor)
        fontColorIcon = QIcon(fontColorImage)
        self.currentFontColorButton.setIcon(fontColorIcon)
        self.currentFontColorButton.setFixedWidth(
            self.currentFontColorButton.height())
        fontRow.addWidget(self.currentFontColorButton)

        speechGroupLayout.addLayout(fontRow)

        self.bubbleText = QTextEdit("Rogudator's speech bubble generator!")
        speechGroupLayout.addWidget(self.bubbleText)

        self.autocenter = QCheckBox(self)
        self.autocenter.setText("Center automatically")
        self.autocenter.setChecked(True)
        speechGroupLayout.addWidget(self.autocenter)

        self.averageLineLength = QGroupBox()
        averageLineLengthSliderAndSpinBox = QHBoxLayout()
        self.averageLineLengthSlider = QSlider(self)
        self.averageLineLengthSlider.setMinimum(0)
        self.averageLineLengthSlider.setMaximum(100)
        self.averageLineLengthSlider.setOrientation(Qt.Orientation.Horizontal)
        averageLineLengthSliderAndSpinBox.addWidget(
            self.averageLineLengthSlider)
        self.averageLineLengthSpinBox = QSpinBox(self)
        self.averageLineLengthSpinBox.setMinimum(0)
        averageLineLengthSliderAndSpinBox.addWidget(
            self.averageLineLengthSpinBox)
        self.averageLineLength.setLayout(averageLineLengthSliderAndSpinBox)
        self.averageLineLength.setDisabled(True)
        speechGroupLayout.addWidget(self.averageLineLength)

        speechGroup.setLayout(speechGroupLayout)
        mainLayout.addWidget(speechGroup)

        tailSize = QGroupBox()
        tailSize.setTitle("Tail size")
        tailSliderAndSpinBox = QHBoxLayout()
        self.tailSlider = QSlider(self)
        self.tailSlider.setMinimum(0)
        self.tailSlider.setMaximum(self.speechFontSize.value() * 10)
        self.tailSlider.setOrientation(Qt.Orientation.Horizontal)
        tailSliderAndSpinBox.addWidget(self.tailSlider)
        self.tailSpinBox = QSpinBox(self)
        self.tailSpinBox.setMinimum(0)
        self.tailSpinBox.setMaximum(self.speechFontSize.value() * 10)
        tailSliderAndSpinBox.addWidget(self.tailSpinBox)
        tailSize.setLayout(tailSliderAndSpinBox)
        mainLayout.addWidget(tailSize)

        self.tailPositions = QGroupBox()
        self.tailPositions.setTitle("Tail position")
        tailPositionsLayout = QHBoxLayout()
        self.tailPosition = []
        for i in range(8):
            self.tailPosition.append(QRadioButton(self))
            self.tailPosition[i].setText(str(i + 1))
            self.tailPosition[i].clicked.connect(self.updatePreview)
            tailPositionsLayout.addWidget(self.tailPosition[i])

        self.tailPositions.setLayout(tailPositionsLayout)
        self.tailPositions.setDisabled(True)
        mainLayout.addWidget(self.tailPositions)

        self.updatePreview()

        self.addOnPage.clicked.connect(self.addOnPageShape)
        self.squareBubble.clicked.connect(self.updatePreview)
        self.roundBubble.clicked.connect(self.updatePreview)
        self.bubbleColorButton.clicked.connect(self.changeBubbleColor)
        self.outlineSlider.valueChanged.connect(self.outlineSpinBoxUpdate)
        self.outlineSpinBox.valueChanged.connect(self.outlineSliderUpdate)
        self.outlineSpinBox.valueChanged.connect(self.updatePreview)
        self.outlineColorButton.clicked.connect(self.changeOutlineColor)
        self.bubbleText.textChanged.connect(self.updatePreview)
        self.speechFontSize.valueChanged.connect(self.updatePreview)
        self.speechFontSize.valueChanged.connect(self.tailSliderUpdateMaximum)
        self.currentFontColorButton.clicked.connect(self.changeFontColor)
        self.speechFont.currentFontChanged.connect(self.updatePreview)
        self.autocenter.stateChanged.connect(self.enableAverageLineLength)
        self.autocenter.clicked.connect(self.updatePreview)
        self.averageLineLengthSlider.valueChanged.connect(
            self.averageLineLengthSpinBoxUpdate)
        self.averageLineLengthSpinBox.valueChanged.connect(self.updatePreview)
        self.averageLineLengthSpinBox.valueChanged.connect(
            self.averageLineLengthSliderUpdate)
        self.tailSlider.valueChanged.connect(self.tailSpinBoxUpdate)
        self.tailSpinBox.valueChanged.connect(self.tailSliderUpdate)
        self.tailSpinBox.valueChanged.connect(self.updatePreview)

        self.scrollMainLayout = QScrollArea(self)
        self.scrollMainLayout.setWidgetResizable(True)
        self.scrollMainLayout.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)

        widget = QWidget()
        widget.setLayout(mainLayout)
        self.scrollMainLayout.setWidget(widget)
        self.setWidget(self.scrollMainLayout)
        self.show()

    def tailSliderUpdateMaximum(self):
        self.tailSlider.setMaximum(self.speechFontSize.value() * 10)
        self.tailSpinBox.setMaximum(self.speechFontSize.value() * 10)

    def changeBubbleColor(self):
        self.bubbleColor = QColorDialog.getColor(self.bubbleColor)
        colorImage = QPixmap(32, 32)
        colorImage.fill(self.bubbleColor)
        colorIcon = QIcon(colorImage)
        self.bubbleColorButton.setIcon(colorIcon)
        self.updatePreview()

    def changeFontColor(self):
        self.speechFontColor = QColorDialog.getColor(self.speechFontColor)
        colorImage = QPixmap(32, 32)
        colorImage.fill(self.speechFontColor)
        colorIcon = QIcon(colorImage)
        self.currentFontColorButton.setIcon(colorIcon)
        self.updatePreview()

    def changeOutlineColor(self):
        self.outlineColor = QColorDialog.getColor(self.outlineColor)
        colorImage = QPixmap(32, 32)
        colorImage.fill(self.outlineColor)
        colorIcon = QIcon(colorImage)
        self.outlineColorButton.setIcon(colorIcon)
        self.updatePreview()

    def outlineSpinBoxUpdate(self):
        self.outlineSpinBox.setValue(self.outlineSlider.value())

    def outlineSliderUpdate(self):
        if self.outlineSpinBox.value() < 51:
            self.outlineSlider.setValue(self.outlineSpinBox.value())

    def tailSpinBoxUpdate(self):
        self.tailSpinBox.setValue(self.tailSlider.value())
        if self.tailSlider.value() == 0:
            self.tailPositions.setDisabled(True)
        else:
            self.tailPositions.setDisabled(False)

    def tailSliderUpdate(self):
        if self.tailSpinBox.value() < 101:
            self.tailSlider.setValue(self.tailSpinBox.value())

    def enableAverageLineLength(self):
        if self.autocenter.isChecked():
            self.averageLineLength.setDisabled(True)
        else:
            self.averageLineLength.setDisabled(False)

    def averageLineLengthSpinBoxUpdate(self):
        self.averageLineLengthSpinBox.setValue(
            self.averageLineLengthSlider.value())

    def averageLineLengthSliderUpdate(self):
        if self.averageLineLengthSpinBox.value() < 101:
            self.averageLineLengthSlider.setValue(
                self.averageLineLengthSpinBox.value())

    def getSpeechLines(self, text, lineLength):
        size = 0
        speach = ""
        lines = []
        if (lineLength > 0):
            words = text.split(" ")
            for word in words:
                speach += word
                size += len(word)
                if size < lineLength:
                    speach += " "
                else:
                    size = 0
                    lines.append(speach)
                    speach = ""
            if (speach != "") and (speach != " "):
                lines.append(speach.strip())
        else:
            lines = text.split("\n")

        return lines

    def getPreview(self):

        lineLength = int((pow(
            (len(self.bubbleText.toPlainText())), 1 / 2)) * 1.8)
        if not (self.autocenter.isChecked()):
            lineLength = self.averageLineLengthSpinBox.value()
        lines = self.getSpeechLines(self.bubbleText.toPlainText(), lineLength)

        biggestLine = ""
        for line in lines:
            if (len(line) > len(biggestLine)):
                biggestLine = line

        #Calculate text box size
        font = self.speechFont.currentFont()
        font.setPixelSize(int(self.speechFontSize.value() * 1.3))
        fontSize = self.speechFontSize.value()
        textHeight = int(fontSize * (len(lines)) -
                         (fontSize - QFontMetrics(font).capHeight()))
        textWidth = QFontMetrics(font).width(biggestLine)
        tailLength = self.tailSpinBox.value()

        framePadding = fontSize
        tailPadding = tailLength
        bubblePadding = int(fontSize * 1.5)

        textTag = "<text x=\"{}\" y=\"{}\" style=\"font-size:{};font-family:{};fill:{};text-anchor:middle\" >{}</text>"
        text = ""
        textStartX = framePadding + tailPadding + bubblePadding + (int(
            textWidth / 2))
        textStartY = framePadding + tailPadding + bubblePadding + QFontMetrics(
            font).capHeight()

        for line in lines:
            text += textTag.format(textStartX, textStartY, fontSize,
                                   font.family(), self.speechFontColor.name(),
                                   line)
            textStartY += fontSize

        bubbleCoordinatesX0 = framePadding + tailPadding
        bubbleCoordinatesY0 = framePadding + tailPadding
        bubbleCoordinatesXHalf = framePadding + tailPadding + bubblePadding + (
            int(textWidth / 2))
        bubbleCoordinatesYHalf = framePadding + tailPadding + bubblePadding + (
            int(textHeight / 2))
        bubbleCoordinatesX = framePadding + tailPadding + bubblePadding + textWidth + bubblePadding
        bubbleCoordinatesY = framePadding + tailPadding + bubblePadding + textHeight + bubblePadding
        bubbleCoordinates = []
        bubbleCoordinates.append(
            BubbleCoordinates(bubbleCoordinatesXHalf, bubbleCoordinatesY0))
        bubbleCoordinates.append(
            BubbleCoordinates(bubbleCoordinatesX, bubbleCoordinatesY0))
        bubbleCoordinates.append(
            BubbleCoordinates(bubbleCoordinatesX, bubbleCoordinatesYHalf))
        bubbleCoordinates.append(
            BubbleCoordinates(bubbleCoordinatesX, bubbleCoordinatesY))
        bubbleCoordinates.append(
            BubbleCoordinates(bubbleCoordinatesXHalf, bubbleCoordinatesY))
        bubbleCoordinates.append(
            BubbleCoordinates(bubbleCoordinatesX0, bubbleCoordinatesY))
        bubbleCoordinates.append(
            BubbleCoordinates(bubbleCoordinatesX0, bubbleCoordinatesYHalf))
        bubbleCoordinates.append(
            BubbleCoordinates(bubbleCoordinatesX0, bubbleCoordinatesY0))

        i = 0
        bubbleCoordinatesString = "M"
        bubbleCoordinatesStringEnd = str(bubbleCoordinates[0].x) + "," + str(
            bubbleCoordinates[0].y) + "Z"
        while (i < 8):
            if (self.roundBubble.isChecked()):

                if (self.tailSpinBox.value() > 0):
                    #for coordinates in center (even)
                    textWidth01 = int(pow(textWidth, 1 / 2.8))
                    textHeight01 = int(pow(textHeight, 1 / 2))
                    #for coordinates in the corner (odd)
                    x04 = int(
                        (bubbleCoordinates[1].x - bubbleCoordinates[0].x) *
                        0.4)
                    x06 = int(
                        (bubbleCoordinates[1].x - bubbleCoordinates[0].x) *
                        0.6)
                    y04 = int(
                        (bubbleCoordinates[2].y - bubbleCoordinates[1].y) *
                        0.4)
                    y06 = int(
                        (bubbleCoordinates[2].y - bubbleCoordinates[1].y) *
                        0.6)
                    if i == 0 and self.tailPosition[i].isChecked():
                        bubbleCoordinatesString += str(
                            bubbleCoordinates[0].x - textWidth01) + "," + str(
                                bubbleCoordinates[0].y) + " L" + str(
                                    bubbleCoordinates[0].x) + "," + str(
                                        bubbleCoordinates[0].y -
                                        tailLength) + " " + str(
                                            bubbleCoordinates[0].x +
                                            textWidth01) + "," + str(
                                                bubbleCoordinates[0].y) + " "
                        bubbleCoordinatesStringEnd = str(
                            bubbleCoordinates[0].x - textWidth01) + "," + str(
                                bubbleCoordinates[0].y) + "Z"
                    elif i == 2 and self.tailPosition[i].isChecked():
                        bubbleCoordinatesString += str(
                            bubbleCoordinates[2].x) + "," + str(
                                bubbleCoordinates[2].y -
                                textHeight01) + " L" + str(
                                    bubbleCoordinates[2].x +
                                    tailLength) + "," + str(
                                        bubbleCoordinates[2].y) + " " + str(
                                            bubbleCoordinates[2].x
                                        ) + "," + str(bubbleCoordinates[2].y +
                                                      textHeight01) + " "
                    elif i == 4 and self.tailPosition[i].isChecked():
                        bubbleCoordinatesString += str(
                            bubbleCoordinates[4].x + textWidth01) + "," + str(
                                bubbleCoordinates[4].y) + " L" + str(
                                    bubbleCoordinates[4].x) + "," + str(
                                        bubbleCoordinates[4].y +
                                        tailLength) + " " + str(
                                            bubbleCoordinates[4].x -
                                            textWidth01) + "," + str(
                                                bubbleCoordinates[4].y) + " "
                    elif i == 6 and self.tailPosition[i].isChecked():
                        bubbleCoordinatesString += str(
                            bubbleCoordinates[6].x) + "," + str(
                                bubbleCoordinates[6].y +
                                textHeight01) + " L" + str(
                                    bubbleCoordinates[6].x -
                                    tailLength) + "," + str(
                                        bubbleCoordinates[6].y) + " " + str(
                                            bubbleCoordinates[6].x
                                        ) + "," + str(bubbleCoordinates[6].y -
                                                      textHeight01) + " "
                    elif i == 1 and self.tailPosition[i].isChecked():
                        bubbleCoordinatesString += "Q" + str(
                            bubbleCoordinates[1].x - x06
                        ) + "," + str(bubbleCoordinates[1].y) + " " + str(
                            int((bubbleCoordinates[1].x +
                                 bubbleCoordinates[1].x - x06) / 2)
                        ) + "," + str(
                            int((bubbleCoordinates[1].y + y04 +
                                 bubbleCoordinates[1].y) / 2)) + " L" + str(
                                     bubbleCoordinates[1].x + tailLength
                                 ) + "," + str(
                                     bubbleCoordinates[1].y - tailLength
                                 ) + " " + str(
                                     int((bubbleCoordinates[1].x +
                                          bubbleCoordinates[1].x - x04) / 2)
                                 ) + "," + str(
                                     int((bubbleCoordinates[1].y + y06 +
                                          bubbleCoordinates[1].y) /
                                         2)) + " Q" + str(
                                             bubbleCoordinates[1].x
                                         ) + "," + str(bubbleCoordinates[1].y +
                                                       y06) + " "
                    elif i == 3 and self.tailPosition[i].isChecked():
                        bubbleCoordinatesString += "Q" + str(
                            bubbleCoordinates[3].x) + "," + str(
                                bubbleCoordinates[3].y - y06) + " " + str(
                                    int(
                                        (bubbleCoordinates[3].x +
                                         bubbleCoordinates[3].x - x04) / 2
                                    )) + "," + str(
                                        int((bubbleCoordinates[3].y - y06 +
                                             bubbleCoordinates[3].y) / 2)
                                    ) + " L" + str(
                                        bubbleCoordinates[3].x + tailLength
                                    ) + "," + str(
                                        bubbleCoordinates[3].y + tailLength
                                    ) + " " + str(
                                        int((bubbleCoordinates[3].x +
                                             bubbleCoordinates[3].x - x06) / 2)
                                    ) + "," + str(
                                        int((bubbleCoordinates[3].y - y04 +
                                             bubbleCoordinates[3].y) /
                                            2)) + " Q" + str(
                                                bubbleCoordinates[3].x - x06
                                            ) + "," + str(
                                                bubbleCoordinates[3].y) + " "
                    elif i == 5 and self.tailPosition[i].isChecked():
                        bubbleCoordinatesString += "Q" + str(
                            bubbleCoordinates[5].x + x06
                        ) + "," + str(bubbleCoordinates[5].y) + " " + str(
                            int((bubbleCoordinates[5].x +
                                 bubbleCoordinates[5].x + x06) / 2)
                        ) + "," + str(
                            int((bubbleCoordinates[5].y - y04 +
                                 bubbleCoordinates[5].y) / 2)) + " L" + str(
                                     bubbleCoordinates[5].x - tailLength
                                 ) + "," + str(
                                     bubbleCoordinates[5].y + tailLength
                                 ) + " " + str(
                                     int((bubbleCoordinates[5].x +
                                          bubbleCoordinates[5].x + x04) / 2)
                                 ) + "," + str(
                                     int((bubbleCoordinates[5].y - y06 +
                                          bubbleCoordinates[5].y) /
                                         2)) + " Q" + str(
                                             bubbleCoordinates[5].x
                                         ) + "," + str(bubbleCoordinates[5].y -
                                                       y06) + " "
                    elif i == 7 and self.tailPosition[i].isChecked():
                        bubbleCoordinatesString += "Q" + str(
                            bubbleCoordinates[7].x) + "," + str(
                                bubbleCoordinates[7].y + y06) + " " + str(
                                    int(
                                        (bubbleCoordinates[7].x +
                                         bubbleCoordinates[7].x + x04) / 2
                                    )) + "," + str(
                                        int((bubbleCoordinates[7].y + y06 +
                                             bubbleCoordinates[7].y) / 2)
                                    ) + " L" + str(
                                        bubbleCoordinates[7].x - tailLength
                                    ) + "," + str(
                                        bubbleCoordinates[7].y - tailLength
                                    ) + " " + str(
                                        int((bubbleCoordinates[7].x +
                                             bubbleCoordinates[7].x + x06) / 2)
                                    ) + "," + str(
                                        int((bubbleCoordinates[7].y + y04 +
                                             bubbleCoordinates[7].y) /
                                            2)) + " Q" + str(
                                                bubbleCoordinates[7].x + x06
                                            ) + "," + str(
                                                bubbleCoordinates[7].y) + " "
                    else:
                        if (i % 2 == 0):
                            bubbleCoordinatesString += str(
                                bubbleCoordinates[i].x) + "," + str(
                                    bubbleCoordinates[i].y) + " "
                        else:
                            bubbleCoordinatesString += "Q" + str(
                                bubbleCoordinates[i].x) + "," + str(
                                    bubbleCoordinates[i].y) + " "
                else:
                    if (i % 2 == 0):
                        bubbleCoordinatesString += str(
                            bubbleCoordinates[i].x) + "," + str(
                                bubbleCoordinates[i].y) + " "
                    else:
                        bubbleCoordinatesString += "Q" + str(
                            bubbleCoordinates[i].x) + "," + str(
                                bubbleCoordinates[i].y) + " "
            elif (self.squareBubble.isChecked()):
                bubbleCoordinatesString += str(
                    bubbleCoordinates[i].x) + "," + str(
                        bubbleCoordinates[i].y) + " "
            i += 1
        bubbleCoordinatesString += bubbleCoordinatesStringEnd
        pathStyle = "style=\"fill:{};stroke:{};stroke-width:{};stroke-linejoin:round\"".format(
            self.bubbleColor.name(), self.outlineColor.name(),
            self.outlineSpinBox.value())
        bubble = "<path " + pathStyle + " d=\"" + bubbleCoordinatesString + "\"/>"

        frameWidth = framePadding + tailPadding + bubblePadding + textWidth + bubblePadding + tailPadding + framePadding
        frameHeight = framePadding + tailPadding + bubblePadding + textHeight + bubblePadding + tailPadding + framePadding

        result = "<svg width=\"{}\" height=\"{}\" >{}{}</svg>".format(
            frameWidth, frameHeight, bubble, text)

        return result

    def updatePreview(self):
        result = self.getPreview()
        resultBytes = bytearray(result, encoding='utf-8')
        self.preview.renderer().load(resultBytes)

    def addOnPageShape(self):
        result = self.getPreview()
        d = Krita.instance().activeDocument()
        root = d.rootNode()
        l3 = d.createVectorLayer(self.bubbleText.toPlainText()[:16])
        root.addChildNode(l3, None)
        l3.addShapesFromSvg(result)
        pass

    def canvasChanged(self, canvas):
        pass