"""
Module for the G-Code Editor, G-Code Editor can handle opening and saving the G-Code.
G-Code Editor is based on the QTextEdit Class
"""
import os
import re

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from Classes import Verschneidung, Werkzeug

import LayoutElements.mainWindowGUI as mainWindowGUI

from utils.globalSettings import (
    # Import GUI Settings to access global settings
    GUI_SETTINGS,
    # with Language Settings language pack can be accessed
    LANGUAGE_SETTINGS, 
    writeSettings
)

class gcodeEditor(QTextEdit):
    """Module for the G-Code Editor, G-Code Editor can handle opening and saving the G-Code"""

    def __init__(self, mainWindow: mainWindowGUI):
        """Create an instace of the gcodeTexteditor"""
        super().__init__()

        self.mainWindow: mainWindowGUI = mainWindow

        #self.layoutGCode = QVBoxLayout()

        #Font Texteditor
        font = QFont("unexistent")      #beliebiger Platzhalter als String, damit nächste Zeile wirksam wird
        font.setStyleHint(QFont.Monospace) #Buchstaben haben dieselbe Breite
        font.setPointSize(GUI_SETTINGS["gCodeSize"])
        self.setFont(font)
        self.textChanged.connect(self.updateFormat)
        self.openRecentGCode()

        # for mechanic G-Code is read only
        if GUI_SETTINGS["GUI"]["userRole"] == "mechanic":
            self.setReadOnly(True)

    #Folgende Methoden gehört zum Popup-Menü G-Code. Es werden Dialoge gestartet, um die Files auszuwählen

    def gcodeSave(self) -> None:
        """Save current G-Code from G-Code Editor"""

        filters = "MPF-Datei (*.mpf);; Alle Dateien (*)"
        filename, selected_filter = QFileDialog.getSaveFileName(self, filter = filters)
        print("Result:", filename, selected_filter)

        if filename:
            with open(filename, "w") as f:
                file_content = self.toPlainText()
                f.write(file_content)


    def gcodeOpen(self) -> None:
        """Open G-Code for G-Code Editor"""

        filters = "MPF-Datei (*.mpf);; Alle Dateien (*)"
        filename, selected_filter = QFileDialog.getOpenFileName(self, filter=filters)
        print("Result:", filename, selected_filter)

        if filename:
            with open(filename, "r") as f:
                try:
                    file_contents = f.read()
                    self.setPlainText(file_contents)
                    self.moveCursor(QTextCursor.Start)
                    self.updateFormat()
                except:
                    # Handles all errors if file can not be opend
                    errorHandling = QMessageBox(self.mainWindow)
                    errorHandling.setWindowTitle(LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["errorMessageOpen"])
                    errorHandling.setText(LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["errorMessageOpenDetail"])
                    errorHandling.setIcon(QMessageBox.Warning)
                    errorHandling.setStandardButtons(QMessageBox.Cancel)
                    errorHandling.exec()

    def updateFormat(self) -> None:
        """Update Format of G-Code to Highlight Syntax"""

        # start with disconnet to prevent endles recursion as this function updates text and triggers textChanged event
        self.textChanged.disconnect()
        # get cursor position
        textCursor = self.textCursor()
        textCursorPosition = textCursor.position()
        scrollPosition = self.verticalScrollBar().value()

        #Definition of Font Colors for Syntax
        htmlComment = "<font color=\""+ GUI_SETTINGS["gCodeColors"]["htmlCommentColor"] + "\">;"
        htmlLineNumber = "<font color=\""+ GUI_SETTINGS["gCodeColors"]["htmlLineNumberColor"] + "\">"
        htmlGCommand = "<font color=\""+ GUI_SETTINGS["gCodeColors"]["htmlGCommandColor"] + "\">"
        htmlFCommand = "<font color=\""+ GUI_SETTINGS["gCodeColors"]["htmlFCommandColor"] + "\">"
        htmlMCommand = "<font color=\""+ GUI_SETTINGS["gCodeColors"]["htmlMCommandColor"] + "\">"
        htmlCoord = "<font color=\""+ GUI_SETTINGS["gCodeColors"]["htmlCoordColor"] + "\">"
        #TODO Erweiterung um weitere Styles

        htmlDefault = "<font color=\""+ GUI_SETTINGS["gCodeColors"]["htmlDefaultColor"] + "\">"


        # space bevor endTag as spaces are removed by split
        htmlEndTag = "</font>"

        text = self.toPlainText()

        #write G-Code to autoSave
        with open(os.path.expandvars(GUI_SETTINGS["paths"]["autoSaves"] + "gCode.mpf"), 'w') as f:
            f.write(text)

        lines = text.split("\n")
        formatedText = ""

        # Texteditor adds new line at end at each refresh --> delete if last line is empty
        if lines[len(lines) - 1] == '':
            lines.pop()

        for thisLine in lines:
            #seperate comment in line from rest of line
            thisLine = thisLine.split(";", 1)
            comment = ""
            if len(thisLine) > 1:
                comment = htmlComment + thisLine[1] + htmlEndTag

            commands = re.split("\s", thisLine[0])
            # add space back to commands exept last command
            i = 0
            for thisCommand in commands[:-1]:
                commands[i] = thisCommand + "&nbsp;"
                i = i + 1

            newLine = ""

            # apply formating for each command
            for thisCommand in commands:
                if re.match("N[0-9]+", thisCommand) != None:
                    # LineNumber detected
                    newLine = newLine + htmlLineNumber + thisCommand + htmlEndTag
                elif re.match("G[0-9]+", thisCommand) != None:
                    # G Command detected
                    newLine = newLine + htmlGCommand + thisCommand + htmlEndTag
                elif re.match("F[0-9]+", thisCommand) != None:
                    # F Command detected
                    newLine = newLine + htmlFCommand + thisCommand + htmlEndTag
                elif re.match("M[0-9]+", thisCommand) != None:
                    # M Command detected
                    newLine = newLine + htmlMCommand + thisCommand + htmlEndTag
                elif re.match("^[ABCXYZ]=?[-+]?[0-9]+\.?[0-9]*[-+]?.*", thisCommand) != None:
                    # Coords detected
                    newLine = newLine + htmlCoord + thisCommand + htmlEndTag
                    
                #TODO Erweiterung um weitere Styles
                else:
                    # Default handling --> no syntax detected
                    newLine = newLine + htmlDefault + thisCommand + htmlEndTag

            newLine = newLine + comment + "<br>\n"
            formatedText = formatedText + newLine

        # remove last break line to prevent additional new line at end
        formatedText = formatedText.removesuffix("\n")

        self.setHtml(formatedText)
        textCursor.setPosition(textCursorPosition)
        self.setTextCursor(textCursor)
        self.verticalScrollBar().setValue(scrollPosition)
        self.textChanged.connect(self.updateFormat)

    def openRecentGCode(self) -> None:
        """Open G-Code from autoSaves"""
        if os.path.isfile(os.path.expandvars(GUI_SETTINGS["paths"]["autoSaves"] + "gCode.mpf")):
            with open(os.path.expandvars(GUI_SETTINGS["paths"]["autoSaves"] + "gCode.mpf"), 'r') as f:
                try:
                    file_contents = f.read()
                    self.setPlainText(file_contents)
                    self.moveCursor(QTextCursor.Start)
                    self.updateFormat()
                except:
                    pass
        else:
            return

    def adjustTextSize(self, newTextSize: int) -> None:
        """adujust the Textsize for the G-Code Editor"""
        GUI_SETTINGS["gCodeSize"] = newTextSize
        writeSettings()
        font = QFont("unexistent")      #beliebiger Platzhalter als String, damit nächste Zeile wirksam wird
        font.setStyleHint(QFont.Monospace) #Buchstaben haben dieselbe Breite
        font.setPointSize(GUI_SETTINGS["gCodeSize"])
        self.setFont(font)
