class APISSystemTableEditor(QDialog, FORM_CLASS):
    def __init__(self, dbm, parent=None):
        """Constructor."""
        self.dbm = dbm
        super(APISSystemTableEditor, self).__init__(parent)

        self.table = None
        self.model = None
        self.insertQuery = None
        self.updateQuery = None
        self.deleteQuery = None
        self.inputDialog = None

        self.setupUi(self)

        self.uiEditBtn.setEnabled(False)
        self.uiRemoveBtn.setEnabled(False)

        self.rejected.connect(self.onClose)

        self.setupTable()

    def setupTable(self):
        self.uiSystemTableV.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.uiSystemTableV.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.uiSystemTableV.resizeColumnsToContents()
        self.uiSystemTableV.resizeRowsToContents()
        self.uiSystemTableV.horizontalHeader().setSectionResizeMode(
            QHeaderView.Stretch)

    def onSelectionChanged(self):
        if self.uiSystemTableV.selectionModel().hasSelection():
            self.uiEditBtn.setEnabled(True)
            self.uiRemoveBtn.setEnabled(True)
        else:
            self.uiEditBtn.setEnabled(False)
            self.uiRemoveBtn.setEnabled(False)

    def loadTable(self, table):
        # check if table in db
        if not DbHasTable(self.dbm.db, table):
            return False

        self.table = table
        self.dbm.createTriggerForSystemTable(table)
        # TODO: if returns FALSE then deactivate editing Capabilites + Wanring

        self.uiSysTableLbl.setText(self.table)

        self.model = QSqlRelationalTableModel(self, self.dbm.db)
        self.model.setTable(table)
        self.model.select()
        #rc = self.model.rowCount()
        while (self.model.canFetchMore()):
            self.model.fetchMore()
            #rc = self.model.rowCount()

        self.uiSystemTableV.setModel(self.model)
        self.uiSystemTableV.selectionModel().selectionChanged.connect(
            self.onSelectionChanged)
        self.onSelectionChanged()

        # dummyRecord holds field structure!
        dummyRecord = self.model.record()
        editors = []
        for fIdx in range(dummyRecord.count()):
            field = dummyRecord.field(fIdx)
            if field.name() != "ogc_fid":
                editors.append({
                    'name': field.name(),
                    'type': field.type(),
                    'lineEdit': QLineEdit(),
                    'default': None
                })

        # init input dialog
        self.inputDialog = APISInputDialog(editors, dummyRecord, parent=self)
        self.uiAddBtn.clicked.connect(self.addRecord)
        self.uiEditBtn.clicked.connect(
            self.editRecord
        )  # in EditMode: load current Value; try to update (but with trigger: only possible to update if not in use!!!)
        self.uiRemoveBtn.clicked.connect(self.removeRecord)
        return True

    def addRecord(self):
        if self.inputDialog.exec_():
            rec = self.inputDialog.getRecord()
            if not rec.isEmpty():
                res = self.model.insertRowIntoTable(rec)
                if res:
                    self.model.select()
                    self.dbm.dbRequiresUpdate = True
                else:
                    QMessageBox.warning(
                        self, "DB Fehler",
                        "Der folgende Fehler ist aufgetreten: {}".format(
                            self.model.lastError().text()))
        else:
            pass
        self.inputDialog.resetEditors()

    def editRecord(self):
        recIdx = self.uiSystemTableV.selectionModel().currentIndex().row()
        # Get current Record for index
        currRec = self.model.record(recIdx)
        # Set current Record in Dialog
        self.inputDialog.setEditors(currRec)
        if self.inputDialog.exec_():
            data = self.inputDialog.getData()
            # QMessageBox.information(None, "edited record", f"{data}")
            for key in data:
                currRec.setValue(key, data[key])
            if not currRec.isEmpty():
                res = self.model.updateRowInTable(recIdx, currRec)
                if res:
                    self.model.select()
                    self.dbm.dbRequiresUpdate = True
                else:
                    QMessageBox.warning(
                        self, "DB Fehler",
                        "Der folgende Fehler ist aufgetreten: {}".format(
                            self.model.lastError().text()))
        self.inputDialog.resetEditors()

    def removeRecord(self):
        #Check if one really wants to remove the entry!
        # Abfrage wirklich löschen
        header = u"Eintrag löschen"
        question = u"Möchten Sie den Eintrag wirklich aus der Datenbank löschen?"
        result = QMessageBox.question(self, header, question,
                                      QMessageBox.Yes | QMessageBox.No,
                                      QMessageBox.Yes)
        if result == QMessageBox.Yes:
            recIdx = self.uiSystemTableV.selectionModel().currentIndex().row()
            # QMessageBox.information(self, "Information", f"Current Idx {recIdx}")
            res = self.model.removeRow(recIdx)
            if res:
                self.model.select()
                self.dbm.dbRequiresUpdate = True
            else:
                QMessageBox.warning(
                    self, "DB Fehler",
                    "Der folgende Fehler ist aufgetreten: {}".format(
                        self.model.lastError().text()))

    def onClose(self):
        '''
        Run some actions when
        the user closes the dialog
        '''
        self.uiAddBtn.clicked.disconnect(self.addRecord)
        self.uiEditBtn.clicked.disconnect(self.editRecord)
        self.uiRemoveBtn.clicked.disconnect(self.removeRecord)
        self.inputDialog.deleteLater()
class StampTableWidget(StampTableView):

    addStampSignal = pyqtSignal(str)
    # deleteStampSignal = pyqtSignal()
    surveyModeSignal = pyqtSignal(bool)

    def __init__(self):
        super().__init__()
        self.hasSelection = False  # todo
        self.surveyDatetime = None

        # init table model
        self.stampTableModel = QSqlRelationalTableModel()
        self.stampTableModel.setTable(R.tableName)
        self.stampTableModel.setEditStrategy(QSqlTableModel.OnFieldChange)
        self.stampTableModel.setFilter("survey_datetime = None")
        self.stampTableModel.select()
        self.stampTableView.setModel(self.stampTableModel)
        self.stampTableSelectionModel = self.stampTableView.selectionModel()
        self.stampTableSelectionModel.selectionChanged.connect(
            self.onStampSelectionChange)

        # connect buttons
        self.addStampButton.clicked.connect(
            lambda ignore, key="-": self.addStampSignal.emit(key))
        self.deleteStampButton.clicked.connect(self.deleteButtonAction)
        self.hotkeyButton.clicked.connect(self.enableHotkeys)
        # self.recordButton.clicked.connect(self.surveyMode)

        # hotkeys
        self.hotkeys = self.initHotkeys()

        # copy selection to clipboard
        self.installEventFilter(self)

    def eventFilter(self, source, event):
        if (event.type() == QEvent.KeyPress
                and event.matches(QKeySequence.Copy)):
            self.copySelection()
            return True
        return super().eventFilter(source, event)

    def copySelection(self):
        selection = self.stampTableView.selectedIndexes()
        if selection:
            rows = sorted(index.row() for index in selection)
            columns = sorted(index.column() for index in selection)
            rowcount = rows[-1] - rows[0] + 1
            colcount = columns[-1] - columns[0] + 1
            table = [[''] * colcount for _ in range(rowcount)]
            for index in selection:
                row = index.row() - rows[0]
                column = index.column() - columns[0]
                table[row][column] = index.data()
            stream = io.StringIO()
            csv.writer(stream).writerows(table)
            QApplication.clipboard().setText(stream.getvalue())

    def initHotkeys(self):
        keyList = []

        shortcut = QShortcut(
            QKeySequence(Qt.Key_Space, QKeySequence.NativeText), self)
        keyList.append(shortcut)
        shortcut.activated.connect(
            lambda key="-": self.addStampSignal.emit(key))

        for i in range(0, 10):
            print(i)
            shortcut = QShortcut(QKeySequence(str(i), QKeySequence.NativeText),
                                 self)
            keyList.append(shortcut)
            shortcut.activated.connect(
                lambda key=str(i): self.addStampSignal.emit(key))
        return keyList

    def enableHotkeys(self, isClicked):
        for shortcut in self.hotkeys:
            shortcut.setEnabled(isClicked)

    def onDeselection(self):
        self.enableHotkeys(False)
        self.hotkeyButton.setChecked(False)

    # TODO delete
    def testHotKey(self, key):
        print("test")
        print(key)

    # TODO maybe repaint
    def loadSurveyStamps(self, keys):
        print("LSS")
        self.surveyDatetime = keys[0]
        filter = self.createFilter(keys)
        self.stampTableModel.setFilter(filter)
        self.stampTableModel.select()
        print("survey_datetime = " + self.surveyDatetime)
        QApplication.processEvents()
        self.repaint()

    def createFilter(self, keys):
        filter = "survey_datetime = \"" + self.surveyDatetime + "\""
        for i in range(1, len(keys)):
            filter = filter + " OR survey_datetime = \"" + keys[i] + "\""
        print(filter)
        return filter

    @pyqtSlot()
    def deleteButtonAction(self):
        for row in self.stampTableSelectionModel.selectedRows():
            self.stampTableModel.removeRow(row.row())
        self.stampTableSelectionModel.clearSelection()
        self.stampTableModel.select()
        QApplication.processEvents()

    def clearSurveyStamps(self):
        self.surveyDatetime = None
        # self.stampTableModel.setFilter("") # TODO will this work?
        self.stampTableModel.setFilter("survey_datetime = None")
        print("survey_datetime = None")

    def addStamp(self, stamp, key="-"):
        stampRecord = StampRecord(miliseconds=stamp,
                                  surveyDatetime=self.surveyDatetime,
                                  label=key,
                                  note="")
        sqlRecord = stampRecord.getQSQLRecord(self.stampTableModel.record())
        self.stampTableModel.insertRecord(0, sqlRecord)
        # self.surveyWidget.sortByKey()
        # self.surveyWidget.select(0)
        QApplication.processEvents()  # allow for selection highlight

    def addRecord(self, stampRecord):
        sqlRecord = stampRecord.getQSQLRecord(self.stampTableModel.record())
        print(self.stampTableModel.insertRowIntoTable(sqlRecord))

        # self.repaint() # TODO
        # self.surveyModeSignal.emit(modeOn)

    # @pyqtSlot(bool)
    # def enableSurvey(self, canSurvey):
    #     print(canSurvey)
    #     self.recordButton.setEnabled(canSurvey)

    @pyqtSlot()
    def testButtonAction(self):
        print("Test")

    @pyqtSlot(bool)
    def surveyMode(self, modeOn):
        self.addStampButton.setEnabled(modeOn)
        self.hotkeyButton.setEnabled(modeOn)
        self.enableHotkeys(self.hotkeyButton.isChecked())

    @pyqtSlot(QItemSelection)
    def onStampSelectionChange(self, selection):
        self.hasSelection = selection.count() > 0
        self.deleteStampButton.setEnabled(self.hasSelection)

    @pyqtSlot(bool)
    def enableStamps(self, modeOn):
        self.addStampButton.setEnabled(modeOn)
        self.hotkeyButton.setEnabled(modeOn)
        if not modeOn and self.hotkeyButton.isChecked():
            self.hotkeyButton.setChecked(False)
            self.enableHotkeys(False)
class APISAdvancedInputDialog(QDialog):
    def __init__(self,
                 dbm,
                 tableName,
                 showEntriesCombo,
                 modelColumnName=None,
                 excludeEntries=None,
                 parent=None):
        super(APISAdvancedInputDialog, self).__init__(parent)

        self.dbm = dbm
        self.tableName = tableName
        self.modelColumnName = modelColumnName
        self.showEntriesCombo = showEntriesCombo
        self.excludeEntries = excludeEntries

        self.valueToBeAdded = None
        self.editors = None
        self.record = None
        self.tableExists = False

        if self.prepairEditorsAndRecord():
            self.setupForm()
        else:
            pass
            # something went wrong preping

    def prepairEditorsAndRecord(self):
        if not DbHasTable(self.dbm.db, self.tableName):
            return False

        self.tableExists = True

        self.model = QSqlRelationalTableModel(self, self.dbm.db)
        self.model.setTable(self.tableName)
        self.model.select()
        while (self.model.canFetchMore()):
            self.model.fetchMore()

        self.record = self.model.record()
        self.editors = []
        for fIdx in range(self.record.count()):
            field = self.record.field(fIdx)
            if field.name() != "ogc_fid":
                self.editors.append({
                    'name': field.name(),
                    'type': field.type(),
                    'lineEdit': QLineEdit()
                })

        return True

    def setupForm(self):
        layout = QFormLayout()

        if self.showEntriesCombo:
            self.uiAvailableEntriesCombo = QComboBox()
            # populate (but exlude if exclude has elements)

            if self.excludeEntries and len(self.excludeEntries) > 0:
                self.model.setFilter("{0} NOT IN ({1})".format(
                    self.modelColumnName,
                    ",".join("'{0}'".format(i) for i in self.excludeEntries)))
                # QMessageBox.information(self, "info", "{0} NOT IN ({1})".format(self.modelColumnName, ",".join("'{0}'".format(i) for i in self.excludeEntries)))
                # self.model.select()
            self.model.removeColumn(0)
            self.setupComboBox(self.uiAvailableEntriesCombo,
                               self.model.fieldIndex(self.modelColumnName))
            layout.addRow(self.uiAvailableEntriesCombo)

            self.uiAddBtn = QPushButton("Hinzufügen")
            if self.uiAvailableEntriesCombo.count() < 1:
                self.uiAddBtn.setEnabled(False)
            self.uiAddBtn.clicked.connect(self.addInputToSelection)
            layout.addRow(self.uiAddBtn)

        for editor in self.editors:
            # QMessageBox.information(self, "info", "{}".format((editor["name"])))
            if editor["name"] != "ogc_fid":
                label = QLabel(editor["name"])
                # QMessageBox.information(None, "info", "{}".format(editor["type"]))
                if editor["type"] == QVariant.Int:
                    intVal = QIntValidator()
                    intVal.setBottom(0)
                    editor['lineEdit'].setValidator(intVal)
                layout.addRow(label, editor['lineEdit'])
                editor['lineEdit'].textEdited.connect(self.onTextEdited)

        self.uiSubmitBtn = QPushButton("Speichern")
        self.uiSubmitBtn.setEnabled(False)
        self.uiSubmitBtn.clicked.connect(self.saveInputAsQSqlRecord)
        layout.addRow(self.uiSubmitBtn)
        self.setLayout(layout)
        self.setWindowTitle("APIS Input Dialog")
        self.adjustSize()

    def onTextEdited(self, text):
        for editor in self.editors:
            if len(editor['lineEdit'].text().replace(" ", "")) == 0:
                self.uiSubmitBtn.setEnabled(False)
                return
        self.uiSubmitBtn.setEnabled(True)

    def addInputToSelection(self):
        self.setValueToBeAdded(self.uiAvailableEntriesCombo.currentText())
        self.accept()

    def setValueToBeAdded(self, value):
        self.valueToBeAdded = value

    def getValueToBeAdded(self):
        return self.valueToBeAdded

    def saveInputAsQSqlRecord(self):
        for editor in self.editors:
            self.record.setValue(editor["name"], editor['lineEdit'].text())
        if not self.record.isEmpty():
            result = self.model.insertRowIntoTable(self.record)
            if result:
                self.setValueToBeAdded(
                    self.record.field(self.modelColumnName).value())
                self.accept()
            else:
                QMessageBox.warning(
                    self, "DB Fehler",
                    "Der folgende Feheler ist aufgetreten: {}".format(
                        self.model.lastError().text()))
                self.reject()
        else:
            self.reject()

    def setupComboBox(self, editor, modelColumn):
        tv = QTableView()
        editor.setView(tv)

        tv.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        tv.setSelectionMode(QAbstractItemView.SingleSelection)
        tv.setSelectionBehavior(QAbstractItemView.SelectRows)
        tv.setAutoScroll(False)

        editor.setModel(self.model)

        editor.setModelColumn(modelColumn)
        editor.setInsertPolicy(QComboBox.NoInsert)

        tv.resizeColumnsToContents()
        tv.resizeRowsToContents()
        tv.verticalHeader().setVisible(False)
        tv.horizontalHeader().setVisible(True)
        #tv.setMinimumWidth(tv.horizontalHeader().length())
        tv.horizontalHeader().setStretchLastSection(True)
        #tv.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
        tv.resizeColumnsToContents()
        scroll = 0 if editor.count() <= editor.maxVisibleItems(
        ) else QApplication.style().pixelMetric(QStyle.PM_ScrollBarExtent)
        tv.setMinimumWidth(tv.horizontalHeader().length() + scroll)