class MainView(QMainWindow):
    applicationClosed = Signal()

    def __init__(self):
        super().__init__()

        menuBar = self.menuBar()
        menuBar.addMenu(self.createFileMenu())
        menuBar.addMenu(self.createSettingsMenu())
        menuBar.addMenu(self.createHelpMenu())

        self.statusBar().showMessage("Ready")

        connectionStatusGroupBox = self.createConnectionStatusGroup()
        positionIndicationGroupBox = self.createPositionIndicationGroup()
        turnTableControlGroupBox = self.createTurnTableControlGroup()

        mainWidgetLayout = QVBoxLayout()
        mainWidgetLayout.addWidget(connectionStatusGroupBox)
        mainWidgetLayout.addWidget(positionIndicationGroupBox)
        mainWidgetLayout.addWidget(turnTableControlGroupBox)

        mainWidgetGroup = QGroupBox()
        mainWidgetGroup.setLayout(mainWidgetLayout)

        self.setCentralWidget(mainWidgetGroup)


#------------------------------------------------------------------------------
# Interface Creation Helper Functions
#------------------------------------------------------------------------------
    def createFileMenu(self):
        self.loadZeroPositionDataAction = QAction("Load Zero Position", self)
        self.saveZeroPositionDataAction = QAction("Save Zero Position", self)
        exitAction = QAction(
            "E&xit", 
            self, 
            shortcut="Ctrl+Q", 
            statusTip="Exit the application", 
            triggered=self.close
        )

        fileMenu = QMenu("File")
        fileMenu.addAction(self.loadZeroPositionDataAction)
        fileMenu.addAction(self.saveZeroPositionDataAction)
        fileMenu.addSeparator()
        fileMenu.addAction(exitAction)

        return fileMenu


    def createSettingsMenu(self):
        self.applicationSettingsAction = QAction("Settings", self)

        settingsManagerMenu = QMenu("Settings")
        settingsManagerMenu.addAction(self.applicationSettingsAction)

        return settingsManagerMenu


    def createHelpMenu(self):
        helpViewAction = QAction("Help", self)
        aboutViewAction = QAction("About", self)

        helpMenu = QMenu("Help")
        helpMenu.addAction(helpViewAction)
        helpMenu.addAction(aboutViewAction)

        return helpMenu


    def createPositionIndicationGroup(self):
        self.currentPositionLineEdit = createReadOnlyLineEdit("+0.000")
        self.targetPositionLineEdit = createReadOnlyLineEdit("+0.000")
        self.positionErrorLineEdit = createReadOnlyLineEdit("+0.000")

        self.setCurrentPositionAsZeroButton = QPushButton("Set As Zero")        
        self.resetZeroPositionButton = QPushButton("Reset Zero")

        positionInformationLayout = QGridLayout()
        positionInformationLayout.addWidget(createPositionLabel("Current"), 0, 0)
        positionInformationLayout.addWidget(createPositionLabel("Target"), 0, 1)
        positionInformationLayout.addWidget(createPositionLabel("Error"), 0, 2)
        positionInformationLayout.addWidget(self.currentPositionLineEdit, 1, 0)
        positionInformationLayout.addWidget(self.targetPositionLineEdit, 1, 1)
        positionInformationLayout.addWidget(self.positionErrorLineEdit, 1, 2)
        positionInformationLayout.addWidget(self.setCurrentPositionAsZeroButton, 2, 0)
        positionInformationLayout.addWidget(self.resetZeroPositionButton, 3, 0)

        positionGroupBox = QGroupBox("Azimuth")
        positionGroupBox.setLayout(positionInformationLayout)

        return positionGroupBox


    def createTurnTableControlGroup(self):
        self.gotoPositionSpinBox = createDoubleSpinBox() 
        self.stepSizeSpinBox = createDoubleSpinBox()

        self.goPushButton = QPushButton("Go")
        self.goPushButton.setEnabled(False)
        self.goPushButton.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_G))

        self.stepPushButton = QPushButton("Step")
        self.stepPushButton.setEnabled(False)
        self.stepPushButton.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_S))

        self.enableSteppingCheckBox = QCheckBox("Enable Stepping")
        self.enableSteppingCheckBox.setEnabled(False)
        self.enableSteppingCheckBox.clicked.connect(self.stepPushButton.setEnabled)

        self.stopPushButton = QPushButton("STOP")
        self.stopPushButton.setEnabled(False)
        self.stopPushButton.pressed.connect(lambda: self.motorVoltageSlider.setValue(0.000))
        self.stopPushButton.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_T))

        turnTableVoltageControlGroup = self.createTurnTableVoltageControlGroup()

        turnTableControlGridLayout = QGridLayout()
        turnTableControlGridLayout.addWidget(QLabel("Go To Position:"), 0, 0)
        turnTableControlGridLayout.addWidget(self.gotoPositionSpinBox, 0, 1)
        turnTableControlGridLayout.addWidget(self.goPushButton, 0, 2)
        turnTableControlGridLayout.addWidget(QLabel("Step Size:"), 1, 0)
        turnTableControlGridLayout.addWidget(self.stepSizeSpinBox, 1, 1)
        turnTableControlGridLayout.addWidget(self.stepPushButton, 1, 2)
        turnTableControlGridLayout.addWidget(self.enableSteppingCheckBox, 1, 3)
        turnTableControlGridLayout.addWidget(self.stopPushButton, 2, 3)
        turnTableControlGridLayout.addWidget(turnTableVoltageControlGroup, 3, 0, 3, 4)

        turnTableGroupBox = QGroupBox("Turn Table Controls")
        turnTableGroupBox.setLayout(turnTableControlGridLayout)

        return turnTableGroupBox


    def createTurnTableVoltageControlGroup(self):
        self.motorVoltageSlider = DoubleSlider(orientation=Qt.Orientation.Horizontal)
        self.motorVoltageSlider.setTickPosition(QSlider.TickPosition.TicksBothSides)
        self.motorVoltageSlider.setTickInterval(200)
        self.motorVoltageSlider.setEnabled(False)

        self.motorVoltageSliderValueSpinBox = createDoubleSpinBox()
        self.motorVoltageSliderValueSpinBox.setEnabled(False)

        self.motorVoltageSliderValueSpinBox.valueChanged.connect(self.motorVoltageSlider.setValue)
        self.motorVoltageSlider.doubleValueChanged.connect(self.motorVoltageSliderValueSpinBox.setValue)

        self.resetVoltageButton = QPushButton("Reset")
        self.resetVoltageButton.setEnabled(False)
        self.resetVoltageButton.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_R))
        self.resetVoltageButton.pressed.connect(lambda: self.motorVoltageSlider.setValue(0.000))

        sliderGridLayout = QGridLayout()
        sliderGridLayout.addWidget(QLabel("Min Voltage"), 0, 0, 1, 1)
        sliderGridLayout.addWidget(QLabel("Max Voltage"), 0, 4, 1, 1)
        sliderGridLayout.addWidget(self.motorVoltageSlider, 1, 0, 1, 5)
        sliderGridLayout.addWidget(self.motorVoltageSliderValueSpinBox, 2, 1, 1, 1)
        sliderGridLayout.addWidget(self.resetVoltageButton, 2, 4, 1, 1)

        voltageControlGroupBox = QGroupBox()
        voltageControlGroupBox.setLayout(sliderGridLayout)

        return voltageControlGroupBox


    def createConnectionStatusGroup(self):
        connectionStatusGroup = QGroupBox("Connection Status")

        self.shaftEncoderConnectionStatusLineEdit = createReadOnlyLineEdit("Disconnected")
        self.motorControllerConnectionStatusLineEdit = createReadOnlyLineEdit("Disconnected")
        self.watchDogConnectionStatusLineEdit = createReadOnlyLineEdit("Disconnected")
        self.tcpServerConnectionStatusLineEdit = createReadOnlyLineEdit("Disconnected")

        self.connectButton = QPushButton("Connect")

        self.disconnectButton = QPushButton("Disconnect")
        self.disconnectButton.setEnabled(False)

        connectionButtonLayout = QHBoxLayout()
        connectionButtonLayout.addWidget(self.connectButton)
        connectionButtonLayout.addWidget(self.disconnectButton)

        connectionStatusLayout = QFormLayout()
        connectionStatusLayout.addRow(QLabel("Shaft Encoder: "), self.shaftEncoderConnectionStatusLineEdit)
        connectionStatusLayout.addRow(QLabel("Motor Controller: "), self.motorControllerConnectionStatusLineEdit)
        connectionStatusLayout.addRow(QLabel("Watchdog: "), self.watchDogConnectionStatusLineEdit)
        connectionStatusLayout.addRow(QLabel("TCP Server: "), self.tcpServerConnectionStatusLineEdit)
        connectionStatusLayout.addRow(connectionButtonLayout)

        connectionStatusGroup.setLayout(connectionStatusLayout)

        return connectionStatusGroup


    def closeEvent(self, event):
        messageBox = QMessageBox()
        messageBox.setText("The Turn Table is currently still running.")
        messageBox.setInformativeText("Are you sure you want to exit?")
        messageBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
        messageBox.setDefaultButton(QMessageBox.Cancel)
        
        response = messageBox.exec_()

        if response == QMessageBox.Ok:
            self.applicationClosed.emit()
            event.accept()
        elif response == QMessageBox.Cancel:
            event.ignore()


#------------------------------------------------------------------------------
# Callback functions for handling GUI events
#------------------------------------------------------------------------------
    def updatePositionLineEdits(self, newPosition):
        updatePositionLineEdit(self.currentPositionLineEdit, newPosition.current)
        updatePositionLineEdit(self.targetPositionLineEdit, newPosition.target)
        updatePositionLineEdit(self.positionErrorLineEdit, newPosition.error)


    def updateConnectionStatusLineEdits(self, shaftEncoder: bool, motorController: bool, watchdog: bool, tcpServer: bool):
        updateConnectionStatusLineEdit(self.shaftEncoderConnectionStatusLineEdit, shaftEncoder)
        updateConnectionStatusLineEdit(self.motorControllerConnectionStatusLineEdit, motorController)
        updateConnectionStatusLineEdit(self.watchDogConnectionStatusLineEdit, watchdog)
        updateConnectionStatusLineEdit(self.tcpServerConnectionStatusLineEdit, tcpServer)


    def toggleControls(self):
        toggleControlEnable(self.enableSteppingCheckBox)
        toggleControlEnable(self.stopPushButton)
        toggleControlEnable(self.goPushButton)
        toggleControlEnable(self.connectButton)
        toggleControlEnable(self.disconnectButton)
        toggleControlEnable(self.motorVoltageSlider)
        toggleControlEnable(self.motorVoltageSliderValueSpinBox)
        toggleControlEnable(self.resetVoltageButton)