from PyQt6 import QtWidgets,QtCore
from PyQt6.QtCore import pyqtSignal,pyqtSlot
from LowLevelWidgetsPackage import defaultConfigForWidgets 
from LowLevelWidgetsPackage.SimpleProgrammablePSUPackage.SimpleProgrammablePSUGUI import Ui_SImpleProgrammablePSU
import time
import traceback
class _PSU_status():
    def __init__(self,output:bool,voltage:float,current:float,voltage_readback:float,current_readback:float,channel:str) -> None:
        self.output = output
        self.voltage = voltage
        self.current = current
        self.voltage_readback = voltage_readback
        self.current_readback = current_readback
        self.channel_name= channel
        self.requested_command = ""


class SignalClass(QtCore.QObject):
    user_input_changed_signal = pyqtSignal(object, str) #_PSU_status, name of widget
    received_data_signal = pyqtSignal(object, str) #_PSU_status, name of widget
        
class SimpleProgrammablePSUClass(QtWidgets.QWidget):
    def __init__(self,channel:str = "CH1", 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 SimpleProgrammablePSU CLASS","UNNECESSARY")
        self.ui = Ui_SImpleProgrammablePSU() #UI form generated by UI designe
        self.ui.setupUi(self)
        self._name = "SimpleProgrammablePSU"
        self.do_once_flag = False
        self.signals = SignalClass()

        self.widgetSTatus = _PSU_status(output=self.ui.che_output_enable.isChecked(),
                                        voltage=float(self.ui.dspin_voltage.value()),
                                        current=float(self.ui.dspin_current.value()),
                                        voltage_readback=float(self.ui.la_measured_voltage.text().replace(",",".").replace("V","")),
                                        current_readback=float(self.ui.la_measured_current.text().replace(",",".").replace("A","")),
                                        channel= channel)

        self.ui.pb_set_current.clicked.connect(self._setCurrentCallback)
        self.ui.pb_set_voltage.clicked.connect(self._setVoltageCallback)
        self.ui.che_output_enable.clicked.connect(self._outputEnableCallback)
        self.ui.pb_readback.clicked.connect(self._readCallback)
        self.signals.received_data_signal.connect(self._updateGUI)

        self.timer = QtCore.QTimer(self)
        self.timer.timeout.connect(self._askForValues)
        self.ui.che_continuous_readback.stateChanged.connect(self._continuousRead)  
        self.thread_pool = QtCore.QThreadPool()

    def _continuousRead(self):
        if self.ui.che_continuous_readback.isChecked():
            self.timer.start(200)
        else:
            self.timer.stop()
    
    def _askForValues(self):
        self.widgetSTatus.requested_command = "MEASURE READBACKS"
        self.signals.user_input_changed_signal.emit(self.widgetSTatus,self._name)

    def _dummyAskForValues(self):
        """THIS FUNCTION MUST BE CALLED AFTER SIGNALS OF PARENT WIDGETS ARE CONNECTED
        it force the SimpleProgrammablePSU to ask for values from the device"""

        self.widgetSTatus.requested_command = "READ ALL"
        self.signals.user_input_changed_signal.emit(self.widgetSTatus,self._name)

    @pyqtSlot(object,str)
    def _updateGUI(self,widgetStatus: _PSU_status, name:str):
        try: 
            self.log.log(f"{self._name} received signal from {name}","DEBUG")
            self.ui.la_measured_current.setText(str(widgetStatus.current_readback)+"A")
            self.ui.la_measured_voltage.setText(str(widgetStatus.voltage_readback)+"V")

            #do this only on initialization....
            if self.do_once_flag == False or widgetStatus.requested_command == "READ ALL":
                self.do_once_flag = True
                self.log.log(f"CHANNEL STATUS IS: {widgetStatus.output}","DEBUG")
                self.ui.che_output_enable.setChecked(int(str(widgetStatus.output).replace("ON","1").replace("OFF","0").replace("True","1").replace("False","0").replace("VIRTUAL","0")))
                self.ui.dspin_current.setValue(float(str(widgetStatus.current).replace("VIRTUAL","0")))
                self.ui.dspin_voltage.setValue(float(str(widgetStatus.voltage).replace("VIRTUAL","0")))

            self.ui.pb_set_current.setEnabled(True)
            self.ui.pb_set_voltage.setEnabled(True)
            self.ui.che_output_enable.setEnabled(True)
            self.ui.che_continuous_readback.setEnabled(True)
        
        except Exception as e:
            self.log.log(f"ERROR in {self._name} _updateGUI: {e}","ERROR")
            self.log.log(traceback.format_exc(),"ERROR",oneline=False)
            self.ui.la_measured_current.setText("ERROR")
            self.ui.la_measured_voltage.setText("ERROR")
            self.ui.pb_set_current.setEnabled(False)
            self.ui.pb_set_voltage.setEnabled(False)
            self.ui.che_output_enable.setEnabled(False)
            self.ui.che_continuous_readback.setEnabled(False)

    
    def _setCurrentCallback(self):
        self.widgetSTatus.current = float(self.ui.dspin_current.text().replace(",","."))
        self.widgetSTatus.requested_command = "SET CURRENT"
        self.signals.user_input_changed_signal.emit(self.widgetSTatus,self._name)
        
    
    def _setVoltageCallback(self):
        self.widgetSTatus.voltage = float(self.ui.dspin_voltage.text().replace(",","."))
        self.widgetSTatus.requested_command = "SET VOLTAGE"
        self.signals.user_input_changed_signal.emit(self.widgetSTatus,self._name)
    
    def _outputEnableCallback(self):
        self.widgetSTatus.output = self.ui.che_output_enable.isChecked()
        self.widgetSTatus.requested_command = "SET OUTPUT"
        self.signals.user_input_changed_signal.emit(self.widgetSTatus,self._name)

    def _readCallback(self):
        self.widgetSTatus.output = self.ui.che_output_enable.isChecked()
        self.widgetSTatus.requested_command = "READ ALL"
        self.signals.user_input_changed_signal.emit(self.widgetSTatus,self._name)

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