#!D:\IDE\Anaconda3\envs\Microscope_Scan python
# -*- coding: UTF-8 -*-
"""
 @Author: Administrator
 @FileName: AppTimeLoop.py
 @DateTime: 2025/3/23 16:50
 @SoftWare: PyCharm
 @Author  ：xsh
"""
from PyQt5 import Qt
# from AppSettings.Settings import
LOOP_SIGNAL_CONNECTION_TYPE: Qt.Qt.ConnectionType = Qt.Qt.ConnectionType(Qt.Qt.AutoConnection | Qt.Qt.UniqueConnection)
MIN_WAIT_TIMES      : int = 2
DELAY_WAIT_TIME     : int = 50
PROCESS_EVENT_TIME  : int = 200
MIN_SEEP_TIMES      : int = 1


class AppTimeLoop(Qt.QObject):
    m_Timer         : Qt.QTimer
    m_Loop          : Qt.QEventLoop
    m_Args          : list
    m_Kwargs        : dict
    m_CallBack      : callable
    finished        : Qt.pyqtSignal = Qt.pyqtSignal()
    timeout         : Qt.pyqtSignal = Qt.pyqtSignal()
    m_Control       : Qt.QObject = None
    m_ParentControl : Qt.QObject = None
    def __init__(self, parent: Qt.QObject = None):
        super(AppTimeLoop, self).__init__(parent=parent)
        self.Initialization(self, parent)

    def quit(self):
        self.finished.emit()

    def exit(self):
        self.slot_FinishedLoop()

    def isActive(self) -> bool:
        return self.isValid() and self.m_Timer.isActive()

    def remainingTime(self) -> int:
        if not self.isValid():
            return 0
        return self.m_Timer.remainingTime()

    def execute(self, interVal: int, callBack: callable, *args, **kwargs) -> bool:

        self.start(interVal)
        try:
            self.m_Args = list(args)
        except Exception as e:
            self.m_Args = None
        try:
            self.m_Kwargs = dict(kwargs)
        except Exception:
            self.m_Kwargs = None
        self.m_CallBack = callBack
        if self.m_CallBack is None:
            self.m_Loop.exec()
            return True

        if self.m_Args is not None and len(self.m_Args) > 0:
            if self.m_Kwargs is not None and len(self.m_Kwargs) > 0:
                self.m_CallBack(*self.m_Args, **self.m_Kwargs)
            else:
                self.m_CallBack(*self.m_Args)
        else:
            if self.m_Kwargs is not None and len(self.m_Kwargs) > 0:
                self.m_CallBack(**self.m_Kwargs)
            else:
                self.m_CallBack()
        return True

    def start(self, interVal=1000):
        self.initData()
        waittimes: int = abs(interVal)
        waittimes = MIN_WAIT_TIMES if waittimes <= MIN_WAIT_TIMES else waittimes
        if not self.isValid():
            self.initData()
            self.initConnect()
        if self.isActive():
            self.m_Timer.blockSignals(True)
            self.m_Timer.stop()
            self.m_Timer.blockSignals(False)
            self.m_Loop.quit()
            while self.m_Loop.isRunning():
                Qt.QCoreApplication.processEvents(Qt.QEventLoop.AllEvents, MIN_WAIT_TIMES)
        self.m_Timer.start(waittimes)

    def stop(self):
        if not self.isValid():
            return
        if not self.isActive():
            return
        self.m_Timer.stop()

    @staticmethod
    def processEvents(interVal: int):
        waittimes: int = abs(interVal)
        waittimes = MIN_WAIT_TIMES if waittimes <= MIN_WAIT_TIMES else waittimes
        ETime: Qt.QDateTime = Qt.QDateTime.currentDateTime().addMSecs(waittimes)
        while True:
            if Qt.QDateTime.currentDateTime() > ETime:
                break
            Qt.QCoreApplication.processEvents(Qt.QEventLoop.AllEvents, DELAY_WAIT_TIME)

    @staticmethod
    def processGlobalEvents(interVal: int):
        waittimes: int = abs(interVal)
        waittimes = MIN_WAIT_TIMES if waittimes <= MIN_WAIT_TIMES else waittimes
        Qt.QCoreApplication.processEvents(Qt.QEventLoop.AllEvents, waittimes)

    @staticmethod
    def delay(interVal: int):
        waittimes: int = abs(interVal)
        waittimes = 2 if waittimes <= 2 else waittimes

        ETime: Qt.QTime = Qt.QTime.currentTime().addMSecs(waittimes)
        while True:
            if Qt.QTime.currentTime() > ETime:
                break


    @staticmethod
    def wait(interVal: int):
        waittimes: int = abs(interVal)
        waittimes = MIN_WAIT_TIMES if waittimes <= MIN_WAIT_TIMES else waittimes
        Qt.QThread.msleep(waittimes)

    @staticmethod
    def sleep(interVal: int):
        waittimes: int = abs(interVal)
        waittimes = 1 if waittimes <= 1 else waittimes
        waittimes = waittimes * 1000
        Qt.QThread.msleep(waittimes)

    @staticmethod
    def msleep(interVal: int):
        waittimes: int = abs(interVal)
        waittimes = MIN_SEEP_TIMES if waittimes <= MIN_SEEP_TIMES else waittimes
        Qt.QThread.msleep(waittimes)

    def isValid(self) -> bool:
        if not hasattr(self, 'm_Timer') or not isinstance(self.m_Timer, Qt.QTimer):
            return False
        if not hasattr(self, 'm_Loop') or not isinstance(self.m_Loop, Qt.QEventLoop):
            return False
        return True

    def initData(self):
        if not hasattr(self, 'm_Timer') or not isinstance(self.m_Timer, Qt.QTimer):
            self.m_Timer = Qt.QTimer()
        if not hasattr(self, 'm_Loop') or not isinstance(self.m_Loop, Qt.QEventLoop):
            self.m_Loop = Qt.QEventLoop()
        self.m_Args = None
        self.m_Kwargs = None
        self.m_CallBack = None

    def deleData(self):
        pass

    def initConnect(self):
        self.m_Timer.timeout.connect(slot=self.slot_TimeOut, type=LOOP_SIGNAL_CONNECTION_TYPE)
        self.finished.connect(slot=self.slot_FinishedLoop, type=LOOP_SIGNAL_CONNECTION_TYPE)

        pass

    def deleConnect(self):
        self.finished.disconnect()
        if self.isValid():
            self.m_Timer.timeout.disconnect()
        pass

    def initValue(self):
        pass

    def deleValue(self):
        pass

    def initProperty(self):
        self.m_Timer.setTimerType(Qt.Qt.TimerType.PreciseTimer)
        self.m_Timer.setSingleShot(True)

    def deleProperty(self):
        pass



    def Initialization(self, control: Qt.QObject, parent: Qt.QObject) -> None:
        self.SetupUi(control, parent)
        self.initialize()

    def SetupUi(self, control: Qt.QObject, parent: Qt.QObject):
        self.m_Control = control
        self.m_ParentControl = parent
        if not isinstance(self.m_Control, Qt.QObject):
            return
        self.m_Control.setObjectName(self.__class__.__name__)
        if self.m_Control.parent() != self.m_ParentControl and isinstance(self.m_ParentControl, Qt.QObject):
            self.m_Control.setParent(self.m_ParentControl)
        Qt.QMetaObject.connectSlotsByName(self.m_Control)

    def initialize(self):
        self.initData       ()
        self.initValue      ()
        self.initProperty   ()
        self.initConnect    ()
        pass

    def deinitialize(self):
        self.deleConnect    ()
        self.deleProperty   ()
        self.deleValue      ()
        self.deleData       ()
        pass

    def slot_TimeOut(self):
        if self.m_Timer.isActive():
            self.m_Timer.stop()
        if not hasattr(self, 'm_Loop') or not isinstance(self.m_Loop, Qt.QEventLoop):
            return
        self.m_Loop.exit()
        self.timeout.emit()

    def slot_FinishedLoop(self):
        if self.m_Timer.isActive():
            self.m_Timer.stop()
        if not hasattr(self, 'm_Loop') or not isinstance(self.m_Loop, Qt.QEventLoop):
            return
        self.m_Loop.exit()



