#!D:\IDE\Anaconda3\envs\Microscope_Scan python
# -*- coding: UTF-8 -*-
"""
 @Author: Administrator
 @FileName: logDriver.py
 @DateTime: 2025/6/21 16:52
 @SoftWare: PyCharm
 @Author  ：xsh
"""
from PyQt5 import Qt
from abc import abstractmethod
import threading
import queue
import sys
from AppLog.logUtils import log_exception, logUtils
from AppLog.logEvent import LogLevel, logEvent
from AppLog.logSingleton import logSingleton
from AppLog.logSlot import logSlot
from AppLog.logInterface import logInterface
import inspect
import ctypes


def _async_raise(tid, exctype):
    tid = ctypes.c_long(tid)
    if not inspect.isclass(exctype):
        exctype = type(exctype)
    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
    if res == 0:
        raise ValueError("invalid thread id")
    elif res != 1:
        ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
        raise SystemError("PyThreadState_SetAsyncExc failed")


class logDriver(Qt.QThread, logInterface, logSingleton):
    queueBuffer         : queue.Queue
    condition           : threading.Condition
    is_running          : bool
    is_finish           : bool
    m_Name              : str
    m_Info              : str
    m_Control           : Qt.QObject
    m_ParentControl     : Qt.QObject
    Locker: Qt.QMutex = Qt.QMutex()
    @classmethod
    def GetInstance(cls, *args, **kwargs) -> 'logDriver':
        return super(logDriver, cls).GetInstance(*args, **kwargs)

    def __init__(self, parent: Qt.QObject = None):
        super(logDriver, self).__init__(parent=parent)
        self.Initialization('logDriver', self, parent)




    def initData(self):
        if not self.has_queueBuffer:
            self.queueBuffer        = queue.Queue           ()
        if not self.has_condition:
            self.condition    = threading.Condition   ()
        self.is_finish  = True
        self.is_running = False


    def deleValue(self):
        if self.isValid:
            with self.condition:
                while not self.IsEmpty():
                    self.queueBuffer.get()
                    self.queueBuffer.task_done()
                    Qt.QApplication.processEvents(Qt.QEventLoop.AllEvents, 1000)


    def WaitDone(self, item: logEvent, *args, **kwargs):
        if isinstance(item, logEvent):
            item.WaitDone(*args, **kwargs)

    def run(self) -> None:
        self.process()

    def Start(self):
        if self.isRunning():
            return
        self.is_running = True
        self.start(Qt.QThread.HighPriority)



    def Stop(self):
        self.deleValue()
        with self.condition:
            self.is_running = False
            self.condition.notify_all()
        if isinstance(self, Qt.QThread):
            self.quit()

        self.processGlobalEvents(200)
        end_times: Qt.QDateTime = Qt.QDateTime.currentDateTime().addMSecs(3000)
        while True:

            if self.is_finish:
                break
            if Qt.QDateTime.currentDateTime() > end_times:
                break
            if not self.isRunning():
                break
            self.processGlobalEvents(200)
        if self.isRunning():
            try:
                if isinstance(self, Qt.QThread):
                    self.terminate()
                elif isinstance(self, threading.Thread):
                    _async_raise(self.ident, SystemExit)
            except Exception as e:
                logUtils.print_Exception(e)


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

    def push(self, item, *args, **kwargs):
        with self.condition:
            self.queueBuffer.put(item)
            self.condition.notify_all()

    def process(self):
        self.is_running = True
        self.is_finish = False
        while self.is_running:
            with self.condition:

                if not self.is_running:
                    break
                if self.queueBuffer.empty() and self.is_running:
                    self.condition.wait(0.5)
                else:
                    try:
                        item = self.queueBuffer.get()
                        if item is not None:
                            self.WaitDone(item)
                        self.queueBuffer.task_done()
                    except Exception as e:
                        logUtils.processEvent(e)
                    self.msleep(50)


        self.is_running = False
        self.is_finish = True

        if isinstance(self, Qt.QThread):
            print("%-20s \t线程结束\tID:%-20s \n" % (self.__class__.__name__, self.currentThreadId().__int__()))
        elif isinstance(self, threading.Thread):
            print("%-20s \t线程结束\tID:%-20s\n" % (self.__class__.__name__, self.ident))

    @property
    def isValid(self) -> bool:
        return self.has_queueBuffer and self.has_condition


    @property
    def IsRunning(self) -> bool:
        return self.is_running

    def IsEmpty(self) -> bool:
        try:
            return self.has_queueBuffe and self.queueBuffer.empty()
        except Exception as e:
            return True

    @property
    def has_queueBuffer (self) -> bool:
        return hasattr(self, 'queueBuffer' ) and isinstance(self.queueBuffer, queue.Queue         )

    @property
    def has_condition   (self) -> bool:
        return hasattr(self, 'condition'   ) and isinstance(self.condition  , threading.Condition )

    @property
    def has_is_running  (self) -> bool:
        return hasattr(self, 'is_running'  ) and isinstance(self.is_running , bool                )

    @property
    def has_is_finish   (self) -> bool:
        return hasattr(self, 'is_finish'   ) and isinstance(self.is_finish  , bool                )
