#!D:/IDE/anaconda3/envs/Microscope_Scan python
# -*- coding: UTF-8 -*-
"""
@FileName：AppBusinessController.py
@Description：
@Author：XSH
@Time：2025/11/15 12:59
@Department：研发部
@Copyright：©2025 乐辰生物
"""
import numpy as np
import cv2
import asyncio
import copy
from AppSettings.Settings import *
from PyQt5                                                      import Qt
from abc                                                        import abstractmethod, abstractclassmethod, abstractstaticmethod
from AppInterfaces.utils                                        import *
from AppUtils.utils                                             import *
from AppCore.Levels                                             import *
from AppCore.DBModels                                           import *
from AppInterfaces.Interfaces                                   import *
from AppBackEnd.AppBusinessInterface                            import AppBusinessInterface
from AppCore.Requests                                           import *
from AppUtils.FocusingUtil                                      import FocusingUtil
class AppBusinessController(AppBusinessInterface):
    @abstractmethod
    def isValid(self) -> bool:
        return False

    @abstractmethod
    def Done(self, **args):
        pass

    @abstractmethod
    def WaitDone(self, **args) -> int:
        pass

    @abstractmethod
    def initModules(self, parent: AppBusinessInterface = None, **args):
        pass


    def UpdateDeviceStatus(self):
        if not self.hasDevices:
            self.initDevices()
        if self.hasDevices:
            self.devices.UpdateDeviceStatus()

    def initCamera(self):
        if not self.hasDevices:
            self.initHardWare()
        if not self.hasCamera:
            self.devices.initCamera()


    def initMotion(self):
        if not self.hasDevices:
            self.initHardWare()
        if not self.hasMotion:
            self.devices.initMotion()


    def initScanCode(self):
        if not self.hasDevices:
            self.initHardWare()
        if not self.hasScanCode:
            self.devices.initScanCode()

    def initWebServer(self):
        if not self.hasDevices:
            self.initHardWare()
        if not self.hasWebServer:
            self.devices.initWebServer()


    def initScanLevel(self):
        if not self.hasScanLevel:
            self.ScanLevel = ScanStatusLevel.Default_Status


    def initFlowLocker(self):
        if not self.hasFlowLocker:
            self.FlowLocker = Qt.QMutex()


    def initConfig(self):
        if not self.hasConfig:
            from AppSettings.AppSetting import AppSetting, AppConfig
            self.Config = AppConfig


    def initSystemConfig(self):
        if not self.hasSystemConfig:
            from AppSettings.SystemSetting import SystemSetting, SystemConfig
            self.SystemConfig = SystemConfig

    def initGlobalStatus(self):
        if not self.hasGlobalStatus:
            from AppSettings.AppStatusSetting import AppStatusSetting, AppStatus
            self.GlobalStatus = AppStatus

    def initHardWare(self):
        pass

    def initApplication(self):
        pass


    def initAlgorithm(self):
        pass

    def initEventBus(self):
        pass



    def initCheckBusiness(self):
        pass


    def initPickBusiness(self):
        pass


    def initDropBusiness(self):
        pass


    def initFocusingBusiness(self):
        pass


    def initScanningBusiness(self):
        pass


    def initOilingBusiness(self):
        pass


    def initCellFocusingBusiness(self):
        pass



    def initSlideScanningBusiness(self):
        pass

    """报警控制"""


    def clearWarning(self):
        if self.hasDetection:
            self.detection.buzzer_switch(False)
        self.status.clearWarning()
        if self.status.isPause:
            self.status.setRunning(True)



    def setWarning(self, warning: str, enable: (bool, int) = True):
        if self.hasDetection:
            if self.system.isBuzzerMode:
                self.detection.buzzer_switch(enable)
            else:
                self.detection.buzzer_switch(False)
        self.status.setWarning(enable)
        if enable:
            self.status.setPause(True)
            self.sendWarning(warning)
        else:
            self.status.setRunning(True)

        request: Request = Request.APIInstance(WebAPILevel.getScanningData)
        self.webevent.SendEvent(request)


    def setTrayWarning(self, warning: str, enable: (bool, int) = True):
        if self.hasDetection:
            if self.system.isBuzzerMode:
                self.detection.buzzer_switch(enable)
            else:
                self.detection.buzzer_switch(False)
        self.status.setWarning(enable)
        if enable:
            self.status.setPause(True)
            request: Request = Request.APIInstance(WebAPILevel.pushSlideTableTrayWarning)
            request.data = {'Warning': f'{warning}'}
            self.webevent.SendEvent(request)
            if HeadEndShowMode.get('DEBUG_SHOW', False):
                AppSlot.SlideTableNotEmptySignal.emit()
        else:
            self.status.setRunning(True)





    def sendWarning(self, warning: str):
        from AppLog.logHelper import logWARNING
        if self.hasWebServerEvent:
            request: Request = Request.APIInstance(WebAPILevel.pushWarning)
            request.data = {'Warning': f'{warning}'}
            self.webevent.SendEvent(request)
        if HeadEndShowMode.get('DEBUG_SHOW', False):
            AppSlot.MessageSignal.emit(self.__class__.__name__, warning)
        logWARNING << warning


    def sendMessage(self, message: str):
        from AppLog.logHelper import logWARNING
        if self.hasWebServerEvent:
            request: Request = Request.APIInstance(WebAPILevel.pushMessage)
            request.data = {'Message': f'{message}'}
            self.webevent.SendEvent(request)

        if HeadEndShowMode.get('DEBUG_SHOW', False):
            AppSlot.MessageSignal.emit(self.__class__.__name__, message)
        logWARNING << message


    def isBuzzerAvailable(self) -> bool:
        isBuzzerAvailable: bool = False
        if self.hasDetection:
            isBuzzerAvailable = self.detection.get_buzzer_switch()
        return isBuzzerAvailable


    def setBuzzerAvailable(self, enable: (bool, int)):
        isBuzzerAvailable: bool = True if isinstance(enable, (bool, int)) and enable else False
        if self.hasDetection:
            self.detection.buzzer_switch(isBuzzerAvailable)
        if isBuzzerAvailable != self.status.isBuzzerAvailable():
            self.status.setBuzzerAvailable(isBuzzerAvailable)
        self.status.setPause(isBuzzerAvailable)


    def process_scanning_status(self) -> int:
        """处理扫描状态: 暂停 退出 跳过"""
        """处理跳过"""
        if self.status.isJumpScanning:
            return RECODE_JUMPING
        if self.status.waitForExitRunning():
            return RECODE_CHANGED
        """退出或者暂停处理"""
        while self.status.waitForPauseRunning():
            AppTimeLoop.processEvents(self.system.WarningWaitTimes())
            self.devices.SlotStatusTimerTimeOut()
        return RECODE_SUCCEED

    def process_scanning_warning(self, warning_string: str, isBuzzer: bool = True):
        self.setWarning(warning_string, isBuzzer)
        if isBuzzer:
            count = 0
            while self.waitForBuzzerOFF():
                if self.status.waitForExitRunning():
                    self.clearWarning()
                    break
                AppTimeLoop.processEvents(self.system.WarningWaitTimes())
                self.devices.SlotStatusTimerTimeOut()
                count += 1
                if count >= 20:
                    count = 0
                    self.setWarning(warning_string, isBuzzer)
        self.clearWarning()

    def process_slide_tray_warning(self, warning_string: str, isBuzzer: bool = True):
        self.setTrayWarning(warning_string, isBuzzer)
        if isBuzzer:
            count = 0
            while self.waitForBuzzerOFF():
                if self.status.waitForExitRunning():
                    self.clearWarning()
                    break
                AppTimeLoop.processEvents(self.system.WarningWaitTimes())
                self.devices.SlotStatusTimerTimeOut()
                count += 1
                if count >= 20:
                    count = 0
                    self.setTrayWarning(warning_string, isBuzzer)
        self.clearWarning()

    def waitForBuzzerOFF(self, waittimes: int = 30000) -> bool:
        isBuzzer: int = 0
        isWrong: int
        _waittimes: int = max(30000, waittimes)
        endtime: Qt.QDateTime = Qt.QDateTime.currentDateTime().addMSecs(_waittimes)
        while True:
            if Qt.QDateTime.currentDateTime() > endtime:
                break
            if self.system.isBuzzerMode and self.hasDetection:
                isBuzzer = self.detection.get_buzzer_switch()
            else:
                isBuzzer = self.status.isPause
            if not isBuzzer:
                break
            AppTimeLoop.processEvents(self.system.WarningWaitTimes())
            self.devices.SlotStatusTimerTimeOut()

        return bool(isBuzzer)

    def waitForCloseTheDoor(self, waittimes: int = 30000) -> bool:
        isWrong: int
        _waittimes: int = max(30000, waittimes)
        isCloseTheDoor: bool = self.isCloseTheDoor()
        message_string: str = "仪器门已经打开 暂停机械臂运行"
        if self.system.isEnglishMode:
            message_string = 'The instrument door is now open; robotic arm operation has been suspended'
        if not isCloseTheDoor:
            if self.status.isCloseTheDoor() != isCloseTheDoor:
                self.sendMessage(message_string)
                self.status.setPause(True)
                while self.status.isPause:
                    AppTimeLoop.processEvents(self.system.WarningWaitTimes())
                    self.devices.SlotStatusTimerTimeOut()
                    isCloseTheDoor = self.isCloseTheDoor()
        self.status.setDoorAvailable(isCloseTheDoor)

        return bool(isCloseTheDoor)

    def waitForCheckChamberBox(self) -> int:
        isWrong: int = RECODE_FAILURE
        if not self.hasAxisH or not self.hasMicroscope:
            return isWrong
        from AppCore.DBModels import ChamberConfigModel, ObjectiveModel
        x: float
        y: float
        z: float
        objective: int = ObjectiveLevel.Objective1
        x, y, z = ChamberConfigModel.getCheckPosition_xyz()
        Objective: ObjectiveModel = ObjectiveModel.getConfig(objective)
        self.microscope.init_z_range()
        self.microscope.set_z_speed(Objective.Default_Speed)
        self.microscope.waitmove_z(z)
        isWrong = self.axis_h.wait_force_quit()
        if RECODE_SUCCEED != isWrong:
            return isWrong
        isWrong = self.axis_h.wait_check_chamber_box()
        return isWrong

    def isCloseTheDoor(self) -> bool:
        isCloseTheDoor: bool = True
        if self.hasDetection:
            isCloseTheDoor = self.detection.is_close_the_door()
        return isCloseTheDoor


    def startOilDripping(self, speed: int) -> int:
        """设置油泵速度"""
        isWrong: int = RECODE_FAILURE
        if self.hasDetection:
            try:
                isWrong = self.detection.oil_switch(False)
                self.detection.set_oil_speed(max(10, int(speed)))
            except Exception as e:
                AppUtils.print_Exception(e)
                isWrong = RECODE_FAILURE
        return isWrong


    def oilDripping(self, waittimes: int, finish_waittimes: int):
        """油泵滴油 等待一定时长后停止 等待一定时长"""
        from AppLog.logHelper import logSCANNING
        """最长时间为20秒"""
        isWrong: int = RECODE_FAILURE
        if not self.hasDetection:
            return isWrong
        _status: bool = self.detection.get_oil_status()
        _max_waittimes: int = 200000
        _waittimes: int = min(max(100, abs(waittimes)), _max_waittimes)
        _delay: int = 100
        endtime: Qt.QDateTime = Qt.QDateTime.currentDateTime().addMSecs(_max_waittimes)
        while True:
            isWrong = self.detection.oil_switch(True)
            logSCANNING << "打开油泵状态"
            if RECODE_SUCCEED == isWrong:
                AppTimeLoop.processEvents(5)
                if self.detection.get_oil_switch():
                    break
            if Qt.QDateTime.currentDateTime() > endtime:
                break
        _status = self.detection.get_oil_status()
        logSCANNING << f"油管状态:{_status} {_waittimes}"
        if isWrong == RECODE_SUCCEED:
            endtime = Qt.QDateTime.currentDateTime().addMSecs(_waittimes)
            while _waittimes >= 0:
                _status = self.detection.get_oil_status()
                logSCANNING << f"油管状态:{_status} {_waittimes}"
                _waittimes -= _delay
                if Qt.QDateTime.currentDateTime() > endtime:
                    break
                AppTimeLoop.processEvents(_delay)

        endtime = Qt.QDateTime.currentDateTime().addMSecs(_max_waittimes)
        while True:
            isWrong = self.detection.oil_switch(False)
            logSCANNING << "打开油泵状态"
            if RECODE_SUCCEED == isWrong:
                AppTimeLoop.processEvents(5)
                if not self.detection.get_oil_switch():
                    break
            if Qt.QDateTime.currentDateTime() > endtime:
                break


        _finish_waittimes: int = min(max(100, abs(finish_waittimes)), _max_waittimes)
        endtime = Qt.QDateTime.currentDateTime().addMSecs(_finish_waittimes)
        while _finish_waittimes >= 0:
            if Qt.QDateTime.currentDateTime() > endtime:
                break
            _finish_waittimes -= _delay
            AppTimeLoop.processEvents(_delay)
        logSCANNING << f"等待时长:{_finish_waittimes}"
        """打开油泵 等待一定时长后关闭油泵  然后判断油管传感器状态 """
        _status = self.detection.get_oil_status()
        logSCANNING << f"油管状态:{_status} {_waittimes}"
        warning_string: str = "油路出错 请检查油瓶"
        if self.system.isEnglishMode:
            warning_string = 'Oil circuit malfunction detected. Please inspect the mirror oil reservoir'
        if not _status or RECODE_SUCCEED != isWrong:
            self.process_scanning_warning(warning_string)
            while True:
                if self.status.waitForExitRunning():
                    self.clearWarning()
                    break
                AppTimeLoop.processEvents(self.system.WarningWaitTimes())
                self.devices.SlotStatusTimerTimeOut()
                _status = self.detection.get_oil_status()
                logSCANNING << f"油管状态:{_status} {_waittimes}"
                if _status:
                    self.clearWarning()
                    break
                self.process_scanning_warning(warning_string)
            self.clearWarning()
            isWrong = RECODE_SUCCEED

        return isWrong


    def isCellScan(self, chamber_number: int, row_number: int) -> int:
        """如果是微核 则不需要高倍扫描"""
        classifier: str = self.getChamberSlideClassifier(chamber_number, row_number, False)
        slide: ChamberStatusModel = ChamberStatusModel.getChamberSlide(chamber_number,row_number)
        from AppLog.logHelper import logSCANNING
        message: str
        if self.isMicronucleus(classifier):
            return RECODE_FAILURE
        if self.status.currentScanStatus == ScanStatusLevel.FocusingWarning_Status:
            return RECODE_FAILURE
        if self.status.isJumpScanning:
            return RECODE_FAILURE
        if self.status.currentScanStatus != ScanStatusLevel.LowScanning_Status:
            return RECODE_FAILURE
        """获取所有核型小图的点"""
        CellArrays: list[CellModel] = CellModel.all()
        CellCount: int = len(CellArrays) if isinstance(CellArrays, list) else 0
        message = f'{chamber_number}号片仓{row_number}行玻片{slide.CodeString}识别细胞数是为{CellCount} 不进行高倍物镜扫描'
        if self.system.isEnglishMode:
            message = f'Slide boxs {chamber_number}, Row {row_number}, SpecimenNo: {slide.CodeString} The number of identified cells is {CellCount}, so high-power objective scanning is not performed.'
        """如果核型数量为空"""
        if CellCount <= 0:
            self.sendMessage(message)
            """保存样本信息"""
            self.eventBus.SaveImage(chamber_number, row_number)
            self.status.changedChamberScanningStatus(chamber_number,row_number, ScanStatusLevel.CellEmpty_Status)
            return RECODE_FAILURE
        """如果不能找到模板 则直接退出"""
        template, Preview, Collect = self.status.getSlideScanTemplate(chamber_number, row_number)
        if template is None or Preview is None or Collect is None:
            return RECODE_FAILURE
        if Preview.has_warning_value and Preview.has_is_warning_scan:
            """如果预警值 <= 0 说明可以扫描"""
            if Preview.warning_value <= 0:
                return RECODE_SUCCEED
            """如果核型数量小于预设的最小数量"""
            if CellCount < Preview.warning_value:
                """如果低于预警值扫描"""
                if Preview.is_warning_scan or Collect.cell_count <= 0:
                    return RECODE_SUCCEED
                self.sendMessage(message)
                """保存样本信息"""
                self.eventBus.SaveImage(chamber_number, row_number)
                return RECODE_FAILURE
        return RECODE_SUCCEED


    def isFocusingCellAvailable(self, model: SlideModelInterface) -> bool:
        CellAvailable: bool = False
        CellThreshold           : int
        MinCellCount            : int
        FocusingThreshold       : int
        FocusCompleteCount      : int
        MaxImageCount           : int
        MinContourArea          : int
        FocusingColorThreshold  : int
        image                   : np.ndarray
        try:
            if model.hasImageSource:
                image = model.toImage()
            else:
                return CellAvailable
            if model.hasFocusing:
                CellThreshold           = model.Focusing.CellThreshold             #
                MinCellCount            = model.Focusing.MinCellCount              #
                MinContourArea          = model.Focusing.MinContourArea            #
                FocusingColorThreshold  = model.Focusing.FocusingColorThreshold    #
            else:
                CellThreshold, MinCellCount, FocusingThreshold, FocusingColorThreshold, FocusCompleteCount, MaxImageCount, MinContourArea = FocusingConfigModel.getFocusingConfig(model.ObjectiveLevel, model.Level)
            from AppLog.logHelper import logSCANNING
            if ScanStatusLevel.isHigFocusing(model.Level):
                CellCount = FocusingUtil.get_cell_count(image, CellThreshold, MinContourArea)
                logSCANNING << f"细胞数量: {CellCount} 数量阀值: {MinCellCount}"
            else:
                Blurred_CellCount: int = FocusingUtil.get_cell_count_Blurred(image, CellThreshold, MinContourArea)
                if Blurred_CellCount > 0:
                    CellCount = FocusingUtil.get_cell_count(image, CellThreshold, MinContourArea)
                else:
                    CellCount = Blurred_CellCount
                logSCANNING << f"细胞数量: {CellCount} 数量阀值: {MinCellCount} {Blurred_CellCount}"
            CellAvailable = CellCount >= MinCellCount
        except Exception as e:
            AppUtils.print_Exception(e)
            CellAvailable = False
        return CellAvailable



    def CompleteFocusingModel(self, model: SlideModelInterface):
        self.waitForFocusingEmpty()
        if isinstance(model, SlideModelInterface) and model.hasImageSource:
            image: np.ndarray = model.toImage()
            if HeadEndShowMode.get('DEBUG_SHOW', False):
                self.uievent.SendEvent(image.copy())
            try:
                if self.hasWebEvent:
                    if model.hasPreview and model.preview.isMicronucleus():
                        self.webevent.SendEvent(Response.MPreviewImage(buffer=image.copy()))
                    else:
                        self.webevent.SendEvent(Response.PreviewImage(buffer=image.copy()))
            except Exception as e:
                AppUtils.print_Exception(e)
            AppTimeLoop.processGlobalEvents(500)

    def SendFocusingImage(self, image: np.ndarray, isMicronucleus: bool, model: SlideModelInterface = None):
        try:
            if HeadEndShowMode.get('DEBUG_SHOW', False):
                self.uievent.SendEvent(ImageEvent.instance(image=image.copy()))
            if model is not None:
                self.webevent.SendEvent(Request.FocusingInstance(**model.to_field()))
            if isMicronucleus:
                self.webevent.SendEvent(Response.MPreviewImage(buffer=image.copy()))
                self.webevent.SendEvent(Response.MVideoStream(buffer=image.copy()))
            else:
                self.webevent.SendEvent(Response.PreviewImage(buffer=image.copy()))
                self.webevent.SendEvent(Response.VideoStream(buffer=image.copy()))
        except Exception as e:
            AppUtils.print_Exception(e)
        # AppTimeLoop.processGlobalEvents(500)

    def waitForEmpty(self, waittimes: int = None):
        """等待线程数据全部执行完成"""
        try:
            if HeadEndShowMode.get('DEBUG_SHOW', False):
                self.uievent.waitForEmpty()
            self.focusingevent.waitForEmpty()
            if self.ScanLevel == ScanStatusLevel.LowScanning_Status:
                self.scanningevent.waitForEmpty()

        except Exception as e:
            AppUtils.print_Exception(e)
        if isinstance(waittimes, int):
            AppTimeLoop.processGlobalEvents(waittimes)

    def waitForFocusingEmpty(self, waittimes: int = None):
        """等待定焦线程数据全部执行完成"""
        try:
            if HeadEndShowMode.get('DEBUG_SHOW', False):
                self.uievent.waitForEmpty()
            self.camerafocusingevent.waitForEmpty()
            self.focusingevent      .waitForEmpty()
        except Exception as e:
            AppUtils.print_Exception(e)
        if isinstance(waittimes, int):
            AppTimeLoop.processGlobalEvents(waittimes)


    def waitForScanningEmpty(self, waittimes: int = None):
        """等待快扫线程数据全部执行完成"""
        try:
            if HeadEndShowMode.get('DEBUG_SHOW', False):
                self.uievent  .waitForEmpty()
            self.camerafocusingevent.waitForEmpty()
            self.focusingevent      .waitForEmpty()
            self.camerascanningevent.waitForEmpty()
            self.scanningevent      .waitForEmpty()
        except Exception as e:
            AppUtils.print_Exception(e)
        if isinstance(waittimes, int):
            AppTimeLoop.processGlobalEvents(waittimes)

    def process_pick_warning(self) -> int:
        """处理取片故障动作"""
        isWrong: int = RECODE_FAILURE
        self.axis_h.set_h_force_quit()
        """循环等待托盘移动到位"""
        count: int = 5
        while count < 5:
            tray_place_status: bool = self.axis_h.get_tray_place_status()
            tray_back_limit_status: bool = self.axis_h.get_back_limit_status()
            if tray_place_status or tray_back_limit_status:
                isWrong = RECODE_SUCCEED
            else:
                isWrong = self.axis_h.waitmove_to_back()
                if RECODE_SUCCEED != isWrong:
                    self.axis_h.reset_hook()
            count += 1
        return isWrong

    def process_drop_warning(self) -> int:
        """处理放片故障动作"""
        isWrong: int = RECODE_FAILURE
        self.axis_h.set_h_force_quit()
        """循环等待托盘移动到位"""
        count: int = 5
        while count < 5:
            tray_front_limit_status: bool = self.axis_h.get_front_limit_status()
            if tray_front_limit_status:
                isWrong = RECODE_SUCCEED
            else:
                isWrong = self.axis_h.waitmove_to_front()
                if RECODE_SUCCEED != isWrong:
                    self.axis_h.reset_hook()
            count += 1
        return isWrong
    """##############################################################################################################"""

    def waitForHome_xy_microscope(self):
        isWrong: int = RECODE_FAILURE
        if not self.hasMicroscope:
            return isWrong
        isWrong = self.microscope.waithome()
        if RECODE_SUCCEED != isWrong:
            return isWrong
        if not self.hasAxisX or not self.hasAxisY:
            return RECODE_FAILURE
        isWrong = self.manipulator.waithome_xy()
        return isWrong


    def waitForHome_z(self):
        isWrong: int = RECODE_FAILURE
        if self.hasAxisZ:
            isWrong = self.axis_z.waitHome()
        return isWrong


    def ChamberCheckTray(self, chamber_number: int, **args) -> int:
        isWrong: int = RECODE_FAILURE
        self.initCheckBusiness()
        warning_string: str = f'检测片仓{chamber_number}号托盘错误'
        if self.hasCheckBusiness:
            isWrong = self.checkbusiness.WaitDone(chamber_number=chamber_number)
        else:
            warning_string = '检测片仓初始化错误'
        if RECODE_SUCCEED != isWrong:
            self.waitForWarning(warning_string)
        return isWrong


    def ChamberCheck(self, **args) -> int:
        isWrong: int = RECODE_FAILURE
        self.initCheckBusiness()
        warning_string: str = '检测片仓错误'
        if self.hasCheckBusiness:
            isWrong = self.checkbusiness.WaitDone()
        else:
            warning_string = '检测片仓初始化错误'
        if RECODE_SUCCEED != isWrong:
            self.waitForWarning(warning_string)
        return isWrong


    def ChamberToSlideTable(self, chamber_number: int, isExit: bool = True, **args) -> int:
        isWrong: int = RECODE_FAILURE
        self.initPickBusiness()
        warning_string: str = f'取片仓{chamber_number}号托盘到载玻台错误'
        if self.system.isEnglishMode:
            warning_string = f'Retrieval error for slide box {chamber_number}'
        if self.hasPickBusiness:
            isWrong = self.pickbusiness.WaitDone(chamber_number=chamber_number, isExit=isExit, **args)
        else:
            warning_string = f'取片流程初始化错误'
            if self.system.isEnglishMode:
                warning_string = f'Initialization error in the slide box retrieval process'
        if RECODE_SUCCEED != isWrong:
            self.process_scanning_warning(warning_string, True)
        return isWrong


    def SlideTableToChamber(self, chamber_number: int, isExit: bool = True, **args) -> int:
        isWrong: int = RECODE_FAILURE
        self.initDropBusiness()
        warning_string: str = f'放{chamber_number}号托盘到片仓错误'
        if self.system.isEnglishMode:
            warning_string = f'Error in loading into slide box {chamber_number}'
        if self.hasDropBusiness:
            isWrong = self.dropbusiness.WaitDone(chamber_number=chamber_number, isExit=isExit, **args)
        else:
            warning_string = f'初始化片仓放片流程错误'
            if self.system.isEnglishMode:
                warning_string = 'Initialization error in the slide box loading procedure'
        if RECODE_SUCCEED != isWrong:
            self.waitForWarning(warning_string)
        return isWrong


    def waitForWarning(self, warning_string: str, **args):
        self.sendWarning(warning_string)
        count = 0
        while self.waitForBuzzerOFF():
            AppTimeLoop.processEvents(self.system.WarningWaitTimes())
            count += 1
            if count % 10 == 0:
                count = 0
                self.setWarning(warning_string)
        return


    def StartFocusing(self, slide: SlideFocusingModel, Objective: ObjectiveModel, focusing_status: int, isMono: bool = True, isGrabbing: bool = True, isShowFocusing: bool = True):
        isWrong                 : int                   = RECODE_FAILURE
        objective               : int                   = Objective.Level
        Focusing                : FocusingConfigModel   = FocusingConfigModel.getConfig(objective, focusing_status)
        focusing_lower_limit    : int                   = Objective.Focus_Lower_Limit
        focusing_upper_limit    : int                   = Objective.Focus_Upper_Limit
        focusing_length         : int                   = int(Focusing.FocusingRange)
        focusing_z_speed        : int                   = int(Focusing.FocusingSpeed)
        focusing_b_z            : int                   = min(focusing_upper_limit, max(focusing_lower_limit, int(slide.Position_Z) - focusing_length))
        focusing_e_z            : int                   = min(focusing_upper_limit, max(focusing_lower_limit, int(slide.Position_Z) + focusing_length))
        classifier              = self.getFocusingClassifier(slide)
        """请空当前焦点缓存"""
        self.focusingevent.StartFocusing(isShowFocusing)
        """改变系统状态"""
        self.status.init_focusing_status()
        """设置移动速度"""
        self.microscope.set_z_speed(Objective.Default_Speed)
        """设置移动模式"""
        if self.system.isLeiCaMicroscope():
            self.microscope.set_z_move_mode(True)
        """清除Z轴范围"""
        isWrong = self.microscope.wait_init_z_range()
        if RECODE_SUCCEED != isWrong:
            return RECODE_FAILURE, focusing_b_z, focusing_e_z, None
        isWrong = self.microscope.waitmove_z(focusing_b_z)
        if RECODE_SUCCEED != isWrong:
            return RECODE_FAILURE, focusing_b_z, focusing_e_z, None
        if self.system.isLeiCaMicroscope():
            if ScanStatusLevel.isHigFocusing(focusing_status) or self.isMicronucleus(classifier):
                self.microscope.set_z_move_mode(False)
            else:
                self.microscope.set_z_move_mode(True)
        """设置定焦范围"""
        self.microscope.set_z_range(min(focusing_b_z, focusing_e_z), max(focusing_b_z, focusing_e_z))
        self.focusingevent.FocusingCompleteConnect(self.SlotFocusingComplete)
        isWrong, focusing_model = self.RangeClassifierFocusing(slide, Objective, focusing_b_z, focusing_e_z, focusing_z_speed, focusing_status, classifier, isGrabbing)
        self.focusingevent.StopFocusing()
        """设置移动速度"""
        self.microscope.set_z_speed(Objective.Default_Speed)
        """移动到Z轴起始定焦位置"""
        if isinstance(focusing_model, SlideModelInterface) and focusing_model.ImageScore > 0:
            self.microscope.waitmove_z(focusing_model.Position_Z)
        else:
            self.microscope.waitmove_z(focusing_b_z)
        return isWrong, focusing_b_z, focusing_e_z, focusing_model





    def StartClassifierFocusing(self, slide: SlideFocusingModel, Objective: ObjectiveModel, focusing_status: int, classifier: str = 'Aberration', isGrabbing: bool = True, isShowFocusing: bool = True):
        isWrong                 : int = RECODE_FAILURE
        objective               : int = Objective.Level
        focusing_model          : SlideFocusingModel = None
        isUpWard                : int = 0
        Focusing                : FocusingConfigModel = FocusingConfigModel.getConfig(objective, focusing_status)
        focusing_lower_limit    : int = Objective.Focus_Lower_Limit
        focusing_upper_limit    : int = Objective.Focus_Upper_Limit
        focusing_length         : int = int(Focusing.FocusingRange)
        focusing_z_speed        : int = int(Focusing.FocusingSpeed)
        focusing_b_z            : int = min(focusing_upper_limit, max(focusing_lower_limit, int(slide.Position_Z) - focusing_length))
        focusing_e_z            : int = min(focusing_upper_limit, max(focusing_lower_limit, int(slide.Position_Z) + focusing_length))
        self.microscope.stop_z()
        """请空当前焦点缓存"""
        self.focusingevent.StartFocusing(isShowFocusing)
        """改变系统状态"""
        self.status.init_focusing_status()
        """设置移动速度"""
        self.microscope.set_z_speed(Objective.Default_Speed)
        """设置移动模式"""
        if self.system.isLeiCaMicroscope():
            self.microscope.set_z_move_mode(True)
        """清除Z轴范围"""
        isWrong = self.microscope.wait_init_z_range()
        if RECODE_SUCCEED != isWrong:
            return RECODE_FAILURE, focusing_b_z, focusing_e_z, None
        isWrong = self.microscope.waitmove_z(focusing_b_z)
        if RECODE_SUCCEED != isWrong:
            return RECODE_FAILURE, focusing_b_z, focusing_e_z, None
        if self.system.isLeiCaMicroscope():
            if ScanStatusLevel.isHigFocusing(focusing_status) or self.isMicronucleus(classifier):
                self.microscope.set_z_move_mode(False)
            else:
                self.microscope.set_z_move_mode(True)
        """设置定焦范围"""
        self.microscope.set_z_range(min(focusing_b_z, focusing_e_z), max(focusing_b_z, focusing_e_z))
        self.focusingevent.FocusingCompleteConnect(self.SlotFocusingComplete)
        isWrong, focusing_model = self.RangeClassifierFocusing(slide, Objective, focusing_b_z, focusing_e_z, focusing_z_speed, focusing_status, classifier, isGrabbing)
        isUpWard = self.focusingevent.isUpWard()
        self.focusingevent.StopFocusing()
        """设置移动速度"""
        self.microscope.set_z_speed(Objective.Default_Speed)
        """移动到Z轴起始定焦位置"""
        if isinstance(focusing_model, SlideModelInterface) and focusing_model.ImageScore > 0:
            self.microscope.waitmove_z(focusing_model.Position_Z)
        else:
            self.microscope.waitmove_z(focusing_b_z)

        return isWrong, focusing_b_z, focusing_e_z, focusing_model, isUpWard






    def StartCellFocusing(self, slide: SlideFocusingModel, Objective: ObjectiveModel, focusing_status: int, isMono: bool = True, isGrabbing: bool = True, isShowFocusing: bool = True):
        focusing_model      : SlideFocusingModel
        Focusing            : FocusingConfigModel
        isWrong             : int = RECODE_FAILURE
        focusing_length     : int
        focusing_z_speed    : int
        focusing_b_z        : int
        focusing_e_z        : int
        objective           : int
        focusing_lower_limit: int
        focusing_upper_limit: int
        focusing_offset     : int
        objective               = Objective.Level
        focusing_lower_limit    = Objective.Focus_Lower_Limit
        focusing_upper_limit    = Objective.Focus_Upper_Limit
        Focusing                = FocusingConfigModel.getConfig(objective, focusing_status)
        focusing_length         = int(Focusing.FocusingRange)
        focusing_z_speed        = int(Focusing.FocusingSpeed)
        focusing_offset         = int(Focusing.FocusingOffset)
        focusing_b_z            = min(focusing_upper_limit, max(focusing_lower_limit, int(slide.Position_Z) - focusing_length + focusing_offset     ))
        focusing_e_z            = min(focusing_upper_limit, max(focusing_lower_limit, int(slide.Position_Z) + focusing_length + abs(focusing_offset)))
        classifier = self.getFocusingClassifier(slide)
        self.microscope.stop_z()
        """请空当前焦点缓存"""
        self.focusingevent.StartFocusing(isShowFocusing)
        """改变系统状态"""
        self.status.init_focusing_status()
        """设置移动速度"""
        self.microscope.set_z_speed(Objective.Default_Speed)
        """设置移动模式"""
        if self.system.isLeiCaMicroscope():
            self.microscope.set_z_move_mode(True)
        """清除Z轴范围"""
        isWrong = self.microscope.wait_init_z_range()
        if RECODE_SUCCEED != isWrong:
            return RECODE_FAILURE, focusing_b_z, focusing_e_z, None
        isWrong = self.microscope.waitmove_z(focusing_b_z)
        if RECODE_SUCCEED != isWrong:
            return RECODE_FAILURE, focusing_b_z, focusing_e_z, None
        if self.system.isLeiCaMicroscope():
            if ScanStatusLevel.isHigFocusing(focusing_status) or self.isMicronucleus(classifier):
                self.microscope.set_z_move_mode(False)
            else:
                self.microscope.set_z_move_mode(True)
        """设置定焦范围"""
        self.microscope.set_z_range(min(focusing_b_z, focusing_e_z), max(focusing_b_z, focusing_e_z))
        self.focusingevent.FocusingCompleteConnect(self.SlotFocusingComplete)
        isWrong, focusing_model = self.RangeClassifierFocusing(slide, Objective, focusing_b_z, focusing_e_z, focusing_z_speed,  focusing_status, classifier, isGrabbing)
        self.focusingevent.StopFocusing(isShowFocusing)
        """设置移动速度"""
        self.microscope.set_z_speed(Objective.Default_Speed)
        """移动到Z轴起始定焦位置"""
        if isinstance(focusing_model, SlideModelInterface) and focusing_model.ImageScore > 0:
            self.microscope.waitmove_z(focusing_model.Position_Z)
        else:
            self.microscope.waitmove_z(focusing_b_z)
        return isWrong, focusing_b_z, focusing_e_z, focusing_model



        pass

    def StartCellClassifierFocusing(self, slide: SlideFocusingModel, Objective: ObjectiveModel, focusing_status: int, classifier: str = 'Aberration', isGrabbing: bool = True, isShowFocusing: bool = True):
        focusing_model      : SlideFocusingModel
        Focusing            : FocusingConfigModel
        isWrong             : int = RECODE_FAILURE
        focusing_length     : int
        focusing_z_speed    : int
        focusing_b_z        : int
        focusing_e_z        : int
        focusing_move_mode  : int
        objective           : int
        focusing_lower_limit: int
        focusing_upper_limit: int
        focusing_offset     : int
        objective               = Objective.Level
        focusing_lower_limit    = Objective.Focus_Lower_Limit
        focusing_upper_limit    = Objective.Focus_Upper_Limit
        Focusing                = FocusingConfigModel.getConfig(objective, focusing_status)
        focusing_length         = int(Focusing.FocusingRange)
        focusing_z_speed        = int(Focusing.FocusingSpeed)
        focusing_offset         = int(Focusing.FocusingOffset)
        focusing_b_z            = min(focusing_upper_limit, max(focusing_lower_limit, int(slide.Position_Z) - focusing_length + focusing_offset))
        focusing_e_z            = min(focusing_upper_limit, max(focusing_lower_limit, int(slide.Position_Z) + focusing_length + focusing_offset))
        self.microscope.stop_z()
        """请空当前焦点缓存"""
        self.focusingevent.StartFocusing(isShowFocusing)
        """改变系统状态"""
        self.status.init_focusing_status()
        """设置移动速度"""
        self.microscope.set_z_speed(Objective.Default_Speed)
        """设置移动模式"""
        if self.system.isLeiCaMicroscope():
            self.microscope.set_z_move_mode(True)
        """清除Z轴范围"""
        isWrong = self.microscope.wait_init_z_range()
        if RECODE_SUCCEED != isWrong:
            return RECODE_FAILURE, focusing_b_z, focusing_e_z, None
        isWrong = self.microscope.waitmove_z(focusing_b_z)
        if RECODE_SUCCEED != isWrong:
            return RECODE_FAILURE, focusing_b_z, focusing_e_z, None
        if self.system.isLeiCaMicroscope():
            if ScanStatusLevel.isHigFocusing(focusing_status) or self.isMicronucleus(classifier):
                self.microscope.set_z_move_mode(False)
            else:
                self.microscope.set_z_move_mode(True)
        """设置定焦范围"""
        self.microscope.set_z_range(min(focusing_b_z, focusing_e_z), max(focusing_b_z, focusing_e_z))
        self.focusingevent.FocusingCompleteConnect(self.SlotFocusingComplete)
        isWrong, focusing_model = self.RangeClassifierFocusing(slide, Objective, focusing_b_z, focusing_e_z, focusing_z_speed,  focusing_status, classifier, isGrabbing)
        self.focusingevent.StopFocusing(isShowFocusing)
        """设置移动速度"""
        self.microscope.set_z_speed(Objective.Default_Speed)
        """移动到Z轴起始定焦位置"""
        if isinstance(focusing_model, SlideModelInterface) and focusing_model.ImageScore > 0:
            self.microscope.waitmove_z(focusing_model.Position_Z)
        else:
            self.microscope.waitmove_z(focusing_b_z)
        return isWrong, focusing_b_z, focusing_e_z, focusing_model








    def StartCustomClassifierFocusing(self, slide: SlideModelInterface, Objective: ObjectiveModel, b_z: int, e_z: int, focusing_z_speed: int, focusing_status: int, classifier: str = 'Aberration', isGrabbing: bool = True, isShowFocusing: bool = True) -> (int, SlideModelInterface):
        isWrong                 : int = RECODE_FAILURE
        focusing_model          : SlideFocusingModel
        isUpWard                : int = 0
        focusing_lower_limit    : int = Objective.Focus_Lower_Limit
        focusing_upper_limit    : int = Objective.Focus_Upper_Limit
        focusing_b_z            : int = min(focusing_upper_limit, max(focusing_lower_limit, b_z))
        focusing_e_z            : int = min(focusing_upper_limit, max(focusing_lower_limit, e_z))
        self.microscope.stop_z()
        """请空当前焦点缓存"""
        self.focusingevent.StartFocusing(isShowFocusing)
        """改变系统状态"""
        self.status.init_focusing_status()
        """设置移动速度"""
        self.microscope.set_z_speed(Objective.Default_Speed)
        """设置移动模式"""
        if self.system.isLeiCaMicroscope():
            self.microscope.set_z_move_mode(True)
        """清除Z轴范围"""
        isWrong = self.microscope.wait_init_z_range()
        if RECODE_SUCCEED != isWrong:
            return RECODE_FAILURE, focusing_b_z, focusing_e_z, None
        isWrong = self.microscope.waitmove_z(focusing_b_z)
        if RECODE_SUCCEED != isWrong:
            return RECODE_FAILURE, focusing_b_z, focusing_e_z, None
        if self.system.isLeiCaMicroscope():
            if ScanStatusLevel.isHigFocusing(focusing_status) or self.isMicronucleus(classifier):
                self.microscope.set_z_move_mode(False)
            else:
                self.microscope.set_z_move_mode(True)
        """设置定焦范围"""
        self.microscope.set_z_range(min(focusing_b_z, focusing_e_z), max(focusing_b_z, focusing_e_z))
        self.focusingevent.FocusingCompleteConnect(self.SlotFocusingComplete)
        isFilter: bool = not ScanStatusLevel.isLowFirstFocusing(focusing_status)
        isWrong, focusing_model = self.RangeClassifierFocusing(slide, Objective, focusing_b_z, focusing_e_z, focusing_z_speed, focusing_status, classifier, isGrabbing, isFilter)
        isUpWard = self.focusingevent.isUpWard()
        self.focusingevent.StopFocusing()
        """设置移动速度"""
        self.microscope.set_z_speed(Objective.Default_Speed)
        """移动到Z轴起始定焦位置"""
        if isinstance(focusing_model, SlideModelInterface) and focusing_model.ImageScore > 0:
            self.microscope.waitmove_z(focusing_model.Position_Z)
        else:
            self.microscope.waitmove_z(focusing_b_z)
        return isWrong, focusing_b_z, focusing_e_z, focusing_model, isUpWard





    def StartClassifierScanFocusing(self, slide: SlideModelInterface, Objective: ObjectiveModel, focusing_status: int, classifier: str = 'Aberration', isShowFocusing: bool = True) -> (int, SlideModelInterface):
        isWrong                     : int                   = RECODE_FAILURE
        objective                   : int                   = Objective.Level
        focusing_model              : SlideFocusingModel    = None
        Focusing                    : FocusingConfigModel   = FocusingConfigModel.getConfig(objective, focusing_status)
        focusing_lower_limit        : int                   = Objective.Focus_Lower_Limit
        focusing_upper_limit        : int                   = Objective.Focus_Upper_Limit
        focusing_length             : int                   = int(Focusing.FocusingRange)
        focusing_b_z                : int                   = min(focusing_upper_limit, max(focusing_lower_limit, slide.Position_Z - focusing_length))
        focusing_e_z                : int                   = min(focusing_upper_limit, max(focusing_lower_limit, slide.Position_Z + focusing_length))
        focusing_z_speed            : int                   = Focusing.FocusingSpeed
        self.microscope.stop_z()
        """请空当前焦点缓存"""
        self.focusingevent.StartFocusing(isShowFocusing)

        """改变系统状态"""
        self.status.init_focusing_status()
        """设置移动速度"""
        self.microscope.set_z_speed(Objective.Default_Speed)
        """设置移动模式"""
        if self.system.isLeiCaMicroscope():
            self.microscope.set_z_move_mode(True)
        """清除Z轴范围"""
        isWrong = self.microscope.wait_init_z_range()
        if RECODE_SUCCEED != isWrong:
            return RECODE_FAILURE, focusing_b_z, focusing_e_z, None
        isWrong = self.microscope.waitmove_z(focusing_b_z)
        if RECODE_SUCCEED != isWrong:
            return RECODE_FAILURE, focusing_b_z, focusing_e_z, None
        if self.system.isLeiCaMicroscope():
            if ScanStatusLevel.isHigFocusing(focusing_status) or self.isMicronucleus(classifier):
                self.microscope.set_z_move_mode(False)
            else:
                self.microscope.set_z_move_mode(True)
        """设置定焦范围"""
        self.microscope.set_z_range(min(focusing_b_z, focusing_e_z), max(focusing_b_z, focusing_e_z))
        self.focusingevent.FocusingCompleteConnect(self.SlotFocusingComplete)
        isWrong, focusing_model = self.RangeClassifierFocusing(slide, Objective, min(focusing_b_z, focusing_e_z), max(focusing_b_z, focusing_e_z), focusing_z_speed, focusing_status, classifier, True)
        self.focusingevent.StopFocusing(isShowFocusing)
        """设置移动速度"""
        self.microscope.set_z_speed(Objective.Default_Speed)
        """移动到Z轴起始定焦位置"""
        if isinstance(focusing_model, SlideModelInterface) and focusing_model.ImageScore > 0:
            self.microscope.waitmove_z(focusing_model.Position_Z)
        else:
            self.microscope.waitmove_z(focusing_b_z)
        return isWrong, focusing_b_z, focusing_e_z, focusing_model





    def RangeClassifierFocusing(self, slide: SlideModelInterface, Objective: ObjectiveModel, focusing_b_z: int, focusing_e_z: int, focusing_z_speed: int, focusing_status: int, classifier: str = 'Aberration', isGrabbing: bool = True, isFilter: bool = True) -> (int, SlideModelInterface):
        """
        model               : SlideModelInterface  定焦数据源
        Objective           : ObjectiveModel       定焦物镜参数
        focusing_b_z        : int                  开始定焦位置
        focusing_e_z        : int                  结束定焦位置
        focusing_z_speed    : int                  定焦速度
        focusing_status     : int                  当前定焦状态
        """
        from AppLog.logHelper import logSCANNING
        focusing_model  : SlideFocusingModel
        item            : SlideFocusingModel
        index           : int = 1
        """开始Z轴定速定焦"""
        focusing_times: Qt.QDateTime = Qt.QDateTime.currentDateTime()
        logSCANNING << f"{AppConvert.QDateTimeToString(Qt.QDateTime.currentDateTime())}开始玻片定焦"
        """开始定焦"""
        isLeiCaMicroscope = self.system.isLeiCaMicroscope()
        rel_length: float = focusing_e_z - focusing_b_z
        if isLeiCaMicroscope:
            isWrong = self.microscope.POS_CONST_Z(focusing_z_speed, rel_length)
        else:
            self.microscope.set_z_speed(focusing_z_speed)
            isWrong = self.microscope.rel_move(rel_length, MTBCmdSetModes.Default)
        if RECODE_SUCCEED != isWrong:
            self.microscope.init_z_range()
            self.microscope.stop_z()
            return RECODE_FAILURE, None

        max_focusing_times: int = 60000
        endtime         : Qt.QDateTime = Qt.QDateTime.currentDateTime().addMSecs(max_focusing_times)
        while True:
            if isFilter:
                if self.status.focusing_status == ScanStatusLevel.FocusingFinish_Status:
                    self.microscope.stop_z()
                    break
            if isLeiCaMicroscope:
                isWrong, Moving, Lower, Upper, Limit, Focus = self.microscope.manager.get_z_status()
                if RECODE_SUCCEED == isWrong:
                    if isinstance(Moving, int) and Moving == 0:
                        break
                    if isinstance(Lower, int) and Lower:
                        break
                    if isinstance(Upper, int) and Upper:
                        break
                    if isinstance(Focus, int) and Focus:
                        break
            else:
                is_moving: bool = self.microscope.is_moving()
                if not is_moving:
                    break
            item = slide.copy()
            item.Level = focusing_status
            item.Index = index
            index += 1
            isWrong, position_z = self.microscope.get_position_z()
            """获取Z轴位置错误 重新移动到目标位置"""
            if RECODE_SUCCEED == isWrong:
                item.Position_Z = position_z
                self.camera.getFocusingNumpy(item=item, classifier=classifier)
                self.focusingevent.SendEvent(item)
            else:
                AppTimeLoop.processGlobalEvents(200)
            if Qt.QDateTime.currentDateTime() > endtime:
                break
            if isFilter:
                if self.status.focusing_status == ScanStatusLevel.FocusingFinish_Status:
                    break
        self.microscope.stop_z()
        self.focusingevent.FocusingCompleteDisconnect(self.SlotFocusingComplete)

        max_focusing_index, focusing_model = self.focusingevent.getMaxFocusingItem()
        if focusing_model is not None and max_focusing_index is None:
            if focusing_model.ImageScore <= 0:
                focusing_model = None
        isWrong = RECODE_SUCCEED if focusing_model is not None else RECODE_FAILURE
        info: str = f"{AppConvert.DateTimeToString(Qt.QDateTime.currentDateTime())}结束定焦 {focusing_times.msecsTo(Qt.QDateTime.currentDateTime())}ms"
        if isinstance(focusing_model, SlideModelInterface):
            info += f'\t焦点: {focusing_model.Position_Z} 评分: {focusing_model.ImageScore}'
        logSCANNING << info
        self.microscope.wait_init_z_range()
        return isWrong, focusing_model

    def start_z_moving(self, speed: int, max_waittimes: int = 300000) -> int:
        """开始Z轴定速定焦"""
        isWrong     : int
        waittimes   : int = max(55000, max_waittimes)
        begintimes  = Qt.QDateTime.currentDateTime().addMSecs(waittimes)
        self.microscope.stop_z()
        isWrong     = self.microscope.POS_CONST_Z(speed)
        while True:
            if RECODE_SUCCEED == isWrong:
                break
            AppTimeLoop.processGlobalEvents(200)
            self.microscope.stop_z()
            isWrong = self.microscope.POS_CONST_Z(speed)
            if Qt.QDateTime.currentDateTime() > begintimes:
                break
            self.process_scanning_status()
            if self.status.waitForExitRunning():
                self.microscope.stop_z()
                break
        return isWrong




    def waitForFocusing(self, z: (float, int), max_waittimes: int = 55000, reset_times: int = 5000) -> int:
        isWrong         : int = RECODE_FAILURE
        position_z      : int
        reset_waittimes : int = max(5000, reset_times)
        waittimes       : int = max(55000, max_waittimes)
        endtime         = Qt.QDateTime.currentDateTime().addMSecs(reset_waittimes)
        complete_time   = endtime.addMSecs(waittimes)
        isWrong         = self.microscope.waitmove_z(z)
        while True:
            if RECODE_SUCCEED == isWrong:
                break
            if Qt.QDateTime.currentDateTime() > endtime:
                break
            isWrong = self.microscope.waitmove_z(z)
            """处理停止和暂停"""
            while self.status.waitForPauseRunning():
                AppTimeLoop.processEvents(self.system.WarningWaitTimes())

            AppTimeLoop.processGlobalEvents(200)
        if RECODE_SUCCEED != isWrong:
            return isWrong
        endtime = Qt.QDateTime.currentDateTime().addMSecs(reset_waittimes)
        complete_time = endtime.addMSecs(waittimes)
        while True:
            isWrong, position_z = self.microscope.get_position_z()
            if RECODE_SUCCEED == isWrong and int(position_z) == int(z):
                break
            if Qt.QDateTime.currentDateTime() > endtime:
                self.microscope.waitmove_z(z)
            if Qt.QDateTime.currentDateTime() > complete_time:
                break
            self.process_scanning_status()
            AppTimeLoop.processGlobalEvents(200)

        return isWrong

    def waitForStartClassifierFocusing(self, slide: SlideModelInterface, classifier: str = 'Aberration', waittimes: int = 5000) -> int:
        maxwaittimes: int = max(500, waittimes) if isinstance(waittimes, int) else 1000
        item        : SlideModelInterface
        begintimes: Qt.QDateTime = Qt.QDateTime.currentDateTime().addMSecs(maxwaittimes)
        while True:
            """处理停止和暂停"""
            SCANNING_STATUS = self.process_scanning_status()
            if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
                break
            if Qt.QDateTime.currentDateTime() > begintimes:
                break
            item = slide.copy()
            isWrong, position_z = self.microscope.get_position_z()
            """获取Z轴位置错误 重新移动到目标位置"""
            if RECODE_SUCCEED == isWrong:
                item.Position_Z = position_z
                self.camera.getFocusingNumpy(item=item, classifier=classifier)
            AppTimeLoop.processGlobalEvents(500)
        return RECODE_SUCCEED


    def save_specimen(self, chamber_number: int, row_number: int, tray_number: int):
        self.microscope.stop_z()
        self.status.setSlideTableAlreadyScanned(tray_number)
        self.eventBus.SaveSpecimen(chamber_number, row_number)



    def CheckChamberSlide(self, chamber_number: int = None, isSafe: bool = False, isExit: bool = True, **args) -> int:
        isWrong: int = RECODE_FAILURE
        warning_string: str
        self.initCheckBusiness()
        if self.hasCheckBusiness:
            isWrong = self.checkbusiness.WaitDone(chamber_number=chamber_number, isSafe=isSafe, isExit=isExit, **args)
            warning_string = f'检测{chamber_number}号片仓玻片错误'
            if self.system.isEnglishMode:
                warning_string = f'Error in slide detection of box {chamber_number}'

        else:
            warning_string = f'初始化玻片检测流程错误'
            if self.system.isEnglishMode:
                warning_string = 'Error in initializing the slide detection process'

        if RECODE_SUCCEED != isWrong:
            self.process_scanning_warning(warning_string)
        return isWrong

    """玻片取片"""

    def PickChamberSlide(self, chamber_number: int, isSafe: bool = False, isExit: bool = True, **args) -> int:
        isWrong: int = RECODE_FAILURE
        self.initPickBusiness()
        warning_string: str
        if self.hasPickBusiness:
            isWrong = self.pickbusiness.WaitDone(chamber_number=chamber_number, isSafe=isSafe, isExit=isExit, **args)
            warning_string = f'取片仓{chamber_number}行托盘错误'
            if self.system.isEnglishMode:
                warning_string = f'Retrieval error for tray NO {chamber_number}'

        else:
            warning_string = f'初始化片仓取片流程错误'
            if self.system.isEnglishMode:
                warning_string = f'Initialization error in the slide box retrieval process'

        if RECODE_SUCCEED != isWrong:
            self.process_scanning_warning(warning_string)

        return isWrong

    """片仓放片"""

    def DropChamberSlide(self, chamber_number: int, isSafe: bool = False, isExit: bool = False, **args) -> int:
        isWrong: int = RECODE_FAILURE
        warning_string: str
        self.initDropBusiness()
        if self.hasDropBusiness:
            isWrong = self.dropbusiness.WaitDone(chamber_number=chamber_number, isSafe=isSafe, isExit=isExit)
            warning_string = f'放片仓{chamber_number}行托盘错误'
            if self.system.isEnglishMode:
                warning_string = f'Error in loading for tray NO {chamber_number}'

        else:
            warning_string = f'初始化片仓放片流程错误'
            if self.system.isEnglishMode:
                warning_string = 'Initialization error in the slide box loading procedure'

        if RECODE_SUCCEED != isWrong:
            self.process_scanning_warning(warning_string)
        return isWrong

    """玻片低倍物镜定焦"""

    def SlideLowFocusing(self, chamber_number: int, row_number: int, isSafe: bool = False, **args) -> int:
        isWrong: int = RECODE_FAILURE
        self.initFocusingBusiness()
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            return RECODE_SUCCEED
        warning_string: str = ''
        if self.hasFocusingBusiness:
            """玻片定焦"""
            isWrong = self.focusingbusiness.WaitDone(chamber_number=chamber_number, row_number=row_number, isSafe=isSafe, **args)
            SCANNING_STATUS = self.process_scanning_status()
            if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
                return RECODE_SUCCEED
            if RECODE_SUCCEED != isWrong:
                CodeString = ChamberStatusModel.getChamberCodeString(chamber_number, row_number)
                warning_string = f'{chamber_number}号片仓{row_number}行玻片{CodeString} 在{row_number}号载玻台低倍物镜定焦失败'
                if self.system.isEnglishMode:
                    warning_string = f'Slide box {chamber_number}, Row {row_number}, QRCode: {CodeString} The low-power objective focusing failure on Slide Table {tray_number}'
        else:
            warning_string = f'初始化定焦流程错误'

            if self.system.isEnglishMode:
                warning_string = 'Initialization of The low-power objective focusing process error'
        if RECODE_SUCCEED != isWrong:
            self.sendMessage(warning_string)
        return isWrong

    """玻片低倍物镜快扫"""

    def SlideLowScanning(self, chamber_number: int, row_number: int, isSafe: bool = False, **args) -> int:
        isWrong: int = RECODE_FAILURE
        self.initScanningBusiness()
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            return RECODE_SUCCEED
        warning_string: str = ''
        if self.hasScanningBusiness:
            """玻片定焦"""
            isWrong = self.scanningbusiness.WaitDone(chamber_number=chamber_number, row_number=row_number, isSafe=isSafe, **args)
            SCANNING_STATUS = self.process_scanning_status()
            if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
                return RECODE_SUCCEED
            if RECODE_SUCCEED != isWrong:
                CodeString = ChamberStatusModel.getChamberCodeString(chamber_number, row_number)
                warning_string = f'{chamber_number}号片仓{row_number}行玻片{CodeString} 在{row_number}号载玻台低倍物镜快扫失败'
                if self.system.isEnglishMode:
                    warning_string = f'Slide box {chamber_number}, Row {row_number}, Slide CodeString:{CodeString} Low-magnification objective rapid scanning failure on Slide Table {tray_number}'
        else:
            warning_string = f'初始化低倍物镜快扫流程错误'
            if self.system.isEnglishMode:
                warning_string = ' Low-magnification objective rapid scanning failure'
        if RECODE_SUCCEED != isWrong:
            self.sendMessage(warning_string)

        return isWrong

    """玻片滴油"""

    def SlideOilDropping(self, chamber_number: int, row_number: int, isSafe: bool = False, **args) -> int:
        isWrong: int = RECODE_FAILURE
        self.initOilingBusiness()
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            return RECODE_SUCCEED

        warning_string: str = ''
        if self.hasOilingBusiness:
            """玻片定焦"""
            isWrong = self.oilingbusiness.WaitDone(chamber_number=chamber_number, row_number=row_number, isSafe=False)
            SCANNING_STATUS = self.process_scanning_status()
            if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
                return RECODE_SUCCEED
            if RECODE_SUCCEED != isWrong:
                CodeString = ChamberStatusModel.getChamberCodeString(chamber_number, row_number)
                warning_string = f'{chamber_number}号片仓{row_number}行玻片{CodeString} 在{row_number}号载玻台滴油失败'
                if self.system.isEnglishMode:
                    warning_string = f'Slide boxs {chamber_number}, Row {row_number} Oil application failed on Slide Table {row_number}'
        else:
            warning_string = f'初始化滴油流程错误'
            if self.system.isEnglishMode:
                warning_string = 'Initialization of the oil dripping process has encountered an error'
        if RECODE_SUCCEED != isWrong:
            self.sendMessage(warning_string)
        return isWrong

    """玻片高倍扫描"""

    def SlideSampleCellFocusing(self, chamber_number: int, row_number: int, isSafe: bool = False, **args) -> int:
        isWrong: int = RECODE_FAILURE
        self.initCellFocusingBusiness()
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            return RECODE_SUCCEED
        warning_string: str = ''
        if self.hasCellFocusingBusiness:
            """玻片定焦"""
            isWrong = self.cellfocusingBusiness.WaitDone(chamber_number=chamber_number, row_number=row_number, isSafe=isSafe)
            SCANNING_STATUS = self.process_scanning_status()
            if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
                return RECODE_SUCCEED
            if RECODE_SUCCEED != isWrong:
                CodeString = ChamberStatusModel.getChamberCodeString(chamber_number, row_number)
                warning_string = f'片仓{chamber_number}号托盘 {row_number}号玻片{CodeString} 高倍物镜扫描失败'
                if self.system.isEnglishMode:
                    warning_string = f'slide boxs {chamber_number},  CodeString:{CodeString} The high-power objective scanning of failure on Slide Table {tray_number}'
        else:
            warning_string = f'初始化高倍物镜扫描流程错误'
            if self.system.isEnglishMode:
                warning_string = 'Initialization Error in High-Magnification Objective Lens Scanning Procedure'
        if RECODE_SUCCEED != isWrong:
            self.sendMessage(warning_string)
        return isWrong


    """底倍扫描玻片 """

    def LowScanningTraySlide(self, chamber_number: int, row_number: int, isSafe: bool = False, **args) -> int:
        isWrong: int = RECODE_FAILURE
        self.initFocusingBusiness()
        self.initScanningBusiness()
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            return RECODE_SUCCEED
        """玻片定焦"""
        if self.status.isJumpScanning:
            return RECODE_SUCCEED
        self.webevent.SlotClearImageListSignal('changedSlide', row_number)
        isWrong = self.SlideLowFocusing(chamber_number=chamber_number, row_number=row_number, isSafe=isSafe)
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            return RECODE_SUCCEED
        if RECODE_SUCCEED != isWrong or self.status.scanning_level != self.focusingbusiness.ScanLevel:
            """定焦错误 改变状态"""
            self.status.setScanningStatus(ScanStatusLevel.FocusingWarning_Status)
            self.status.changedChamberScanningStatus(chamber_number, row_number, ScanStatusLevel.FocusingWarning_Status)
            return RECODE_SUCCEED
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            return RECODE_SUCCEED
        isWrong = self.SlideLowScanning(chamber_number=chamber_number, row_number=row_number,isSafe=isSafe)
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            return RECODE_SUCCEED
        if RECODE_SUCCEED != isWrong or self.status.scanning_level != self.scanningbusiness.ScanLevel:
            """平扫错误 改变状态"""
            if self.status.ScanStatus == ScanStatusLevel.LowScanning_Status:
                self.status.setScanningStatus(ScanStatusLevel.ScanningWarning_Status)
                self.status.changedChamberScanningStatus(chamber_number, row_number, ScanStatusLevel.ScanningWarning_Status)

        return RECODE_SUCCEED

    """高倍扫描玻片 玻片滴油"""

    def HigScanningTraySlide(self, chamber_number: int, row_number: int, isSafe: bool = False, **args) -> int:
        self.webevent.SlotClearImageListSignal(row_number, row_number)
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            return RECODE_SUCCEED

        """玻片滴油"""
        isWrong = self.SlideOilDropping(chamber_number=chamber_number, row_number=row_number, isSafe=isSafe)

        if RECODE_SUCCEED != isWrong or self.status.scanning_level != self.oilingbusiness.ScanLevel:
            return RECODE_SUCCEED
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            return RECODE_SUCCEED
        """玻片百倍扫描"""

        isWrong = self.SlideSampleCellFocusing(chamber_number=chamber_number, row_number=row_number, isSafe=isSafe)

        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            return RECODE_SUCCEED
        if RECODE_SUCCEED != isWrong:
            if self.status.ScanStatus == self.cellfocusingBusiness.ScanLevel:
                self.status.setScanningStatus(ScanStatusLevel.HigFocusingWarning_Status)
                self.status.changedChamberScanningStatus(chamber_number, row_number, ScanStatusLevel.HigFocusingWarning_Status)
        return RECODE_SUCCEED

    """玻片扫描"""

    def waitForSlideScanning(self, chamber_number: int, row_number: int, isSafe: bool = False, **args) -> int:
        isWrong: int
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            return RECODE_SUCCEED
        self.algorithm.initDetector()
        isWrong = self.LowScanningTraySlide(chamber_number=chamber_number, row_number=row_number, isSafe=isSafe, **args)
        """处理跳过 暂停 退出业务"""
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            return RECODE_SUCCEED
        if RECODE_SUCCEED == isWrong:
            """判断是否可以高倍扫描"""
            isWrong = self.isCellScan(chamber_number=chamber_number, row_number=row_number)
            """处理跳过 暂停 退出业务"""
            SCANNING_STATUS = self.process_scanning_status()
            if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
                return RECODE_SUCCEED
            if RECODE_SUCCEED != isWrong:
                """清空扫描识别的核型数据"""
                CellModel.clear()
                self.status.setScanningStatus(ScanStatusLevel.CellEmpty_Status)
                self.status.changedChamberScanningStatus(chamber_number, row_number, ScanStatusLevel.CellEmpty_Status)
                return RECODE_SUCCEED
            self.algorithm.deleDetector()
            """高倍物镜扫描"""

            self.algorithm.initClassifier()
            self.cellfocusingevent.StartFocusing()
            isWrong = self.HigScanningTraySlide(chamber_number=chamber_number, row_number=row_number, isSafe=isSafe, **args)
            self.cellfocusingevent.StopFocusing()
            self.algorithm.deleClassifier()
            """清空扫描识别的核型数据"""
            CellModel.clear()
        """处理跳过 暂停 退出业务"""
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            return RECODE_SUCCEED
        return isWrong


    def waitForClearSlideTable(self):
        isTrayEmpty     : bool
        warning_string  : str = f'载玻台已经有托盘 请取走载玻台上的托盘'
        if self.system.isEnglishMode:
            warning_string = f'There is already a slide at position the slide table. Please remove the slide from the slide table'
        while True:
            isTrayEmpty = self.isTrayNotEmpty()
            if not isTrayEmpty:
                break
            self.status.setTrayStatus(isTrayEmpty)
            self.process_slide_tray_warning(warning_string, isTrayEmpty)
        self.clearWarning()

    def isTrayNotEmpty(self):
        tray_status = self.axis_h.get_tray_place_status()
        back_limit = self.axis_h.get_back_limit_status()
        last_limit = self.axis_h.get_front_limit_status()
        if not tray_status and back_limit:
            return False
        if not tray_status and last_limit:
            return False
        return True


    def waitForCheckChamber(self, chamber_number: int):
        """检测指定位置的托盘是否存在"""
        isWrong : int = RECODE_FAILURE
        _ChamberNumber: int = None
        self.axis_h.wait_force_quit(500)
        if isinstance(chamber_number, (int, float)):
            isWrong = self.axis_h.wait_check_tray(chamber_number)
            if RECODE_SUCCEED == isWrong:
                if not self.axis_h.get_layer_detector_status(chamber_number):
                    _ChamberNumber = chamber_number
        else:
            MinChamberNumber: int
            MaxChamberNumber: int
            MinChamberNumber, MaxChamberNumber = self.system.getChamberRange()
            for ChamberNumber in range(MinChamberNumber, MaxChamberNumber + 1):
                isWrong = self.axis_h.wait_check_tray(ChamberNumber)
                if RECODE_SUCCEED == isWrong:
                    if not self.axis_h.get_layer_detector_status(ChamberNumber):
                        _ChamberNumber = chamber_number
                        break
        return isWrong, _ChamberNumber

    def WaitChamberDropSlide(self, chamber_number: int):
        isWrong: int = RECODE_FAILURE
        ChamberNumber: int = None
        isTrayNotEmpty = self.isTrayNotEmpty()
        if not isTrayNotEmpty:
            return RECODE_SUCCEED

        """检测片仓盒"""
        isWrong = self.waitForCheckChamberBox()
        if RECODE_SUCCEED != isWrong:
            self.process_slide_tray_warning(f'片仓盒没有放入机器', RECODE_SUCCEED == isWrong)
            return isWrong

        """检测指定的行是否存在"""
        isWrong, ChamberNumber = self.waitForCheckChamber(chamber_number)
        if RECODE_SUCCEED != isWrong or not isinstance(ChamberNumber, (int, float)):
            self.process_slide_tray_warning(f'片仓{ChamberNumber}行有托盘', RECODE_SUCCEED == isWrong)
            return isWrong
        isWrong = self.SlideTableToChamber(chamber_number=ChamberNumber, isExit=False)
        if RECODE_SUCCEED == isWrong:
            isWrong = self.axis_h.wait_empty_hook_return()
        else:
            isWrong = self.axis_h.waitmove_to_back()

        if RECODE_SUCCEED == isWrong:
            self.clearWarning()
            return isWrong

        self.process_slide_tray_warning(f'托盘{ChamberNumber}放入片仓错误', RECODE_SUCCEED == isWrong)
        while True:
            isWrong = self.isTrayNotEmpty()
            if RECODE_SUCCEED == isWrong:
                break
            self.process_slide_tray_warning(f'托盘{ChamberNumber}放入片仓错误', RECODE_SUCCEED == isWrong)
            self.axis_h.waitmove_to_back()
        if RECODE_SUCCEED == isWrong:
            self.clearWarning()
        else:
            self.process_slide_tray_warning(f'托盘{ChamberNumber}放入片仓错误', RECODE_SUCCEED == isWrong)
        if RECODE_SUCCEED == isWrong:
            self.clearWarning()
        return isWrong

    def waitForSucceedPickAvailable(self, chamber_number: int) -> (int, int):
        isWrong             : int = RECODE_FAILURE
        MinRowNumber        : int
        MaxRowNumber        : int
        MaxChamberNumber    : int
        MinChamberNumber    : int
        ChamberNumber       : int
        _ChamberNumber      : int
        RowNumber           : int
        _RowNumber          : int
        MinChamberNumber    , MaxChamberNumber   = self.system.getChamberRange       ()
        MinRowNumber        , MaxRowNumber       = self.system.getRowRange           ()
        _ChamberNumber      = chamber_number

        for RowNumber in range(MinRowNumber, MaxRowNumber + 1):
            isWrong = self.status.isPickAvailable(chamber_number=_ChamberNumber, row_number=RowNumber)
            if RECODE_SUCCEED == isWrong:
                ChamberNumber = _ChamberNumber
                return RECODE_SUCCEED, ChamberNumber

        for ChamberNumber in range(chamber_number + 1, MaxChamberNumber + 1):
            for RowNumber in range(MinRowNumber, MaxRowNumber + 1):
                isWrong = self.status.isPickAvailable(chamber_number=ChamberNumber, row_number=RowNumber)
                if RECODE_SUCCEED == isWrong:
                    return isWrong, ChamberNumber
        return RECODE_FAILURE, MaxChamberNumber + 1

    def waitForSucceedSlideAvailable(self, chamber_number: int) -> (int, int):
        isWrong             : int = RECODE_FAILURE
        MinRowNumber        : int
        MaxRowNumber        : int
        MaxChamberNumber    : int
        MinChamberNumber    : int
        ChamberNumber       : int
        _ChamberNumber      : int
        RowNumber           : int
        _RowNumber          : int
        MinChamberNumber    , MaxChamberNumber   = self.system.getChamberRange       ()
        MinRowNumber        , MaxRowNumber       = self.system.getRowRange           ()
        _ChamberNumber      = chamber_number
        for RowNumber in range(MinRowNumber, MaxRowNumber + 1):
            isWrong = self.status.isPickAvailable(chamber_number=_ChamberNumber, row_number=RowNumber)
            if RECODE_SUCCEED == isWrong:
                ChamberNumber = _ChamberNumber
                return RECODE_SUCCEED, ChamberNumber
        return RECODE_FAILURE, MaxChamberNumber + 1


    def readyChamberScanning(self, isAutoScanning: bool = True) -> int:
        """扫描前准备工作"""
        isWrong: int = RECODE_FAILURE
        """实例化模块"""
        if not self.hasDevices:
            self.initModules()
        if not self.hasDevices:
            return isWrong
        self.devices.StopStatusTimer()
        if not self.hasMotion:
            self.initMotion()
        if not self.hasMotion:
            return isWrong
        if not self.motion.hasManager:
            self.motion.initManager()
        if not self.motion.hasManager:
            return isWrong
        if not self.motion.manager.isAvailable:
            self.motion.manager.ReOpen()
        self.devices.UpdateDeviceStatus()
        self.webevent.SendEvent(Request.APIInstance(WebAPILevel.getChamberStatus))
        """设置自动匹配模板模式 """
        self.status.setAutoScanMode(isAutoScanning)
        self.webevent.SlotClearImageListSignal('changedSlide', isWrong)
        """初始化模块"""
        isWrong = self.devices.waitForDeviceHome()
        if RECODE_SUCCEED != isWrong:
            """开始扫描"""
            self.eventBus.WebSocketTransmitStartScanning()
            warning_string: str = '仪器初始化失败'
            if self.system.isEnglishMode:
                warning_string = 'Instrument initialization failed'
            self.setWarning(warning_string)
            return isWrong
        """打开WEB服务端"""
        if not self.webserver.isAvailable:
            self.devices.initWebServer()
            self.webserver.ReOpen()
        """运行状态更新"""
        if not self.status.waitForRunning():
            self.eventBus.WebSocketTransmitStartScanning()
            if not self.status.isTrayZAvailable:
                if self.system.isEnglishMode:
                    self.sendWarning('Slide Chamber initialization error')
                else:
                    self.sendWarning('片仓初始化错误')
            if not self.status.isTrayHAvailable:
                if self.system.isEnglishMode:
                    self.sendWarning('Hook initialization error')
                else:
                    self.sendWarning('挂钩初始化错误')
            if not self.status.isMicroscopeAvailable:
                if self.system.isEnglishMode:
                    self.sendWarning('Microscope initialization error')
                else:
                    self.sendWarning('显微镜初始化错误')

            if not self.status.isManipulatorAvailable:
                if self.system.isEnglishMode:
                    self.sendWarning('Slide Table initialization error')
                else:
                    self.sendWarning('载玻台初始化错误')

            if not self.status.isScanCodeAvailable:
                if self.system.isEnglishMode:
                    self.sendWarning('Scanner initialization error')
                else:
                    self.sendWarning('扫码器初始化错误')

            isWrong = RECODE_FAILURE
            return isWrong
        """检测片仓盒"""
        isWrong = self.waitForCheckChamberBox()
        if RECODE_SUCCEED != isWrong:
            self.sendWarning('请检查片仓盒是否已放置')
            return isWrong
        """开始扫描"""
        self.eventBus.WebSocketTransmitStartScanning()
        # AppTimeLoop.processEvents(1000)
        """托盘有载玻台"""
        self.waitForClearSlideTable()
        return RECODE_SUCCEED

    def finishChamberScanning(self, flag: int = RECODE_SUCCEED) -> int:
        """初始化模块"""
        tray_number: int
        isWrong    : int = RECODE_SUCCEED
        """如果是退出 发送退出信号"""

        self.eventbus.WebSocketTransmitChamberStatus()
        if RECODE_SUCCEED != isWrong:
            pass
        else:
            self.devices.waitForDeviceHome()
            if self.system.isEnglishMode:
                self.sendMessage(EN_SCANNING_COMPLETE)
            else:
                self.sendMessage(SCANNING_COMPLETE)

        self.status.setJumpScanning(False)
        self.devices.setHeartbeat(True)
        self.status.setExit(True)
        self.status.setStopScanningDateTime(Qt.QDateTime.currentDateTime())
        self.status.setScanningDateTime(None)
        self.status.setScanningStatus(ScanStatusLevel.Default_Status)
        self.eventBus.WebSocketPushScanningData()
        self.eventBus.WebSocketTransmitExit()
        return RECODE_SUCCEED

    def changedScanningStatus(self, chamber_number: int, row_number: int, tray_number: int, level: int, codestring: str = None, objective: int = None):
        """修改当前扫描状态"""
        self.status.changedScanningStatus(chamber_number, row_number, tray_number, level, codestring, objective)
        self.eventBus.WebSocketTransmitChamberStatus()

    def changedTrayScanningStatus(self, chamber_number: int, level: int, objective: int = None):
        """修改当前扫描状态"""
        self.status.changedTrayScanningStatus(chamber_number, level, objective)
        self.eventBus.WebSocketTransmitChamberStatus()

    def setScanningStatus(self, tray_number: int, scan_status: int, model: SlideModelInterface):
        """修改当前状态为扫描完成"""
        if not isinstance(model, SlideModelInterface):
            return
        self.changedScanningStatus(model.ChamberGroupNumber            ,
                                   model.ChamberRowNumber              ,
                                   tray_number                         ,
                                   scan_status                         ,
                                   model.CodeString                    ,
                                   model.ObjectiveLevel                ,
                                   )


    def ChangedScanningStatus(self, chamber_number: int, row_number: int, status: int, objective: int = None, **args):
        """修改当前扫描状态"""
        item: SlideModelInterface = ChamberStatusModel.getChamberSlide(chamber_number, row_number)
        if not isinstance(item, SlideModelInterface):
            return
        self.changedScanningStatus(item.ChamberGroupNumber                                                 ,
                                   item.ChamberRowNumber                                                   ,
                                   row_number                                                               ,
                                   status                                                                   ,
                                   item.CodeString                                                         ,
                                   item.ObjectiveLevel if not isinstance(objective, int) else objective    ,
                                   )


    def getBeginOilingSlide(self, chamber_number: int, row_number: int, tray_number: int, objective: int, isOffset: bool = True) -> SlideModelInterface:
        FrontPoint          : SlideModelInterface                                               #
        models              : list[SlideModelInterface]                                         #
        tray_model          : TrayModel         = TrayModel.getConfig(tray_number)              #
        Anointing           : AnointingModel    = AnointingModel.getConfig(objective)           #
        OffsetRowNumber     : int = 0                                                           #
        OffsetColNumber     : int = 0                                                           #
        DropingPoints       : list[int]                                                         #
        middle              : list[list[int]]                                                   #
        _, middle = self.getOilArrays(chamber_number, row_number, tray_number, objective)
        if isOffset:
            OffsetRowNumber      = Anointing.OffsetRowNumber
            OffsetColNumber      = Anointing.OffsetColNumber
        _models: list[SlideModel] = SlideModel.getSourceOilDropingPoint(tray_model, middle, chamber_number, row_number, objective, OffsetRowNumber, OffsetColNumber)
        FrontPoint = None if _models is None or len(_models) <= 0 else _models[0]
        if isinstance(FrontPoint, SlideModelInterface):
            FrontPoint.Position_Z = Anointing.OilDaub_Position
        return FrontPoint

    def getOilArrays(self, chamber_number: int, row_number: int, tray_number: int, objective: int) -> (list[list[int]], list[int]):
        FrontPoint          : list[int]       = []                                              #
        Points              : list[list[int]] = []                                              #
        Anointing           : AnointingModel = AnointingModel.getConfig(objective)              #
        OilDropingNumber    : int = min(6, max(1, int(Anointing.OilDropingNumber)))             #
        template_model      : ScanTemplate                                                      #
        previewsettings     : Previewsettings                                                   #
        collectsettings     : Collectsettings                                                   #
        tray_model          : TrayModel = TrayModel.getConfig(tray_number)                      #
        template_model, previewsettings, collectsettings = self.status.getSlideScanTemplate(chamber_number, row_number)
        if template_model is None or tray_model is None:
            return Points, FrontPoint
        MinRowNumber: int = tray_model.MinRowNumber                                             #
        MinColNumber: int = tray_model.MinColNumber                                             #
        MaxRowNumber: int = tray_model.MaxRowNumber                                             #
        MaxColNumber: int = tray_model.MaxColNumber                                             #
        left        : int = template_model.left                                                 #
        top         : int = template_model.top                                                  #
        width       : int = template_model.width                                                #
        height      : int = template_model.height                                               #

        OilDropingNumber = self.algorithm.getOilPointCount(width,  height)

        Points, FrontPoint = self.algorithm.SlideOilDropingArray(
            left        =       max(left, MinRowNumber)             ,
            top         =       max(top , MinColNumber)             ,
            width       =       min(width , MaxRowNumber - left)    ,
            height      =       min(height, MaxColNumber - top )    ,
            max_row     =       MaxRowNumber                        ,
            max_col     =       MaxColNumber                        ,
            drop_rows   =       1                                   ,
            drop_cols   =       OilDropingNumber                    )

        return Points, FrontPoint