"""
In diesem Skript wird das rechte Tabmenü generiert, das die Parameter enthält.
"""

import os
import json
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

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
)
from utils.commonFunctions import *

from Classes import Verschneidung, Werkzeug

from LayoutElements.configManager import (
    toolManager, 
    machineManager
)
from LayoutElements.gcodeEditor import gcodeEditor
from LayoutElements.plotErstellung import plotWindow

degree_sign = u'\N{DEGREE SIGN}'

ERROR_DOUBLE_EDIT = LANGUAGE_SETTINGS.languagePack["mainWindowGUI"]["rejectedInput"] + "12,34"
ERROR_INT_EDIT = LANGUAGE_SETTINGS.languagePack["mainWindowGUI"]["rejectedInput"] + "123"

class BlinkingButton(QPushButton):
    def __init__(self, text, parent=None):
        super().__init__(text, parent)
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.blink)
        self.blink_state = False

    def start_blinking(self):
        self.timer.start(500)

    def stop_blinking(self):
        self.timer.stop()
        self.setStyleSheet("")  # Reset button style

    def blink(self):
        self.blink_state = not self.blink_state
        if self.blink_state:
            self.setStyleSheet("background-color: #4E4E4E")
        else:
            self.setStyleSheet("")

class setupTabmenu(QVBoxLayout):
    """Tabmenu with all the settings to setup the parametes for the project"""
    def __init__(self, editor: gcodeEditor = None, thisPlotWindow: plotWindow = None, mainWindow: mainWindowGUI = None):
        """Create the tabmenu to setup the parametes for the project"""

        super().__init__()

        self.selectedMachinePath = ""
        self.selectedToolPath = ""
        self.selectedMachineConfig = None
        self.selectedToolConfig = None

        self.thisGcodeEditor: gcodeEditor = editor
        self.thisPlotWindow: plotWindow = thisPlotWindow
        self.mainWindow: mainWindowGUI = mainWindow

        self.tabs = QTabWidget()
        self.addWidget(self.tabs)

        self.geometryTab = QWidget()
        self.toolTab = QWidget()
        self.machineTab = QWidget()
        self.processTab = QWidget()

        # init of managers
        self.toolManager = toolManager(self)
        self.machineManager = machineManager(self)

        self.__initGeometryTab()
        self.__initToolTab()
        self.__initMachineTab()
        self.__initProcessTab()
            
        self.tabs.addTab(self.geometryTab, LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["geometryTab"]["title"])
        self.tabs.addTab(self.toolTab, LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["toolTab"]["title"])
        self.tabs.addTab(self.machineTab, LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["machineTab"]["title"])
        self.tabs.addTab(self.processTab, LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["processTab"]["title"])

        self.openRecentConfig()

        self.__initTextChangeEvents()

        # Definition of Buttons
        gCodeButton = QPushButton(LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["gCodeButton"])
        #connect G-Code button
        gCodeButton.clicked.connect( lambda: self.mainWindow.showStatusbarmessage(LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["gCodeSatusBarMsg"]))
        gCodeButton.clicked.connect(self.mainWindow.App.processEvents)
        gCodeButton.clicked.connect(self.generateGCode)
        gCodeButton.clicked.connect(lambda: self.mainWindow.showStatusbarmessage(""))

        buttonPlotGeneration = QPushButton(LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["plotButton"])
        self.thisPlotWindow.initPlotErstellungsButton(self, buttonPlotGeneration, mainWindow)
        self.thisPlotWindow.finishInit()

        buttonLayout = QHBoxLayout()
        buttonLayout.addWidget(buttonPlotGeneration)
        buttonLayout.addWidget(gCodeButton)


        self.addLayout(buttonLayout)

    """Start Init Routines for each tab"""
       
    def __initGeometryTab(self) -> None:
        """Inits Geometry Tab, is called only locally during init"""

        languageGeometryToolTab = LANGUAGE_SETTINGS.languagePack['setupTabmenu']['geometryTab']

        # Line Edits with limits and precission defined
        self.bool_ebener_Austritt = QCheckBox()
        self.bool_Auslegung = QCheckBox()

        self.d_hb = doubleEditLine("", 0, 100, 3, self.mainWindow.statusBar(), ERROR_DOUBLE_EDIT)
        self.d_qb = doubleEditLine("", 0, 100, 3, self.mainWindow.statusBar(), ERROR_DOUBLE_EDIT)
        self.av = doubleEditLine("", 0, 100, 3, self.mainWindow.statusBar(), ERROR_DOUBLE_EDIT)
        self.fb_soll = doubleEditLine("", 0, 10, 3, self.mainWindow.statusBar(), ERROR_DOUBLE_EDIT)

        self.phi = doubleEditLine("", -360, 360, 3, self.mainWindow.statusBar(), ERROR_DOUBLE_EDIT)
        self.theta = doubleEditLine("", -360, 360, 3, self.mainWindow.statusBar(), ERROR_DOUBLE_EDIT)
        self.psi = doubleEditLine("", -360, 360, 3, self.mainWindow.statusBar(), ERROR_DOUBLE_EDIT)
        self.x = doubleEditLine("", float("-inf"), float("inf"), 3, self.mainWindow.statusBar(), ERROR_DOUBLE_EDIT)
        self.y = doubleEditLine("", float("-inf"), float("inf"), 3, self.mainWindow.statusBar(), ERROR_DOUBLE_EDIT)
        self.z = doubleEditLine("", float("-inf"), float("inf"), 3, self.mainWindow.statusBar(), ERROR_DOUBLE_EDIT)

        self.sicherheitsebene1 = doubleEditLine("", 0, 500, 3, self.mainWindow.statusBar(), ERROR_DOUBLE_EDIT)
        self.sicherheitsebene2 = doubleEditLine("", 0, 500, 3, self.mainWindow.statusBar(), ERROR_DOUBLE_EDIT)
        self.bohrtiefe = doubleEditLine("", 0, 500, 3, self.mainWindow.statusBar(), ERROR_DOUBLE_EDIT)

        self.geometryInputs = [
            #self.bool_ebener_Austritt,
            self.d_hb,
            self.d_qb,
            self.av,
            self.fb_soll,
            self.phi,
            self.theta,
            self.psi,
            self.x,
            self.y,
            self.z,
            self.sicherheitsebene1,
            self.sicherheitsebene2,
            self.bohrtiefe
        ]


        tabLayout = QFormLayout()

        boldFont = QFont("Times")
        boldFont.setBold(True)

        tabLabel_Allgemein = QLabel(f"{languageGeometryToolTab['Allgemein']}")
        tabLabel_Allgemein.setFont(boldFont)
        tabLabel_ebener_Austritt = QLabel(f"{languageGeometryToolTab['bool_ebener_Austritt_label']}")
        tabLabel_ebener_Austritt.setToolTip(self.create_tooltip(f"{languageGeometryToolTab['bool_ebener_Austritt_tooltip']}"))
        tabLabel_Auslegen = QLabel(f"{languageGeometryToolTab['bool_Auslegung_label']}")
        tabLabel_Auslegen.setToolTip(self.create_tooltip(f"{languageGeometryToolTab['bool_Auslegung_tooltip']}"))

        tabLabel_kreuzbohrung = QLabel(f"{languageGeometryToolTab['kreuzbohrung_label']}")
        tabLabel_kreuzbohrung.setFont(boldFont)
        tabLabel_kreuzbohrung.setToolTip(f"{languageGeometryToolTab['kreuzbohrung_tooltip']}")
        tabLabel_hb = QLabel(f"{languageGeometryToolTab['d_hb_label']} [mm]")
        tabLabel_hb.setToolTip(f"{languageGeometryToolTab['d_hb_tooltip']}" % (0, 100))
        tabLabel_qb = QLabel(f"{languageGeometryToolTab['d_qb_label']} [mm]")
        tabLabel_qb.setToolTip(f"{languageGeometryToolTab['d_qb_tooltip']}" % (0, 100))
        tabLabel_av = QLabel(f"{languageGeometryToolTab['av_label']} [mm]")
        tabLabel_av.setToolTip(f"{languageGeometryToolTab['av_tooltip']}" % (0, 100))
        tabLabel_fb = QLabel(f"{languageGeometryToolTab['fb_soll_label']} [mm]")
        tabLabel_fb.setToolTip(f"{languageGeometryToolTab['fb_soll_tooltip']}" % (0, 10))

        tabLabel_rotation = QLabel(languageGeometryToolTab['rotation_label'])
        tabLabel_rotation.setFont(boldFont)
        tabLabel_rotation.setToolTip(languageGeometryToolTab['rotation_tooltip'])
        tabLabel_phi = QLabel(f"{languageGeometryToolTab['phi_label']} [{degree_sign}]")
        tabLabel_phi.setToolTip(self.create_tooltip(f"{languageGeometryToolTab['phi_tooltip']}", 'Images/d_phi.png', 1))
        tabLabel_theta = QLabel(f"{languageGeometryToolTab['theta_label']} [{degree_sign}]")
        tabLabel_theta.setToolTip(self.create_tooltip(f"{languageGeometryToolTab['theta_tooltip']}", 'Images/d_theta.png', 1))
        tabLabel_psi = QLabel(f"{languageGeometryToolTab['psi_label']} [{degree_sign}]")
        tabLabel_psi.setToolTip(self.create_tooltip(f"{languageGeometryToolTab['psi_tooltip']}", 'Images/d_psi.png', 1))

        tabLabel_translation = QLabel(languageGeometryToolTab['translation_label'])
        tabLabel_translation.setFont(boldFont)
        tabLabel_translation.setToolTip(languageGeometryToolTab['translation'])
        tabLabel_x = QLabel(f"{languageGeometryToolTab['x_label']} [mm]")
        tabLabel_x.setToolTip(self.create_tooltip(f"{languageGeometryToolTab['x_tooltip']}", 'Images/t_x.png', 1))
        tabLabel_y = QLabel(f"{languageGeometryToolTab['y_label']} [mm]")
        tabLabel_y.setToolTip(self.create_tooltip(f"{languageGeometryToolTab['y_tooltip']}", 'Images/t_y.png', 1))
        tabLabel_z = QLabel(f"{languageGeometryToolTab['z_label']} [mm]")
        tabLabel_z.setToolTip(self.create_tooltip(f"{languageGeometryToolTab['z_tooltip']}", 'Images/t_z.png', 1))
        tabLabel_Sicherheitsebenen = QLabel(f"{languageGeometryToolTab['Sicherheitsebenen']}")
        tabLabel_Sicherheitsebenen.setFont(boldFont)
        tabLabel_Sicherheitsebene1 = QLabel(f"{languageGeometryToolTab['Sicherheitsebene1']} [mm]")
        tabLabel_Sicherheitsebene1.setToolTip(self.create_tooltip(f"{languageGeometryToolTab['Sicherheitsebene1_tooltip']}", 'Images/rueckzugsabstand.png', 1))
        tabLabel_Sicherheitsebene2 = QLabel(f"{languageGeometryToolTab['Sicherheitsebene2']} [mm]")
        tabLabel_Sicherheitsebene2.setToolTip(self.create_tooltip(f"{languageGeometryToolTab['Sicherheitsebene2_tooltip']}", 'Images/sicherheitsabstand.png', 1))
        tabLabel_Bohrtiefe = QLabel(f"{languageGeometryToolTab['Bohrtiefe']} [mm]")
        tabLabel_Bohrtiefe.setToolTip(self.create_tooltip(f"{languageGeometryToolTab['Bohrtiefe_tooltip']}", 'Images/bohrtiefe.png', 1))

        # Set tooltip backgorung white
        labels = [tabLabel_ebener_Austritt, tabLabel_Auslegen, tabLabel_hb, tabLabel_qb, tabLabel_av, tabLabel_fb,
                  tabLabel_phi, tabLabel_theta, tabLabel_psi, tabLabel_x, tabLabel_y, tabLabel_z,
                  tabLabel_Sicherheitsebene1, tabLabel_Sicherheitsebene2, tabLabel_Bohrtiefe]
        for label in labels:
            label.setStyleSheet("QToolTip { background-color: white; color: black; }")

        tabLayout.addRow(tabLabel_Allgemein)
        tabLayout.addRow(tabLabel_ebener_Austritt, self.bool_ebener_Austritt)
        tabLayout.addRow(tabLabel_Auslegen, self.bool_Auslegung)
        tabLayout.addRow(tabLabel_kreuzbohrung)
        tabLayout.addRow(tabLabel_hb, self.d_hb)
        tabLayout.addRow(tabLabel_qb, self.d_qb)
        tabLayout.addRow(tabLabel_av, self.av)
        tabLayout.addRow(tabLabel_fb, self.fb_soll)


        # Transformation Fields
        tabLayout.addRow(tabLabel_rotation)
        tabLayout.addRow(tabLabel_phi, self.phi)
        tabLayout.addRow(tabLabel_theta, self.theta)
        tabLayout.addRow(tabLabel_psi, self.psi)
        tabLayout.addRow(tabLabel_translation)
        tabLayout.addRow(tabLabel_x, self.x)
        tabLayout.addRow(tabLabel_y, self.y)
        tabLayout.addRow(tabLabel_z, self.z)

        # Sicherheitsebenen
        tabLayout.addRow(tabLabel_Sicherheitsebenen)
        tabLayout.addRow(tabLabel_Sicherheitsebene1, self.sicherheitsebene1)
        tabLayout.addRow(tabLabel_Sicherheitsebene2, self.sicherheitsebene2)
        tabLayout.addRow(tabLabel_Bohrtiefe, self.bohrtiefe)

        self.geometryTab.setLayout(tabLayout)

    def create_tooltip(self, text, icon_filename=None, scale_factor=None):
        # Replace newline characters with HTML line breaks
        formatted_text = text.replace("\n", "<br>")

        if icon_filename and os.path.isfile(icon_filename):
            # Load the icon image
            icon = QPixmap(icon_filename)

            if scale_factor:
                # Create the HTML-formatted tooltip text with the icon image
                tooltip_text = f'<html><body><p>{formatted_text}</p><p><img src="{icon_filename}" width="{icon.width() * scale_factor}" height="{icon.height() * scale_factor}"></p></body></html>'
            else:
                # Create the HTML-formatted tooltip text with the icon image without scaling
                tooltip_text = f'<html><body><p>{formatted_text}</p><p><img src="{icon_filename}"></p></body></html>'
        else:
            # Return only the text if no valid image file is provided
            tooltip_text = f'<html><body><p>{formatted_text}</p></body></html>'

        return tooltip_text

    def __initToolTab(self) -> None:
        """Inits Tool Tab, is called only locally during init"""

        # Line Edits
        self.selectedTool = lockedEditLine("")
        self.werkzeugstatus = lockedEditLine("")
        self.werkzeugstatus.setAlignment(Qt.AlignCenter)
        self.d_kopf = lockedEditLine("")
        self.l_kopf = lockedEditLine("")
        self.l_kopf_gesamt = lockedEditLine("")
        self.d_schaft = lockedEditLine("")
        self.l_werkzeug = lockedEditLine("")
        self.l_werkzeug_gesamt = lockedEditLine("")
        self.l_schaft = lockedEditLine("")
        self.d_schaft2 = lockedEditLine("")
        self.spitzenwinkel = lockedEditLine("")
        self.freiwinkel = lockedEditLine("")
        self.schneidenwinkel = lockedEditLine("")
        self.winkeloffset = lockedEditLine("")

        languagePackToolTab = LANGUAGE_SETTINGS.languagePack['setupTabmenu']['toolTab']

        tabLayout = QFormLayout()

        # set bold label
        boldFont = QFont("Times")
        boldFont.setBold(True)

        # Aktuelles Werkzeug
        tabLabel_current_tool = QLabel(f"{languagePackToolTab['labelAktuellesWerkzeug']}")
        tabLabel_current_tool.setFont(boldFont)

        # Label with selected tool
        selectRow = QGridLayout()
        selectRow.addWidget(tabLabel_current_tool, 1, 1)
        self.selectButton = BlinkingButton(languagePackToolTab["selectButton"])
        self.selectButton.clicked.connect(self.open_tool_manager)
        selectRow.addWidget(self.selectButton, 1, 2)
        tabLayout.addRow(selectRow)
        self.toolManager.set_close_functions(self.selectButton.stop_blinking, self.mainWindow.showStatusbarmessage)

        # Werkzeugname
        tabLabel_werkzeugname = QLabel(f"{languagePackToolTab['Werkzeugname']}")
        tabLayout.addRow(tabLabel_werkzeugname, self.selectedTool)

        # Werkzeugstatus
        tabLabel_werkzeugstatus = QLabel(f"{languagePackToolTab['Werkzeugstatus']}")
        tabLabel_werkzeugstatus.setToolTip(self.create_tooltip(languagePackToolTab['Werkzeugstatus_tooltip']))
        tabLabel_werkzeugstatus.setStyleSheet("QToolTip { background-color: white; color: black; }")
        tabLayout.addRow(tabLabel_werkzeugstatus, self.werkzeugstatus)

        # Werkzeugparameter
        tabLabel_parameter = QLabel(f"{languagePackToolTab['labelWerkzeugparameter']}")
        tabLabel_parameter.setFont(boldFont)
        tabLayout.addRow(tabLabel_parameter)

        # d_kopf
        tabLabel_d_kopf = QLabel(f"{languagePackToolTab['d_kopf']} [mm]")
        tabLabel_d_kopf.setToolTip(self.create_tooltip(f"{languagePackToolTab['d_kopf_tooltip']} ", 'Images/tool_d_kopf.png', 1))
        tabLabel_d_kopf.setStyleSheet("QToolTip { background-color: white; color: black; }")
        tabLayout.addRow(tabLabel_d_kopf, self.d_kopf)

        # l_kopf
        tabLabel_l_kopf = QLabel(f"{languagePackToolTab['l_kopf']} [mm]")
        tabLabel_l_kopf.setToolTip(self.create_tooltip(f"{languagePackToolTab['l_kopf_tooltip']} ", 'Images/tool_l_kopf.png', 1))
        tabLabel_l_kopf.setStyleSheet("QToolTip { background-color: white; color: black; }")
        tabLayout.addRow(tabLabel_l_kopf, self.l_kopf)

        # l_kopf
        tabLabel_l_kopf_gesamt = QLabel(f"{languagePackToolTab['l_kopf_gesamt']} [mm]")
        tabLabel_l_kopf_gesamt.setToolTip(self.create_tooltip(f"{languagePackToolTab['l_kopf_gesamt_tooltip']} ", 'Images/tool_l_kopf_gesamt.png', 1))
        tabLabel_l_kopf_gesamt.setStyleSheet("QToolTip { background-color: white; color: black; }")
        tabLayout.addRow(tabLabel_l_kopf_gesamt, self.l_kopf_gesamt)

        # d_schaft
        tabLabel_d_schaft = QLabel(f"{languagePackToolTab['d_schaft']} [mm]")
        tabLabel_d_schaft.setToolTip( self.create_tooltip(f"{languagePackToolTab['d_schaft_tooltip']} ", 'Images/tool_d_schaft.png', 1))
        tabLabel_d_schaft.setStyleSheet("QToolTip { background-color: white; color: black; }")
        tabLayout.addRow(tabLabel_d_schaft, self.d_schaft)

        # Spanlaenge (l_werkzeug)
        tabLabel_l_werkzeug = QLabel(f"{languagePackToolTab['l_werkzeug']} [mm]")
        tabLabel_l_werkzeug.setToolTip(self.create_tooltip(f"{languagePackToolTab['l_werkzeug_tooltip']} ", 'Images/tool_l_span.png', 1))
        tabLabel_l_werkzeug.setStyleSheet("QToolTip { background-color: white; color: black; }")
        tabLayout.addRow(tabLabel_l_werkzeug, self.l_werkzeug)

        # Gesamtlaenge (l_werkzeug_gesamt)
        tabLabel_l_werkzeug_gesamt = QLabel(f"{languagePackToolTab['l_werkzeug_gesamt']} [mm]")
        tabLabel_l_werkzeug_gesamt.setToolTip(self.create_tooltip(f"{languagePackToolTab['l_werkzeug_gesamt_tooltip']} ", 'Images/tool_l_gesamt.png', 1))
        tabLabel_l_werkzeug_gesamt.setStyleSheet("QToolTip { background-color: white; color: black; }")
        tabLayout.addRow(tabLabel_l_werkzeug_gesamt, self.l_werkzeug_gesamt)

        # Schaftlaenge
        tabLabel_l_schaft = QLabel(f"{languagePackToolTab['l_schaft']} [mm]")
        tabLabel_l_schaft.setToolTip(self.create_tooltip(f"{languagePackToolTab['l_schaft_tooltip']} ", 'Images/tool_l_schaft.png', 1))
        tabLabel_l_schaft.setStyleSheet("QToolTip { background-color: white; color: black; }")
        tabLayout.addRow(tabLabel_l_schaft, self.l_schaft)

        # Schaftdurchmesser 2
        tabLabel_d_schaft2 = QLabel(f"{languagePackToolTab['d_schaft2']} [mm]")
        tabLabel_d_schaft2.setToolTip(self.create_tooltip(f"{languagePackToolTab['d_schaft2_tooltip']} ", 'Images/tool_d_schaft2.png', 1))
        tabLabel_d_schaft2.setStyleSheet("QToolTip { background-color: white; color: black; }")
        tabLayout.addRow(tabLabel_d_schaft2, self.d_schaft2)

        # Spitzenwinkel
        tabLabel_spitzenwinkel = QLabel(f"{languagePackToolTab['spitzenwinkel']} [{degree_sign}]")
        tabLabel_spitzenwinkel.setToolTip(self.create_tooltip(f"{languagePackToolTab['spitzenwinkel_tooltip']} ", 'Images/tool_spitzenwinkel.png', 1))
        tabLabel_spitzenwinkel.setStyleSheet("QToolTip { background-color: white; color: black; }")
        tabLayout.addRow(tabLabel_spitzenwinkel, self.spitzenwinkel)

        # Freiwinkel
        tabLabel_freiwinkel = QLabel(f"{languagePackToolTab['freiwinkel']} [{degree_sign}]")
        tabLabel_freiwinkel.setToolTip(self.create_tooltip(f"{languagePackToolTab['freiwinkel_tooltip']} ", 'Images/tool_freiwinkel.png', 1))
        tabLabel_freiwinkel.setStyleSheet("QToolTip { background-color: white; color: black; }")
        tabLayout.addRow(tabLabel_freiwinkel, self.freiwinkel)

        # Senkwinkel (Schneidenwinkel)
        tabLabel_schneidenwinkel = QLabel(f"{languagePackToolTab['schneidenwinkel']} [{degree_sign}]")
        tabLabel_schneidenwinkel.setToolTip(self.create_tooltip(f"{languagePackToolTab['schneidenwinkel_tooltip']} ", 'Images/tool_senkwinkel.png', 1))
        tabLabel_schneidenwinkel.setStyleSheet("QToolTip { background-color: white; color: black; }")
        tabLayout.addRow(tabLabel_schneidenwinkel, self.schneidenwinkel)

        # Winkeloffset
        tabLabel_winkeloffset = QLabel(f"{languagePackToolTab['winkeloffset']} [{degree_sign}]")
        tabLabel_winkeloffset.setToolTip(self.create_tooltip(f"{languagePackToolTab['winkeloffset_tooltip']} ", 'Images/tool_ausrichtung.png', 1))
        tabLabel_winkeloffset.setStyleSheet("QToolTip { background-color: white; color: black; }")
        tabLayout.addRow(tabLabel_winkeloffset, self.winkeloffset)

        self.toolTab.setLayout(tabLayout)

    def open_tool_manager(self):
        duration = 5000  # 5 seconds
        self.mainWindow.showStatusbarmessage(LANGUAGE_SETTINGS.languagePack['setupTabmenu']['toolTab']['MaschinenverwaltungOpen'])
        self.selectButton.start_blinking()
        self.blink_timer = QTimer(self)
        self.blink_timer.setSingleShot(True)
        self.blink_timer.timeout.connect(self.selectButton.stop_blinking)
        self.blink_timer.start(duration)
        self.toolManager.showManager()

    def __initMachineTab(self) -> None:
        """Inits Machine Tab, is called only locally during init"""

        # Line Edits
        self.selectedMachine = lockedEditLine("")
        self.steuerung = lockedEditLine("")
        self.wks = lockedEditLine("")
        self.mCodeWerkzeugwechsel = lockedEditLine("")
        self.mCodeDrehachsenKlemmen = lockedEditLine("")
        self.mCodeDrehachsenLoesen = lockedEditLine("")
        self.mCodeKontrollMaschinenhalt = lockedEditLine("")
        self.mCodeEinschaltenKSS = lockedEditLine("")
        self.mCodeAusschaltenKSS = lockedEditLine("")
        self.mCodeEinschaltenSpindel = lockedEditLine("")
        self.mCodeEinschaltenSpindelAlt = lockedEditLine("")
        self.mCodeAusschaltenSpindel = lockedEditLine("")
        self.bahnsteuerbetrieb = lockedEditLine("")

        languagePackMachineTab = LANGUAGE_SETTINGS.languagePack['setupTabmenu']['machineTab']

        tabLayout = QFormLayout()

        # set bold labels
        boldFont = QFont("Times")
        boldFont.setBold(True)
        tabLabel_current_machine = QLabel(languagePackMachineTab['labelAktuelleMaschine'])
        tabLabel_current_machine.setFont(boldFont)
        tabLabel_allgemeines = QLabel(languagePackMachineTab['labelAllgemeines'])
        tabLabel_allgemeines.setFont(boldFont)
        tabLabel_mCodes = QLabel(languagePackMachineTab['labelM-Codes'])
        tabLabel_mCodes.setFont(boldFont)

        #tabLayout.addRow(tabLabel_current_machine)

        # Label with selected tool
        selectRow = QGridLayout()
        selectRow.addWidget(tabLabel_current_machine, 1, 1)
        self.selectButtonMachine = BlinkingButton(languagePackMachineTab["selectButton"])
        self.selectButtonMachine.clicked.connect(self.open_machine_manager)
        #selectButton = QPushButton(languagePackMachineTab["selectButton"])
        #selectButton.clicked.connect(self.machineManager.showManager)
        selectRow.addWidget(self.selectButtonMachine, 1, 2)
        self.machineManager.set_close_functions(self.selectButtonMachine.stop_blinking, self.mainWindow.showStatusbarmessage)
        tabLayout.addRow(selectRow)

        tabLayout.addRow(f"{languagePackMachineTab['Name']}", self.selectedMachine)

        tabLayout.addRow(tabLabel_allgemeines)
        tabLayout.addRow(f"{languagePackMachineTab['Steuerung']}", self.steuerung)
        tabLayout.addRow(f"{languagePackMachineTab['WKS']}", self.wks)
        tabLayout.addRow(tabLabel_mCodes)
        tabLayout.addRow(f"{languagePackMachineTab['MCodeWerkzeugwechsel']}", self.mCodeWerkzeugwechsel)
        tabLayout.addRow(f"{languagePackMachineTab['MCodeDrehachsenKlemmen']}", self.mCodeDrehachsenKlemmen)
        tabLayout.addRow(f"{languagePackMachineTab['MCodeDrehachsenLoesen']}", self.mCodeDrehachsenLoesen)
        tabLayout.addRow(f"{languagePackMachineTab['MCodeKontrollMaschinenhalt']}", self.mCodeKontrollMaschinenhalt)
        tabLayout.addRow(f"{languagePackMachineTab['MCodeEinschaltenKSS']}", self.mCodeEinschaltenKSS)
        tabLayout.addRow(f"{languagePackMachineTab['MCodeAusschaltenKSS']}", self.mCodeAusschaltenKSS)
        tabLayout.addRow(f"{languagePackMachineTab['MCodeEinschaltenSpindel']}", self.mCodeEinschaltenSpindel)
        tabLayout.addRow(f"{languagePackMachineTab['MCodeEinschaltenSpindelAlt']}", self.mCodeEinschaltenSpindelAlt)
        tabLayout.addRow(f"{languagePackMachineTab['MCodeAusschaltenSpindel']}", self.mCodeAusschaltenSpindel)

        self.machineTab.setLayout(tabLayout)

    def open_machine_manager(self):
        duration = 5000  # 5 seconds
        self.selectButtonMachine.start_blinking()
        self.mainWindow.showStatusbarmessage(LANGUAGE_SETTINGS.languagePack['setupTabmenu']['machineTab']['MaschinenverwaltungOpen'])
        self.blink_timer_machine = QTimer(self)
        self.blink_timer_machine.setSingleShot(True)
        self.blink_timer_machine.timeout.connect(self.selectButtonMachine.stop_blinking)
        self.blink_timer_machine.start(duration)
        self.machineManager.showManager()

    def __initProcessTab(self) -> None:
        """Inits Process Tab, is called only locally during init"""

        languagePackProcessTab = LANGUAGE_SETTINGS.languagePack['setupTabmenu']['processTab']

        self.nPoints = intEditLine("", 0, 1000, self.mainWindow.statusBar(), ERROR_INT_EDIT)
        self.bearbeitungsrichtung = QComboBox()
        self.bearbeitungsrichtung.addItems(languagePackProcessTab["bearbeitungsrichtung"])

        self.vorschubBohren = doubleEditLine("", 0, 5, 2, self.mainWindow.statusBar(), ERROR_DOUBLE_EDIT)
        self.schnittgeschwindigkeitBohren = doubleEditLine("", 0, 1000, 2, self.mainWindow.statusBar(), ERROR_DOUBLE_EDIT)
        self.vorschubEntgraten = doubleEditLine("", 0, 1000, 2, self.mainWindow.statusBar(), ERROR_DOUBLE_EDIT)
        self.overlap = intEditLine("", 0, 200, self.mainWindow.statusBar(), ERROR_INT_EDIT)
        self.einfahren = intEditLine("", 0, 200, self.mainWindow.statusBar(), ERROR_INT_EDIT)

        self.processInputs = [
            self.nPoints,
            self.vorschubBohren,
            self.schnittgeschwindigkeitBohren,
            self.vorschubEntgraten,
            self.overlap,
            self.einfahren,
        ]

        boldFont = QFont("Times")
        boldFont.setBold(True)

        tabLabel_allgemeines = QLabel(f"{languagePackProcessTab['allgemeines_label']}")
        tabLabel_allgemeines.setFont(boldFont)
        tabLabel_allgemeines.setToolTip(f"{languagePackProcessTab['allgemeines_tooltip']}")
        tabLabel_nPoints = QLabel(f"{languagePackProcessTab['n_points_label']}")
        tabLabel_nPoints.setToolTip(f"{languagePackProcessTab['n_points_tooltip']}" % (0, 1000))
        tabLabel_bearbeitungsrichtung = QLabel(f"{languagePackProcessTab['bearbeitungsrichtung_label']}")
        tabLabel_bearbeitungsrichtung.setToolTip(f"{languagePackProcessTab['bearbeitungsrichtung_tooltip']}")

        tabLabel_bohren = QLabel(f"{languagePackProcessTab['bohren_label']}")
        tabLabel_bohren.setFont(boldFont)
        tabLabel_bohren.setToolTip(f"{languagePackProcessTab['bohren_tooltip']}")
        tabLabel_vorschubBohren = QLabel(f"{languagePackProcessTab['vorschubBohren_label']} [mm/U]")
        tabLabel_vorschubBohren.setToolTip(f"{languagePackProcessTab['vorschubBohren_tooltip']}" % (0, 5))
        tabLabel_schnittgeschwindigkeitBohren = QLabel(
            f"{languagePackProcessTab['schnittgeschwindigkeitBohren_label']} [m/min]")
        tabLabel_schnittgeschwindigkeitBohren.setToolTip(
            f"{languagePackProcessTab['schnittgeschwindigkeitBohren_tooltip']}" % (0, 1000))

        tabLabel_entgraten = QLabel(f"{languagePackProcessTab['entgraten_label']}")
        tabLabel_entgraten.setFont(boldFont)
        tabLabel_entgraten.setToolTip(f"{languagePackProcessTab['entgraten_tooltip']}")
        tabLabel_vorschubEntgraten = QLabel(f"{languagePackProcessTab['vorschubEntgraten_label']} [mm/min]")
        tabLabel_vorschubEntgraten.setToolTip(f"{languagePackProcessTab['vorschubEntgraten_tooltip']}" % (0, 1000))
        tabLabel_overlap = QLabel(f"{languagePackProcessTab['overlap_label']}")
        tabLabel_overlap.setToolTip(self.create_tooltip(f"{languagePackProcessTab['overlap_tooltip']}", 'Images/Overlap.png', 1))
        tabLabel_einfahren = QLabel(f"{languagePackProcessTab['einfahren_label']}")
        tabLabel_einfahren.setToolTip(self.create_tooltip(f"{languagePackProcessTab['einfahren_tooltip']}", 'Images/Einfahren.png', 1))

        tabLayout = QFormLayout()

        # Set Backgroungcolor of tooltip
        labels = [tabLabel_nPoints, tabLabel_bearbeitungsrichtung, tabLabel_vorschubBohren,
                  tabLabel_schnittgeschwindigkeitBohren, tabLabel_vorschubEntgraten, tabLabel_overlap,
                  tabLabel_einfahren]
        for label in labels:
            label.setStyleSheet("QToolTip { background-color: white; color: black; }")

        tabLayout.addRow(tabLabel_allgemeines)
        tabLayout.addRow(tabLabel_nPoints, self.nPoints)
        tabLayout.addRow(tabLabel_bearbeitungsrichtung, self.bearbeitungsrichtung)

        tabLayout.addRow(tabLabel_bohren)
        tabLayout.addRow(tabLabel_vorschubBohren, self.vorschubBohren)
        tabLayout.addRow(tabLabel_schnittgeschwindigkeitBohren, self.schnittgeschwindigkeitBohren)

        tabLayout.addRow(tabLabel_entgraten)
        tabLayout.addRow(tabLabel_vorschubEntgraten, self.vorschubEntgraten)
        tabLayout.addRow(tabLabel_overlap, self.overlap)
        tabLayout.addRow(tabLabel_einfahren, self.einfahren)

        self.processTab.setLayout(tabLayout)

    def __initTextChangeEvents(self) -> None:
        """Text Change Events are added after init to prevent the events being triggered during init"""
        functions = [self.generateGeometryJson, self.setPlotStatusBarChanged, self.setGCodeStaturBarChanged, self.toolManager.setToolStatus]

        for func in functions:
            self.bool_ebener_Austritt.stateChanged.connect(func)
            self.bool_Auslegung.stateChanged.connect(func)
            self.d_hb.textChanged.connect(func)
            self.d_qb.textChanged.connect(func)
            self.av.textChanged.connect(func)
            self.fb_soll.textChanged.connect(func)
            self.phi.textChanged.connect(func)
            self.theta.textChanged.connect(func)
            self.psi.textChanged.connect(func)
            self.x.textChanged.connect(func)
            self.y.textChanged.connect(func)
            self.z.textChanged.connect(func)
            self.sicherheitsebene1.textChanged.connect(func)
            self.sicherheitsebene2.textChanged.connect(func)
            self.bohrtiefe.textChanged.connect(func)

            self.nPoints.textChanged.connect(func)

        functions = [self.generateGeometryJson, self.setGCodeStaturBarChanged]
        for func in functions:
            self.vorschubBohren.textChanged.connect(func)
            self.schnittgeschwindigkeitBohren.textChanged.connect(func)
            self.vorschubEntgraten.textChanged.connect(func)
            self.overlap.textChanged.connect(func)
            self.einfahren.textChanged.connect(func)

    def setPlotStatusBarChanged(self):
        # Update Plot Status Flag:
        self.thisPlotWindow.settingsChanged()
        print('Plot settings changed')

    def setGCodeStaturBarChanged(self):
        self.mainWindow.settingsChanged()
        print('GCode settings changed')

    def setGCodeStaturBarApplied(self):
        self.mainWindow.settingsApplied()
        print('GCode settings applied')

    def setGCodeStaturBarAppliedWithWarnings(self):
        self.mainWindow.settingsAppliedWithWarnings()
        print('GCode settings applied')

    def generateGeometryJson(self) -> dict:
        """Generates the JSON Structure for the Geometry Setup and saves it to autoSave"""
        #self.__initGeometryTab()

        def update_field(widget, readonly, color=''):
            widget.setReadOnly(readonly)
            widget.setStyleSheet(f'background-color: {color}; color: {color};')

        def get_float_value(widget):
            return textToFloat(widget.text())

        # Update fields based on bool_ebener_Austritt
        ebener_Austritt = self.bool_ebener_Austritt.isChecked()
        color = 'lightgrey' if ebener_Austritt else ''
        update_field(self.d_hb, ebener_Austritt, color)
        update_field(self.av, ebener_Austritt, color)

        Auslegung = self.bool_Auslegung.isChecked()
        color = 'lightgrey' if Auslegung else ''
        update_field(self.phi, Auslegung, color)
        update_field(self.theta, Auslegung, color)
        update_field(self.psi, Auslegung, color)
        update_field(self.x, Auslegung, color)
        update_field(self.y, Auslegung, color)
        update_field(self.z, Auslegung, color)
        update_field(self.sicherheitsebene1, Auslegung, color)
        update_field(self.sicherheitsebene2, Auslegung, color)

        # Generate config dictionary
        config = {
            "Allgemein": {
                "ebener_Austritt": ebener_Austritt,
                "Auslegung": Auslegung
            },
            "Verschneidung": {
                "d_hb": get_float_value(self.d_hb),
                "d_qb": get_float_value(self.d_qb),
                "av": get_float_value(self.av),
                "fb_soll": get_float_value(self.fb_soll)
            },
            "Transformation": {
                "Rotation": {
                    "phi": get_float_value(self.phi),
                    "theta": get_float_value(self.theta),
                    "psi": get_float_value(self.psi)
                },
                "Translation": {
                    "x": get_float_value(self.x),
                    "y": get_float_value(self.y),
                    "z": get_float_value(self.z)
                }
            },
            "Sicherheitsebenen": {
                "Sicherheitsebene1": get_float_value(self.sicherheitsebene1),
                "Sicherheitsebene2": get_float_value(self.sicherheitsebene2),
                "Bohrtiefe": get_float_value(self.bohrtiefe)
            }
        }

        # Save to JSON file
        with open(os.path.expandvars(GUI_SETTINGS["paths"]["autoSaves"] + "geometry_setup.json"), 'w') as f:
            json.dump(config, f, indent=4)

        return config

    def generateProcessJson(self) -> dict:
        """Generates the JSON Structure for the Process Setup and saves it to autoSave"""

        config = {}
        config.update({"machinePath": self.selectedMachinePath})
        config.update({"toolPath": self.selectedToolPath})

        bohren = {}
        bohren.update({"Vorschub_f": textToFloat(self.vorschubBohren.text())})
        bohren.update({"Schnittgeschwindigkeit_vc": textToFloat(self.schnittgeschwindigkeitBohren.text())})
        entgraten = {}
        entgraten.update({"Vorschub": textToFloat(self.vorschubEntgraten.text())})
        entgraten.update({"Overlap": textToInt(self.overlap.text())})
        entgraten.update({"Einfahren": textToInt(self.einfahren.text())})
        config.update({"Bohren": bohren, "Entgraten": entgraten})
        config.update({"n_points": textToInt(self.nPoints.text())})

        bearbeitungsrichtung = ""
        if self.bearbeitungsrichtung.currentIndex() == 0:
            bearbeitungsrichtung = "Uhrzeigersinn"
        elif self.bearbeitungsrichtung.currentIndex() == 1:
            bearbeitungsrichtung = "GegenUhrzeigersinn" 
        config.update({"Bearbeitungsrichtung": bearbeitungsrichtung})

        with open(os.path.expandvars(GUI_SETTINGS["paths"]["autoSaves"] + "processing_setup.json"), 'w') as f:
            json.dump(config, f, indent=4)

        return config

    def openConfig(self, tool: str, machine: str, geometry: dict, processing: dict) -> None:
        """Opens a Project Config with specified tool and machine path and a JSON Structure for geometry and processing"""

        def update_field(widget, readonly, color=''):
            widget.setReadOnly(readonly)
            widget.setStyleSheet(f'background-color: {color}; color: {color};')

        def set_text(widget, value):
            widget.setText(str(value))

        # Set geometry fields
        set_text(self.d_hb, geometry["Verschneidung"]["d_hb"])
        set_text(self.d_qb, geometry["Verschneidung"]["d_qb"])
        set_text(self.av, geometry["Verschneidung"]["av"])
        set_text(self.fb_soll, geometry["Verschneidung"]["fb_soll"])

        self.bool_ebener_Austritt.setChecked(geometry["Allgemein"]["ebener_Austritt"])
        self.bool_Auslegung.setChecked(geometry["Allgemein"]["Auslegung"])

        set_text(self.phi, geometry["Transformation"]["Rotation"]["phi"])
        set_text(self.theta, geometry["Transformation"]["Rotation"]["theta"])
        set_text(self.psi, geometry["Transformation"]["Rotation"]["psi"])
        set_text(self.x, geometry["Transformation"]["Translation"]["x"])
        set_text(self.y, geometry["Transformation"]["Translation"]["y"])
        set_text(self.z, geometry["Transformation"]["Translation"]["z"])

        set_text(self.sicherheitsebene1, geometry["Sicherheitsebenen"]["Sicherheitsebene1"])
        set_text(self.sicherheitsebene2, geometry["Sicherheitsebenen"]["Sicherheitsebene2"])
        set_text(self.bohrtiefe, geometry["Sicherheitsebenen"]["Bohrtiefe"])

        # Update fields based on ebener_Austritt condition
        ebener_Austritt = geometry["Allgemein"]["ebener_Austritt"]
        color = 'lightgrey' if ebener_Austritt else ''
        update_field(self.d_hb, ebener_Austritt, color)
        update_field(self.av, ebener_Austritt, color)

        Auslegung = geometry["Allgemein"]["Auslegung"]
        color = 'lightgrey' if Auslegung else ''
        update_field(self.phi, Auslegung, color)
        update_field(self.theta, Auslegung, color)
        update_field(self.psi, Auslegung, color)
        update_field(self.x, Auslegung, color)
        update_field(self.y, Auslegung, color)
        update_field(self.z, Auslegung, color)
        update_field(self.sicherheitsebene1, Auslegung, color)
        update_field(self.sicherheitsebene2, Auslegung, color)

        # Set processing fields
        set_text(self.vorschubBohren, processing["Bohren"]["Vorschub_f"])
        set_text(self.schnittgeschwindigkeitBohren, processing["Bohren"]["Schnittgeschwindigkeit_vc"])
        set_text(self.vorschubEntgraten, processing["Entgraten"]["Vorschub"])
        set_text(self.overlap, processing["Entgraten"]["Overlap"])
        set_text(self.einfahren, processing["Entgraten"]["Einfahren"])
        set_text(self.nPoints, processing["n_points"])

        if processing["Bearbeitungsrichtung"] == "GegenUhrzeigersinn":
            self.bearbeitungsrichtung.setCurrentIndex(1)
        else:
            self.bearbeitungsrichtung.setCurrentIndex(0)

        # open configs and populate fields via manager
        if os.path.isfile(tool):
            with open(tool) as f:
                config = json.load(f)
                config.update({"FilePath": tool})
                self.toolManager.returnSelected(config)

        if os.path.isfile(machine):
            with open(machine) as f:
                config = json.load(f)
                config.update({"FilePath": machine})
                self.machineManager.returnSelected(config)

        return

    def openRecentConfig(self) -> None:
        """Looks for last setup in autoSaves and tries to open them"""
        # open autosave configs
        if os.path.isfile(os.path.expandvars(GUI_SETTINGS["paths"]["autoSaves"] + "processing_setup.json")):
            with open(os.path.expandvars(GUI_SETTINGS["paths"]["autoSaves"] + "processing_setup.json"), 'r') as f:
                try:
                    processing = json.load(f)
                except:
                    pass
        else:
            return

        if os.path.isfile(os.path.expandvars(GUI_SETTINGS["paths"]["autoSaves"] + "geometry_setup.json")):
            with open(os.path.expandvars(GUI_SETTINGS["paths"]["autoSaves"] + "geometry_setup.json"), 'r') as f:
                try:
                    geometry = json.load(f)
                except:
                    pass
        else:
            return

        # used tool and machine is saved in processing file
        tool = processing["toolPath"]
        machine = processing["machinePath"]

        self.openConfig(tool, machine, geometry, processing)

    def generateGCode(self) -> None:
        """Gets Setup and test if Plausible, if plausible start calculation of Verschneidung and generates G-Code"""
        if self.isInputPlausible():
            try:
                global VERSCHNEIDUNG_CALCULATED
                with open(self.selectedToolConfig["FilePath"], 'r', encoding='utf-8') as file:
                    tool_data = json.load(file)
                tool_data["FilePath"] = self.selectedToolConfig["FilePath"]
                with open(self.selectedMachineConfig["FilePath"], 'r', encoding='utf-8') as file:
                    machine_data = json.load(file)
                VERSCHNEIDUNG_CALCULATED = Verschneidung.Verschneidung(tool_data, machine_data,
                self.generateGeometryJson(), self.generateProcessJson())
                VERSCHNEIDUNG_CALCULATED.checkCollision(self.mainWindow)
                gCodeString = VERSCHNEIDUNG_CALCULATED.output_g_code()


                if not self.thisGcodeEditor == None:
                    self.thisGcodeEditor.setPlainText(gCodeString)
                    self.thisGcodeEditor.moveCursor(QTextCursor.Start)
                    self.thisGcodeEditor.updateFormat()
            except:
                showErrorMessage(self.mainWindow, 
                    LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["errorMessageCalc"], 
                    LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["errorMessageCalcDetail"])
        else:
            return

        if VERSCHNEIDUNG_CALCULATED.flag_warnings:
            self.setGCodeStaturBarAppliedWithWarnings()
        else:
            self.setGCodeStaturBarApplied()


    def writeProjectFile(self) -> None:
        """Generate Project File and writes them to user selected directory"""
        projectConfig = {}
        projectConfig.update({"geometry": self.generateGeometryJson()})
        # Tool an Machine path is saved in process
        projectConfig.update({"process": self.generateProcessJson()})

        projectConfig.update({"gCode": self.thisGcodeEditor.toPlainText()})

        filters = "JSON Config (*.json);; Alle Dateien (*)"
        filename, selected_filter = QFileDialog.getSaveFileName(self.mainWindow, filter = filters)

        if filename:
            with open(filename, "w") as f:
                json.dump(projectConfig, f, indent=4)

    def openProjectFile(self) -> None:
        """Open Project File selected by user"""
        filters = "JSON Config (*.json);; Alle Dateien (*)"
        filename, selected_filter = QFileDialog.getOpenFileName(self.mainWindow, filter=filters)

        if filename:
            with open(filename, "r") as f:
                try: 
                    projectConfig = json.load(f)

                    geometry = projectConfig["geometry"]
                    processing = projectConfig["process"]
                    tool = processing["toolPath"]
                    machine = processing["machinePath"]

                    self.openConfig(tool, machine, geometry, processing)

                    # fill gCode
                    self.thisGcodeEditor.setPlainText(projectConfig["gCode"])
                    self.thisGcodeEditor.moveCursor(QTextCursor.Start)
                    self.thisGcodeEditor.updateFormat()
                except:
                    # Handles all errors if file can not be opend
                    showErrorMessage(self.mainWindow, 
                        LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["errorMessageOpen"], 
                        LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["errorMessageOpenDetail"])

        if self.bool_ebener_Austritt.isChecked():
            self.d_hb = lockedEditLine("")
        elif not self.bool_ebener_Austritt.isChecked():
            self.d_hb = doubleEditLine("", 0, 100, 2, self.mainWindow.statusBar(), ERROR_DOUBLE_EDIT)
    def isInputPlausible(self, plots=False) -> bool:
        """ Test if input is complete and if Inputs are accepted by Validators, shows Error Message if not plausible"""

        geometry = self.generateGeometryJson()
        if not isDictComplete(geometry):
            showErrorMessage(self.mainWindow, 
                LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["errorMessageComplete"], 
                LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["geometryTab"]["title"]
                + LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["errorMessageCompleteDetail"])
            return False

        # Check is qb is to close to the edge of hb
        r_hb = geometry['Verschneidung']['d_hb'] / 2.0
        r_qb = geometry['Verschneidung']['d_qb'] / 2.0
        av = geometry['Verschneidung']['av']
        if r_hb - (r_qb + av) < 0.01:
            showErrorMessage(self.mainWindow,
                             LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["errorMessageCriticalCase"],
                             LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["geometryTab"]["title"]
                             + LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["errorMessageCriticalCaseDetail"])
            return False

        # Skip this check if Plots should be created
        if not plots:
            if geometry["Allgemein"]["Auslegung"]:
                showErrorMessage(self.mainWindow,
                                 LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["errorMeesageAuslegung"],
                                 LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["geometryTab"]["title"]
                                 + LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["errorMessageAuslegungDetail"])
                return False

        if self.selectedToolConfig == None:
            showErrorMessage(self.mainWindow, 
                LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["errorMessageComplete"], 
                LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["toolTab"]["title"]
                + LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["errorMessageCompleteDetail"])

        if self.selectedMachineConfig == None:
            showErrorMessage(self.mainWindow, 
                LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["errorMessageComplete"], 
                LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["machineTab"]["title"]
                + LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["errorMessageCompleteDetail"])

        process = self.generateProcessJson()
        if not isDictComplete(process):
            showErrorMessage(self.mainWindow, 
                LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["errorMessageComplete"], 
                LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["processTab"]["title"]
                + LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["errorMessageCompleteDetail"])
            return False

        valid = True

        for thisInput in self.geometryInputs + self.processInputs:
            state, _, _  = thisInput.validator().validate(thisInput.text(), 0)
            if not state == QValidator.Acceptable:
                thisInput.setStyleSheet("border: 1px solid DarkRed; border-radius: 2px; padding: 2px 0px")
                valid = False
            else:
                thisInput.setStyleSheet("")

        if not valid:
            showErrorMessage(self.mainWindow, 
            LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["errorMessageValidator"], 
            LANGUAGE_SETTINGS.languagePack["setupTabmenu"]["errorMessageValidatorDetail"])
            return False
            
        return True

