#!D:/IDE/anaconda3/envs/Microscope_Scan python
# -*- coding: UTF-8 -*-
"""
@FileName：ScanCodeImpl.py
@Description：
@Author：XSH
@Time：2025/11/11 20:16
@Department：研发部
@Copyright：©2025 乐辰生物
"""
import sys
import clr
import socket
import gc
import struct
from clr_loader.types                           import Assembly, ClrFunction    #
from PyQt5                                  import Qt                   #
from AppContexts.Contexts import SerialContext
from AppInterfaces.ImplInterfaces import ScanCodeImplInterface
from AppInterfaces.AppTimeLoop import AppTimeLoop
from AppUtils.AppUtils import AppUtils
from AppCore.AppRequestModels.SerialRequest import SerialRequest
from AppSettings.Settings import (RECODE_FAILURE, RECODE_SUCCEED)
from AppUtils.SerialPortUtil import SerialPortUtil
MAX_SERIAL_DEFAULT_WAIT_TIMES   : int = 5000
MAX_SERIAL_READ_DELAY           : int = 5
MAX_SERIAL_SEND_BUFFER_LENGTH   : int = 255
SERIAL_CODE_SCAN_DELAY          : int = 50
SERIAL_READ_CODE_SCAN_DELAY     : int = 200

class ScanCodeImpl(Qt.QObject, ScanCodeImplInterface):
    ocker: Qt.QMutex = Qt.QMutex()

    @classmethod
    def GetInstance(cls, *args, **kwargs) -> 'ScanCodeImpl':
        return super(ScanCodeImpl, cls).GetInstance(*args, **kwargs)

    def __init__(self, context: SerialContext = None, parent: Qt.QObject = None):
        super(ScanCodeImpl, self).__init__(parent=parent)
        self.Parameter = context
        self.Initialization("ScanCodeImpl", self, parent)
        self.initContext()
        self.ReOpen()

    def initContext(self):
        from AppSettings.AppSetting import AppConfig
        if not self.hasParameter:
            self.Parameter = SerialContext()
            try:
                self.Parameter.deserialize(AppConfig.CodeScanningConfig.serialize())
            except Exception as e:
                pass

    def waitForScanning(self, timeout: int = 1500) -> bool:
        return False

    def StartScanningCode(self) -> int:
        try:
            if not self.isAvailable:
                self.ReOpen()
            if not self.isAvailable:
                return RECODE_FAILURE
            return self.Controller.ScanCode(self.Manager, 1000)
        except Exception as e:
            AppUtils.print_Exception(e)
            return RECODE_FAILURE

    def StopScanningCode(self, timeout: int = 1500) -> int:
        try:
            if not self.isAvailable:
                self.ReOpen()
            if not self.isAvailable:
                return RECODE_FAILURE
            return self.Controller.StopScanCode(self.Manager, timeout)
        except Exception as e:
            AppUtils.print_Exception(e)
            return RECODE_FAILURE

    def ReadScanningCode(self, timeout: int = 1500) -> str:
        try:
            if not self.isAvailable:
                self.ReOpen()
            if not self.isAvailable:
                return None
            return self.Controller.ScanCode(self.Manager, timeout)
        except Exception as e:
            AppUtils.print_Exception(e)
            return None

    def setHostMode(self) -> int:
        try:
            if not self.isAvailable:
                self.ReOpen()
            if not self.isAvailable:
                return RECODE_FAILURE
            return self.Controller.SetHostMode(self.Manager)
        except Exception as e:
            AppUtils.print_Exception(e)
            return RECODE_FAILURE

    def getVERSION(self) -> int:
        try:
            if not self.isAvailable:
                self.ReOpen()
            if not self.isAvailable:
                return RECODE_FAILURE
            return self.Controller.GetVersion(self.Manager)
        except Exception as e:
            AppUtils.print_Exception(e)
            return RECODE_FAILURE

    @property
    def isAvailable(self) -> bool:
        try:
            return self.isValid() and self.Manager.IsAvailable
        except Exception as e:
            return False

    def isValid(self) -> bool:
        try:
            return self.hasManager and self.hasParameter and self.hasController and self.Manager.IsValid
        except Exception as e:
            return False

    def IsOpen(self) -> bool:
        try:
            return self.hasManager and self.Manager.IsOpen
        except Exception as e:
            return False

    def isEnabled(self) -> bool:
        try:
            return self.hasManager and self.Manager.IsOpen
        except Exception as e:
            return False

    def isDisable(self) -> bool:
        return not self.isEnabled()

    def Open(self, timeOut: int = 1000) -> int:
        if not self.hasManager:
            self.initManager(None)
        if not self.hasManager:
            return RECODE_FAILURE
        try:
            self.Manager.setParameter(self.Parameter.COM, self.Parameter.BaudRate, self.Parameter.DataBit,
                                      self.Parameter.StopBit, self.Parameter.ParityBit)
            self.Manager.Open()
            self.Parameter.IsOpen = self.Manager.IsOpen
        except Exception as e:
            AppUtils.print_Exception(e)
        return RECODE_SUCCEED if self.Parameter.IsOpen else RECODE_FAILURE

    def Close(self, timeOut: int = 1000) -> int:
        if not self.hasManager:
            return RECODE_SUCCEED
        try:
            self.Manager.Close()
            self.Manager.deleManager()
            self.Manager = None
        except Exception as e:
            pass
        self.Manager = None
        gc.collect()
        return RECODE_SUCCEED

    def initManager(self, context: object = None, **args):
        self.initContext()
        if not self.hasManager:
            try:
                filename: str = self.Parameter.absoluteFilePath
                info: Qt.QFileInfo = Qt.QFileInfo(filename)
                if not info.exists() or not Qt.QLibrary.isLibrary(info.absoluteFilePath()):
                    return
                sys.path.append(info.absoluteFilePath())
                clr.AddReference(info.absoluteFilePath())
                from IScanCode import ScanCodeReader, ScanCodeController
                self.Manager: ScanCodeReader = ScanCodeController.Instance()
                self.Controller: ScanCodeController = ScanCodeController()
                self.Manager.setParameter(self.Parameter.COM, self.Parameter.BaudRate, self.Parameter.DataBit,
                                          self.Parameter.StopBit, self.Parameter.ParityBit)
            except Exception as e:
                self.Manager = None
                AppUtils.print_Exception(e)

    def deleManager(self):
        if self.hasManager:
            self.Manager = None
            gc.collect()



