from PyQt6 import QtWidgets
from PyQt6 import QtCore
from LowLevelWidgetsPackage import defaultConfigForWidgets 
from LowLevelWidgetsPackage.Ext80pinIOCardPackage.Ext80pinIOCardGUI import Ui_Form
from LowLevelWidgetsPackage.SingleIOPackage.SingleIOModule import SingleIOClass
import random



class signalClass(QtCore.QObject):
    pin_changed_from_widget = QtCore.pyqtSignal(str,int,int,bool,bool,str) #toSet, cardNumber,PinNumber,output,impendance,sender_name
    pin_voltage_request_from_widget = QtCore.pyqtSignal(int,int,str) #cardNumber,PinNumber,sender_name
    measure_all_voltage_request_from_widget = QtCore.pyqtSignal(int,str) #cardNumber,sender_name
    pin_input_request_from_widget = QtCore.pyqtSignal(int,int,str) #cardNumber,PinNumber,sender_name
    measure_all_inputs_request_from_widget = QtCore.pyqtSignal(int,str) #cardNumber,PinNumber,sender_name
    set_dac_request_from_widget = QtCore.pyqtSignal(int,float,str) #cardNumber,DAC_value,sender_name
    read_config_request_from_widget = QtCore.pyqtSignal(int,str) #cardNumber,sender_name

class Ext80pinIOCardClass(QtWidgets.QWidget):
    """This CARD HAS 80IO pins, controlled by 2x5x8 shiftregisters and 2x5 MUXES, connected via 50pin connector to the mainboard."""
    def __init__(self,log:defaultConfigForWidgets.LOGGER = defaultConfigForWidgets.LOGGER("ALL") ,*args, **kwargs):#args = multiple input variables, **kvargs multiple keyword variables (dictionaries, touples etc.)
    ################ INIT Function ##################
        super().__init__(*args, **kwargs)#super inherits all methods and properties from its parent  (QWIDGET classes)
        #Load UI forms creaated in QTdDesigner
        self.log = log
        self.log.log("STARTING Ext80pinIOCard CLASS","UNNECESSARY")
        self.ui = Ui_Form() #UI form generated by UI designe
        self.ui.setupUi(self)
        self.signals = signalClass()
        self._name = "Ext80pinIOCard"
        self._number = 0
        self.createTable(columnVector=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19])
        self.createTable(columnVector=[20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39])
        self.createTable(columnVector=[40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59])
        self.createTable(columnVector=[60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79])
        self.ui.pb_measure_all_input_states.clicked.connect(self._measureAllInputStates)
        self.ui.pb_measure_all_voltages.clicked.connect(self._measureAllVoltages)
        self.ui.pb_read_config.clicked.connect(self._read_config)
        self.ui.pb_update_DAC.clicked.connect(self._set_dac)

    def _set_dac(self):
        self.signals.set_dac_request_from_widget.emit(self._number,self.ui.spin_DAC.value(),self._name)

    def _read_config(self):
        self.signals.read_config_request_from_widget.emit(self._number,self._name)

    def _measureAllInputStates(self):
        self.signals.measure_all_inputs_request_from_widget.emit(self._number,self._name)

    def _measureAllVoltages(self):
        self.signals.measure_all_voltage_request_from_widget.emit(self._number,self._name)

    def _updateTreshold(self,table:QtWidgets.QTableWidget):
        for row in range(table.rowCount()):
            for column in range(table.columnCount()):
                cellWidget:SingleIOClass
                cellWidget = table.cellWidget(row,column)
                cellWidget.setVoltageTreshold(min=self.ui.spin_voltage_from.value(),max=self.ui.spin_voltage_to.value())


    def _selectTable(self, columnVector:list):
        if columnVector[0] == 0:
            return self.ui.tab_1to20
        
        elif columnVector[0] == 20:
            return self.ui.tab_21to40
        
        elif columnVector[0] == 40:
            return self.ui.tab_41to60
        
        elif columnVector[0] == 60:
            return self.ui.tab_61to80

    def createTable(self,columnVector :list):
        number_of_columns = len(columnVector)
        number_of_rows = 1
        table = self._selectTable(columnVector)
        table.setColumnCount(number_of_columns)
        table.setRowCount(number_of_rows) 

        header = [f"PIN {column+1}" for column in columnVector]
        table.setHorizontalHeaderLabels(header)
        font = table.horizontalHeader().font()
        font.setPointSize(9)
        font.setBold(True)
        table.horizontalHeader().setFont(font)
        table.horizontalHeader().setMaximumHeight(20)
        self._fillTable(table,columnVector[0])
    
    def getPinWidget(self,pinNumber:int) -> SingleIOClass:
        if pinNumber < 20:
            table = self.ui.tab_1to20
        elif pinNumber < 40:
            table = self.ui.tab_21to40
        elif pinNumber < 60:
            table = self.ui.tab_41to60
        elif pinNumber < 80:
            table = self.ui.tab_61to80
        else:
            self.log.log(f"Ext80pinIOCard: pinNumber {pinNumber} is out of range","ERROR")
            return None
        row = 0
        column = pinNumber%20
        return table.cellWidget(row,column)

    def _fillTable(self,table:QtWidgets.QTableWidget,offset:int):
        for row in range(table.rowCount()):
            for column in range(table.columnCount()):
                cellWidget = SingleIOClass(log=self.log)
                cellWidget.setName(f"Pin{column+offset}")
                cellWidget.setPinNumber(column+offset)
                cellWidget.setHideLabels(False)
                cellWidget.setVoltageTreshold(min=self.ui.spin_voltage_from.value(),max=self.ui.spin_voltage_to.value())
                #cellWidget.signals.voltage_to_widget.emit(float(random.randint(0,100)/10),"Ext80pinIOCard")
                #cellWidget.signals.input_to_widget.emit(random.randint(0,1),"Ext80pinIOCard")
                cellWidget.signals.pin_changed_from_widget.connect(self._singlePinChangedCallback)
                cellWidget.signals.pin_input_request_from_widget.connect(self._inputMeasurementRequest)
                cellWidget.signals.pin_voltage_request_from_widget.connect(self._voltageMeasurementRequest)
                table.setCellWidget(row,column,cellWidget)
        
        table.resizeRowsToContents()
        table.resizeColumnsToContents()        

    @QtCore.pyqtSlot(int,str)
    def _voltageMeasurementRequest(self,pinNumber:int,sender_name:str):
        self.log.log(f"Ext80pinIOCard: received voltage measurement request from: {sender_name} -> Emiting same signal with added Card Number","SIGNAL")
        self.signals.pin_voltage_request_from_widget.emit(self._number,pinNumber,sender_name)

    @QtCore.pyqtSlot(int,str)
    def _inputMeasurementRequest(self,pinNumber:int,sender_name:str):
        self.log.log(f"Ext80pinIOCard: received input state measurement request from: {sender_name} -> Emiting same signal with added Card Number","SIGNAL")
        self.signals.pin_input_request_from_widget.emit(self._number,pinNumber,sender_name)

    @QtCore.pyqtSlot(str,int,bool,bool,str)#toSet,PinNumber,output(1->HIGH,0->LOW),impendance (1->HIGH,0->LOW),sender_name
    def _singlePinChangedCallback(self,to_set,pin_number:int,output:bool,impedance:bool, sender_name:str):
        self.log.log(f"Ext80pinIOCard: received signal from: {sender_name},set: {to_set} -- OUTPUT: {output}, Impedance: {impedance} -> Emiting same signal with added Card Number","SIGNAL")
        self.signals.pin_changed_from_widget.emit(to_set,self._number,pin_number,output,impedance,self._name)#toset,cardNumber,PinNumber,output,impendance,sender_name

    def setName(self,name:str):
        #to distinguish between different widgets change self.name -> this name will be emit in signals
        self._name = name

    def setCardNumber(self,number:int):
        self._number = number
        
if __name__ == "__main__":
    app1 = QtWidgets.QApplication([])
    window1 = Ext80pinIOCardClass(QtWidgets.QWidget)
    window1.show()
    app1.exec()