#!D:/IDE/anaconda3/envs/Microscope_Scan python
# -*- coding: UTF-8 -*-
"""
@FileName：SlideScanningBusiness.py
@Description：
@Author：XSH
@Time：2025/11/15 13:01
@Department：研发部
@Copyright：©2025 乐辰生物
"""
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 AppCore.Requests                                           import *
from AppBackEnd.AppBusinessController                           import AppBusinessController, AppBusinessInterface
from AppCore.AppAlgorithms.ImageAlgorithm                       import ImageAlgorithm
class SlideScanningBusiness(Qt.QObject, AppBusinessController):
    def __init__(self, parent: AppBusinessInterface = None):
        super(SlideScanningBusiness, self).__init__(parent=parent if parent is not None else parent.m_Control)
        self.initialize()
        self.initScanLevel()
        self.initModules(parent)

    def initScanLevel(self):
        self.ScanLevel = ScanStatusLevel.LowScanning_Status

    def initModules(self, parent: AppBusinessInterface = None, **args):
        if isinstance(parent, AppBusinessInterface):
            self.Config                             = parent.config                       #
            self.SystemConfig                       = parent.system                       #
            self.HardWare                           = parent.devices                      #
            self.GlobalStatus                       = parent.status                       #
            self.Application                        = parent.application                  #
            self.Algorithm                          = parent.algorithm                    #
            self.EventBus                           = parent.eventBus                     #

    def isValid(self) -> bool:
        return self.hasGlobalStatus and self.hasSystemConfig and self.hasConfig and self.hasDetector and self.hasMotion

    @property
    def isAvailable(self) -> bool:
        return self.isValid() and self.hasAxisX and self.hasAxisY and self.hasMicroscope

    def Done(self, **args) -> int:
        isWrong: int = RECODE_FAILURE
        self.status.setScanningStatus(self.ScanLevel)
        self.devices.setHeartbeat(False)
        try:
            isSafe          : bool  = AppConvert.ObjectConvert(args.get('isSafe'          , True), bool)
            chamber_number  : int   = AppConvert.ObjectConvert(args.get('chamber_number'  , None), int )
            row_number      : int   = AppConvert.ObjectConvert(args.get('row_number'      , None), int )
            keys: list[str] = list(args.keys())
            _args: dict = {}
            for key in keys:
                if key == 'isSafe':
                    pass
                elif key == 'chamber_number':
                    pass
                elif key == 'row_number':
                    pass
                else:
                    _args[key] = args.get(key, None)
            if isinstance(chamber_number, int) and isinstance(row_number, int):
                self.ChangedScanningStatus(chamber_number, row_number, self.ScanLevel)
                self.eventbus.WebSocketPushScanningData()
                isWrong = self.SlideScanning(chamber_number, row_number, isSafe, **_args)
        except Exception as e:
            AppUtils.print_Exception(e)
        if self.status.isExit:
            self.status.setScanningStatus(ScanStatusLevel.FinishScanning_Status)
        elif self.status.isJumpScanning:
            self.status.setScanningStatus(ScanStatusLevel.JumpScanning_Status)
        elif RECODE_SUCCEED == isWrong:
            self.status.setScanningStatus(self.ScanLevel)
        self.eventBus.WebSocketPushScanningData()
        return

    def WaitDone(self, **args) -> int:
        isWrong: int = RECODE_FAILURE
        self.status.setScanningStatus(self.ScanLevel)
        self.devices.setHeartbeat(False)

        try:
            isSafe          : bool  = AppConvert.ObjectConvert(args.get('isSafe'          , True), bool)
            chamber_number  : int   = AppConvert.ObjectConvert(args.get('chamber_number'  , None), int )
            row_number      : int   = AppConvert.ObjectConvert(args.get('row_number'      , None), int )
            keys: list[str] = list(args.keys())
            _args: dict = {}
            for key in keys:
                if key == 'isSafe':
                    pass
                elif key == 'chamber_number':
                    pass
                elif key == 'row_number':
                    pass
                else:
                    _args[key] = args.get(key, None)
            if isinstance(chamber_number, int) and isinstance(row_number, int):
                self.ChangedScanningStatus(chamber_number, row_number, self.ScanLevel)
                self.eventbus.WebSocketPushScanningData()
                isWrong = self.SlideScanning(chamber_number, row_number, isSafe, **_args)
        except Exception as e:
            AppUtils.print_Exception(e)
        if self.status.isExit:
            self.status.setScanningStatus(ScanStatusLevel.FinishScanning_Status)
        elif self.status.isJumpScanning:
            self.status.setScanningStatus(ScanStatusLevel.JumpScanning_Status)
        elif RECODE_SUCCEED == isWrong:
            self.status.setScanningStatus(self.ScanLevel)
        self.eventBus.WebSocketPushScanningData()
        return isWrong


    def SlideScanning(self, chamber_number: int, row_number: int, isSafe: bool = False, **args) -> int:
        isWrong: int = RECODE_FAILURE
        model                   : SlideScanningModel
        scanningArrays          : list[SlideScanningModel]
        tray_model              : TrayModel
        slide_model             : ChamberStatusModel
        objective_config        : ObjectiveModel
        TrayBeginAction         : SlideScanningModel
        FocusingCount           : int
        CellThreshold           : int
        MinFocusingCount        : int
        FocusingThreshold       : int
        MinCellCount            : int
        FocusCompleteCount      : int
        Index                   : int
        MaxLength               : int
        _RowNumber              : int
        _ColNumber              : int
        Position_X              : float
        Position_Y              : float
        Position_Z              : int
        _Position_Z             : int
        old_objective           : int
        tray_number             : int = TrayLevel.getTrayNumber(row_number)
        """默认10倍物镜"""
        objective               : int = ObjectiveLevel.Objective10
        """获取当前玻片的数据模型 和是否使用黑白模式  """
        classifier = self.getChamberSlideClassifier(chamber_number, row_number)
        """如果当前模式为彩色模式 则说明是微核 则物镜使用20倍物镜"""
        if self.isMicronucleus(classifier):
            objective = ObjectiveLevel.Objective20
        self.ChangedScanningStatus(chamber_number, row_number, self.ScanLevel,objective)
        """处理扫描状态: 暂停 退出 跳过"""
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            self.microscope.stop_z()
            self.microscope.init_z_range()
            return RECODE_SUCCEED
        isWrong, scanningArrays = self.readySlideScanning(chamber_number, row_number, tray_number, objective)
        """处理扫描状态: 暂停 退出 跳过"""
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            self.microscope.stop_z()
            self.microscope.init_z_range()
            return RECODE_SUCCEED
        MaxLength = 0 if scanningArrays is None else len(scanningArrays)
        if MaxLength <= 0:
            self.eventbus.SaveSpecimen(chamber_number, row_number)
            return RECODE_SUCCEED

        """获取当前物镜参数"""
        Objective = ObjectiveModel.getObjectiveConfig(objective)
        """获取托盘模型"""
        tray_model = TrayModel.getTrayModel(tray_number)
        if tray_model is None or Objective is None:
            return isWrong, None
        TrayBeginAction = self.getBeginOilingSlide(chamber_number, row_number, tray_number, objective)
        SlideScanningModel.setModelPosition(tray_model, TrayBeginAction)
        TrayBeginAction.setChamberLocation(chamber_number, row_number, tray_number, objective)
        _, __, Position_Z = self.algorithm.scansurface.get_point(TrayBeginAction.RowNumber, TrayBeginAction.ColNumber)
        """处理扫描状态: 暂停 退出 跳过"""
        self.microscope.init_objective_range()
        self.microscope.set_z_speed(Objective.Default_Speed)
        self.manipulator.reload_axis_speed()
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            self.algorithm.scansurface.initValue()
            self.microscope.waitmove_z(Objective.Safe_Limit)
            self.manipulator.waitmove_xy(TrayBeginAction.Position_X, TrayBeginAction.Position_Y)
            return RECODE_SUCCEED
        template_model, previewsettings, collectsettings = self.status.getSlideScanTemplate(chamber_number, row_number)
        if template_model is None or previewsettings is None or collectsettings is None:
            return models
        self.eventbus.WebSocketTransmitChamberStatus()
        if self.camera.isMono:
            if self.camera.IsGrabbing:
                self.camera.StopFocusing()
        else:
            if not self.camera.IsGrabbing:
                self.camera.StartFocusing(objective)
            self.camera.initColorCameraConfig()
        model = self.get_scan_begin_slide(scanningArrays)
        self.ChangedScanningStatus(chamber_number, row_number, self.ScanLevel, objective)
        ImageParameter = ImageAnalysisModel.getConfig(classifier)
        if previewsettings.has_target_quantity:
            MaxPieceLength = previewsettings.target_quantity
        else:
            MaxPieceLength = 0
        self.manipulator.reload_scan_speed(isSlow=self.isMicronucleus(classifier))
        """为了防止刚开始定焦时，因重新打开相机和设置参数之后 获取图像错误问题  重新打开相机后等3秒开始定焦"""
        self.waitForStartClassifierFocusing(model.copy(), classifier, 1000)
        if self.isMicronucleus(classifier):
            Index           : int = 0
            PieceLength     : int
            OtherLength     : int = 0
            row_list        : list[list[SlideScanningModel]]
            PieceLength = MaxPieceLength // 3
            piece_array: list[SlideModelInterface]
            array_length: int = len(scanningArrays)
            for count in range(0, array_length):
                row_list = scanningArrays[count]
                """如果扫描1-3块之后 计数按最多数量"""
                if count == 0:
                    OtherLength = OtherLength + PieceLength
                elif count == 1:
                    OtherLength = OtherLength + PieceLength
                else:
                    OtherLength = MaxPieceLength
                print(f"当前区域: {count} 已经识别数量: {self.scanningevent.Index - 1} 需要识别数量:{OtherLength}")
                if MaxPieceLength > 0:
                    if self.scanningevent.Index - 1 >= MaxPieceLength:
                        break
                if not isinstance(row_list, (list, tuple)) or len(row_list) <= 0:
                    continue
                row_length: int = len(row_list)
                arrays0: list[int] = [_ for _ in range(0, row_length, 2)]
                arrays1: list[int] = [_ for _ in range(1, row_length, 2)]
                Index = self.scan_array(Index, classifier, OtherLength, arrays0, row_list, Objective, tray_model, ImageParameter)
                if MaxPieceLength > 0:
                    if self.scanningevent.Index - 1 >= MaxPieceLength:
                        break
                SCANNING_STATUS = self.process_scanning_status()
                if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
                    self.microscope.stop_z()
                    self.microscope.init_z_range()
                    break
                Index = self.scan_array(Index, classifier, OtherLength, arrays1, row_list, Objective, tray_model,
                                        ImageParameter)
                SCANNING_STATUS = self.process_scanning_status()
                if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
                    self.microscope.stop_z()
                    self.microscope.init_z_range()
                    break
                if MaxPieceLength > 0:
                    if self.scanningevent.Index - 1 >= MaxPieceLength:
                        break
        else:
            arrays0: list[int] = [_ for _ in range(0, len(scanningArrays), 1)]
            Index: int = 0
            Index = self.scan_array(Index, classifier, MaxPieceLength, arrays0, scanningArrays, Objective, tray_model, ImageParameter)

        Objective = ObjectiveModel.getObjectiveConfig(objective)
        self.waitForScanningEmpty()
        """写入识别的核型数量"""
        self.status.setPreviewCount(chamber_number, row_number, tray_number, objective, CellModel.count())
        self.algorithm.scansurface.initValue()
        self.microscope.init_z_range()
        self.microscope.set_z_speed(Objective.Default_Speed)
        self.manipulator.reload_axis_speed()
        if isSafe:
            self.manipulator.waitmove_xy(TrayBeginAction.Position_X, TrayBeginAction.Position_Y)
        else:
            OilModel: AnointingModel = AnointingModel.getConfig(ObjectiveLevel.Objective10)
            if self.isMicronucleus(classifier):
                self.microscope.waitmove_z(Objective.Safe_Limit)
            else:
                if OilModel is None:
                    self.microscope.waitmove_z(Objective.Safe_Limit)
                else:
                    self.microscope.waitmove_z(OilModel.OilDaub_Position)


        self.eventbus.WebSocketTransmitChamberStatus()
        """如果是微核扫描 保存扫描数据到样本目录"""
        if self.isMicronucleus(classifier):
            self.eventbus.SaveSpecimen(chamber_number, row_number)
        self.camera.StopGrabbing()
        """如果是微核 平扫完即完成扫描 保存信息到文件"""
        return RECODE_SUCCEED

    def scan_array(self, Index: int, classifier: str, OtherLength: int, array_index: list[int], array: list[SlideModelInterface], Objective: ObjectiveModel, tray_model: TrayModel, ImageParameter: ImageAnalysisModel):
        MaxTrayRowNumber: int = tray_model.MaxRowNumber
        MaxTrayColNumber: int = tray_model.MaxColNumber
        MinTrayRowNumber: int = tray_model.MinRowNumber
        MinTrayColNumber: int = tray_model.MinColNumber
        if ObjectiveLevel.isMicronucleus(Objective.Level):
            MaxTrayRowNumber = tray_model.MaxRowNumber20X
            MaxTrayColNumber = tray_model.MaxColNumber20X
        for _ in array_index:
            models = array[_]
            if OtherLength > 0:
                if self.scanningevent.Index - 1 >= OtherLength:
                    break
            if isinstance(models, (list, tuple)) and len(models) > 0:
                if isinstance(models[0], SlideModelInterface):
                    _array_index: list[int] = [_ for _ in range(0, len(models), 1)]
                else:
                    _array_index: list[int] = array_index[::]
                Index = self.scan_array(Index, classifier, OtherLength, _array_index, models, Objective, tray_model, ImageParameter)
                continue
            elif not isinstance(models, SlideModelInterface):
                continue

            if self.status.waitForExitRunning():
                self.motion.stop_z()
                break
            """处理跳过"""
            SCANNING_STATUS = self.process_scanning_status()
            if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
                self.motion.stop_z()
                break
            try:
                model = models
                model.Level = self.ScanLevel
                model.Index = Index + 1
                model.ID = Index + 1
                if MinTrayRowNumber <= model.RowNumber <= MaxTrayRowNumber or MinTrayColNumber <= model.ColNumber <= MaxTrayColNumber:
                    _, __, _Position_Z = self.algorithm.scansurface.get_point(model.RowNumber, model.ColNumber)
                    if isinstance(_Position_Z, (float, int)):
                        model.Position_Z = int(_Position_Z)
                        self.scan_slide_classifier_action(model, Objective, classifier, ImageParameter)
                        """判断识别的细胞数量是否大于等于设置的采集数量"""
                        if OtherLength > 0:
                            if self.scanningevent.Index - 1 >= OtherLength:
                                break
                    else:
                        print("warning")
            except Exception as e:
                AppUtils.print_Exception(e)
            Index += 1
        return Index

    def get_scan_begin_slide(self, array: list) -> SlideModelInterface:
        if isinstance(array, (list, tuple)):
            if len(array) <= 0:
                return None
            for _array in array:
                return self.get_scan_begin_slide(_array)
        elif isinstance(array, SlideModelInterface):
            return array
        else:
            return None

    def readySlideScanning(self, chamber_number: int, row_number: int, tray_number: int, objective: int) -> int:
        isWrong: int = RECODE_FAILURE
        """初始化相机线程  扫描数据处理线程  平扫数据识别线程"""
        if  not self.hasScanning or not self.hasCameraScanning:
            self.initEventBus()
            self.eventbus.initScanning          ()
            self.eventbus.initCameraScanning    ()
            self.eventbus.initFocusing          ()
        """启动相机线程  扫描数据处理线程  平扫数据识别线程"""
        self.scanningevent      .StartFocusing()
        self.camerascanningevent.StartFocusing()
        """加载识别模型"""
        self.algorithm.initLowClassifier()

        """清空扫描识别的核型数据"""
        CellModel.clear()
        self.status.setPreviewCount(chamber_number, row_number, tray_number, objective, CellModel.count())
        WebSlot.WebServerReceivedSignal.emit(Request.APIInstance(WebAPILevel.getChamberStatus))
        """获取当前托盘的定焦点"""
        FocusingCount       = self.status.getTrayFocusingCount(tray_number)
        """获取当前物镜参数"""
        objective_config    = ObjectiveModel.getObjectiveConfig(objective)
        """获取托盘模型"""
        tray_model          = TrayModel.getTrayModel(tray_number)
        if tray_model is None or objective_config is None:
            self.status.setScanningStatus(ScanStatusLevel.ScanTemplateWarning_Status)
            self.status.changedChamberScanningStatus(chamber_number=chamber_number, row_number=row_number, level=ScanStatusLevel.ScanTemplateWarning_Status)
            return isWrong, None
        """如果识别模型没有加载成功 直接退出"""
        if not self.algorithm.scansurface.isAvailable:
            self.status.setScanningStatus(ScanStatusLevel.LowModelWarning_Status)
            self.status.changedChamberScanningStatus(chamber_number=chamber_number, row_number=row_number, level=ScanStatusLevel.LowModelWarning_Status)
            return isWrong, None
        """获取平扫数据量小定焦点"""
        MinFocusingCount = objective_config.MinFocusCount
        """如果当前定焦点小于物镜参数中设置的最小定焦点 直接退出"""
        if FocusingCount < MinFocusingCount:
            self.status.setScanningStatus(ScanStatusLevel.FocusingWarning_Status)
            self.status.changedChamberScanningStatus(chamber_number=chamber_number, row_number=row_number, level=ScanStatusLevel.FocusingWarning_Status)
            return RECODE_FAILURE, None
        TrayBeginAction = self.getBeginOilingSlide(chamber_number, row_number, tray_number, objective)
        SlideScanningModel.setModelPosition(tray_model, TrayBeginAction)
        TrayBeginAction.setChamberLocation(chamber_number, row_number, tray_number, objective)
        scanningArrays      = self.getArrays(chamber_number, row_number, objective)
        MaxLength = 0 if scanningArrays is None else len(scanningArrays)
        if MaxLength <= 0:
            self.status.setScanningStatus(ScanStatusLevel.ScanTemplateWarning_Status)
            self.status.changedChamberScanningStatus(chamber_number=chamber_number, row_number=row_number, level=ScanStatusLevel.ScanTemplateWarning_Status)
            return RECODE_FAILURE, None
        begin_model: SlideModelInterface = self.get_scan_begin_slide(scanningArrays)
        if begin_model is None:
            return RECODE_FAILURE, None
        Position_X = begin_model.Position_X
        Position_Y = begin_model.Position_Y
        RowNumber = begin_model.RowNumber
        ColNumber = begin_model.ColNumber
        self.manipulator.reload_scan_speed(isSlow=not self.camera.isMono)
        _, __, Position_Z = self.algorithm.scansurface.get_point(RowNumber, ColNumber)
        self.microscope.init_objective_range()
        self.microscope.set_z_upper_limit(objective_config.Upper_Limit)
        self.microscope.set_objective_default_speed(objective)
        """处理暂停和停止"""
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            return RECODE_SUCCEED, scanningArrays
        # 移动Z轴到6mm安全位置
        ObjectiveConfig1: ObjectiveModel = ObjectiveModel.getConfig(ObjectiveLevel.Objective1)
        """三次读取当前物镜状态"""
        _, old_objective = self.microscope.get_objective()
        if RECODE_SUCCEED != _ or old_objective != objective:
            self.motion.waitmove_z(ObjectiveConfig1.Safe_Limit)
            _ = self.devices.changedObjective(level=objective, is_lower_limit=False)
        if RECODE_SUCCEED != _:
            self.status.setScanningStatus(ScanStatusLevel.ModelWarning_Status)
            self.status.changedChamberScanningStatus(chamber_number=chamber_number, row_number=row_number, level=ScanStatusLevel.ModelWarning_Status)
            return RECODE_FAILURE
        self.manipulator.reset_moving(begin_model.Position_X, begin_model.Position_Y)
        self.manipulator.waitmove_xy(begin_model.Position_X, begin_model.Position_Y)
        self.status.setCameraModel(objective)
        if not self.camera.IsOpen:
            self.camera.ReOpen(objective)
        if ObjectiveLevel.isMicronucleus(objective):
            self.camera.StartFocusing(objective)
            self.manipulator.reset_slow_scanning(Position_X, Position_Y)
        else:
            self.camera.StopFocusing()
            self.manipulator.reset_scanning(Position_X, Position_Y)
        if not self.camera.isMono:
            self.camera.initColorCameraConfig()
        """处理暂停和停止"""
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            return RECODE_SUCCEED, scanningArrays
        self.microscope.changedLightIntensity(objective_config.Level)
        self.manipulator.waitmove_xy(Position_X, Position_Y)
        """处理暂停和停止"""
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            return RECODE_SUCCEED, scanningArrays
        self.microscope.set_z_move_mode (1          )
        self.microscope.waitmove_z      (Position_Z )
        _, old_objective = self.microscope.get_objective()
        isWrong = RECODE_SUCCEED if self.camera.IsOpen and old_objective == objective and RECODE_SUCCEED == _ else RECODE_FAILURE
        if RECODE_SUCCEED != isWrong:
            self.status.setScanningStatus(ScanStatusLevel.ModelWarning_Status)
            self.status.changedChamberScanningStatus(chamber_number=chamber_number, row_number=row_number, level=ScanStatusLevel.ModelWarning_Status)
        return isWrong, scanningArrays
        pass










    def exit_scanning(self, z_speed: (int, float), z_position: (int, float)):
        self.algorithm.scansurface.initValue()
        self.microscope.init_z_range()
        self.microscope.set_z_speed(z_speed)
        self.manipulator.reload_axis_speed()
        self.microscope.waitmove_z(z_position)

    def scan_slide_classifier_action(self, model: SlideScanningModel, Objective: ObjectiveModel, classifier = 'Aberration', ImageParameter: ImageAnalysisModel = None, isSafe: bool = False) -> int:
        isWrong                 : int = RECODE_SUCCEED
        information             : str
        move_xy_time            : int
        camera_time             : int
        scanning_times          : int
        low_focusing_begin_z    : int
        low_focusing_end_z      : int
        low_focusing_status     : int
        begin_times             : Qt.QDateTime
        item: SlideScanningModel
        begin_times             = Qt.QDateTime.currentDateTime()
        focusing_status         : int = ScanStatusLevel.Low_Four_Focus_Status
        if not self.isMicronucleus(classifier):
            item            = model.copy()
            item.Level      = self.ScanLevel
            item.Index      = model.Index
            """移动XYZ位置到指定位置"""
            isWrong, information    = self.motion.waitmove_scanning_xyz(item.Position_X, item.Position_Y, item.Position_Z)
            if RECODE_SUCCEED == isWrong:
                move_xy_time = begin_times.msecsTo(Qt.QDateTime.currentDateTime())
                self.camerascanningevent.SendEvent(item)
                scanning_times = begin_times.msecsTo(Qt.QDateTime.currentDateTime())
                print(f'{information} xyz times: {move_xy_time} ms 一帧时间为: {scanning_times}ms')
            else:
                self.scanningevent.SendEvent(item)
        else:
            _item = model.copy()
            isWrong, information    = self.motion.waitmove_slow_scanning_xy(model.Position_X, model.Position_Y)
            move_xy_time = begin_times.msecsTo(Qt.QDateTime.currentDateTime())
            scanning_times = begin_times.msecsTo(Qt.QDateTime.currentDateTime())
            print(f'{information} xyz times: {move_xy_time} ms 一帧时间为: {scanning_times}ms')
            if RECODE_SUCCEED == isWrong:
                isWrong, low_focusing_begin_z, low_focusing_end_z, item = self.StartClassifierScanFocusing(model, Objective, focusing_status, classifier, True)
                if RECODE_SUCCEED == isWrong and isinstance(item, SlideModelInterface):
                    if self.isFocusingCellAvailable(item):
                        item.Level = self.ScanLevel
                        item.Index = model.Index
                        if ImageParameter is not None and  ImageParameter.hasAnalysis and ImageParameter.isAnalysis:
                            image = ImageAlgorithm.ProcessMicronucleus(item.toImage(), ImageParameter)
                            item.setImageSource(image)
                        _item = item
            self.scanningevent.SendEvent(_item)
        AppTimeLoop.processGlobalEvents(200)
        return RECODE_SUCCEED











    def finish_slide_scanning(self, chamber_number: int, row_number: int, **args) -> int:
        pass

    def getArrays(self, chamber_number: int, row_number: int, objective: int, **args) -> (int, list):
        models              : list[SlideScanningModel]  = []
        item                : SlideModel
        Point               : list[int]
        scanning_points     : list[list[int]]
        LState              : int
        RState              : int
        SpecimenNumber      : str
        SlideNumber         : str
        LineNumber          : str
        CodeString          : str
        MaxRowNumber        : int
        MaxColNumber        : int
        MinRowNumber        : int
        MinColNumber        : int
        is_save             : int
        RowNumber           : int
        ColNumber           : int
        Left                : int
        Top                 : int
        Width               : int
        Height              : int
        MaxTrayRowNumber    : int
        MaxTrayColNumber    : int
        MinTrayRowNumber    : int
        MinTrayColNumber    : int
        tray_number         : int = TrayLevel.getTrayNumber(row_number)
        template_model      : ScanTemplate
        previewsettings     : Previewsettings
        collectsettings     : Collectsettings
        tray_model          : TrayModel                 = TrayModel.getTrayModel            (tray_number)
        Objective           : ObjectiveModel            = ObjectiveModel.getObjectiveConfig (objective)
        slide_model         : ChamberStatusModel        = self.status.getChamberSlide(chamber_number, row_number)
        template_model, previewsettings, collectsettings = self.status.getSlideScanTemplate(chamber_number, row_number)
        if slide_model is None or tray_model is None or Objective is None:
            return models
        if template_model is None or previewsettings is None or collectsettings is None:
            return models
        tray_model.initTray(tray_number)
        previewClassifier = PreviewClassifierModel.Classifier(previewsettings.classifier)
        collectClassifier = CollectClassifierModel.Classifier(collectsettings.classifier)
        IsSave              = previewsettings.is_save       #
        LState              = slide_model.LState            #
        RState              = slide_model.RState            #
        SpecimenNumber      = slide_model.SpecimenNumber    #
        SlideNumber         = slide_model.SlideNumber       #
        LineNumber          = slide_model.LineNumber        #
        CodeString          = slide_model.CodeString        #
        """扫描范围"""
        Left                    = template_model.left
        Top                     = template_model.top
        Width                   = template_model.width
        Height                  = template_model.height
        MaxTrayRowNumber: int = tray_model        .MaxRowNumber
        MaxTrayColNumber: int = tray_model        .MaxColNumber
        MinTrayRowNumber: int = tray_model.MinRowNumber
        MinTrayColNumber: int = tray_model.MinColNumber
        if ObjectiveLevel.isMicronucleus(objective):
            MaxTrayRowNumber = tray_model.MaxRowNumber20X
            MaxTrayColNumber = tray_model.MaxColNumber20X
        self.status.setTrayTableSlide(slide_model.ChamberGroupNumber, slide_model.ChamberRowNumber, tray_model.Level,
                                      objective=objective, templateID=template_model.ID, codestring=CodeString,
                                      level=self.ScanLevel)
        if ObjectiveLevel.isMicronucleus(objective):
            scanning_points = self.algorithm.MicronucleusScanningArray( begin_row   =   max(MinTrayRowNumber, min(Left        , MaxTrayRowNumber)) ,
                                                                        begin_col   =   max(MinTrayColNumber, min(Top         , MaxTrayColNumber)) ,
                                                                        row_number  =   max(MinTrayRowNumber, min(Width       , MaxTrayRowNumber)) ,
                                                                        col_number  =   max(MinTrayColNumber, min(Height      , MaxTrayColNumber)) ,
                                                                        max_row     =   MaxTrayRowNumber + 1                  ,
                                                                        max_col     =   MaxTrayColNumber + 1                  ,
                                                                        focus_rows  =   template_model.focus_point_column     ,
                                                                        focus_cols  =   template_model.focus_point_row        )
            piece_array: list
            Index      : int = 0
            row_array: list
            piece_array_points: list


            for row_array in scanning_points:
                row_list: list = []
                step1: int = 0
                step2: int = 0
                for count, piece in enumerate(row_array):
                    piece_array = SlideModel.getScanningItems(tray_model, piece, chamber_number, row_number, objective, IsSave)
                    for item in piece_array:
                        item.ID                         = None                   #
                        item.Focusing                   = None                   #
                        item.Level                      = self.ScanLevel         #
                        item.ChamberGroupNumber         = chamber_number         #
                        item.ChamberRowNumber           = row_number             #
                        item.TrayNumber                 = tray_number            #
                        item.Index                      = Index                  #
                        item.IsSave                     = IsSave                 #
                        item.LState                     = LState                 #
                        item.RState                     = RState                 #
                        item.SpecimenNumber             = SpecimenNumber         #
                        item.SlideNumber                = SlideNumber            #
                        item.LineNumber                 = LineNumber             #
                        item.CodeString                 = CodeString             #
                        item.SlideTable                 = tray_model             #
                        item.Objective                  = Objective              #
                        item.ScanTemplate               = template_model         #
                        item.Preview                    = previewsettings        #
                        item.Collect                    = collectsettings        #
                        item.PreviewClassifier          = previewClassifier      #
                        item.PreferredClassifier        = previewClassifier      #
                        item.CollectClassifier          = collectClassifier      #
                        Index += 1
                    if count % 2 == 0:
                        if step1 % 2 == 0:
                            row_list.append(piece_array)
                        else:
                            row_list.append(piece_array[::-1])
                        step1 += 1
                    else:
                        if step2 % 2 == 0:
                            row_list.append(piece_array)
                        else:
                            row_list.append(piece_array[::-1])
                        step2 += 1
                models.append(row_list)
        else:
            scanning_points = self.algorithm.SlideScanningArray(begin_row   =   max(MinTrayRowNumber, min(Left        , MaxTrayRowNumber)) ,
                                                                begin_col   =   max(MinTrayColNumber, min(Top         , MaxTrayColNumber)) ,
                                                                row_number  =   max(MinTrayRowNumber, min(Width       , MaxTrayRowNumber)) ,
                                                                col_number  =   max(MinTrayColNumber, min(Height      , MaxTrayColNumber)) ,
                                                                max_row     =   MaxTrayRowNumber + 1                ,
                                                                max_col     =   MaxTrayColNumber + 1                ,
                                                                is_row_s_line=True)
            models = SlideModel.getScanningItems(tray_model, scanning_points, chamber_number, row_number, objective, IsSave)
            for index, item in enumerate(models):
                item.ID                         = None                   #
                item.Focusing                   = None                   #
                item.Level                      = self.ScanLevel         #
                item.ChamberGroupNumber         = chamber_number         #
                item.ChamberRowNumber           = row_number             #
                item.TrayNumber                 = tray_number            #
                item.Index                      = index                  #
                item.IsSave                     = IsSave                 #
                item.LState                     = LState                 #
                item.RState                     = RState                 #
                item.SpecimenNumber             = SpecimenNumber         #
                item.SlideNumber                = SlideNumber            #
                item.LineNumber                 = LineNumber             #
                item.CodeString                 = CodeString             #
                item.SlideTable                 = tray_model             #
                item.Objective                  = Objective              #
                item.ScanTemplate               = template_model         #
                item.Preview                    = previewsettings        #
                item.Collect                    = collectsettings        #
                item.PreviewClassifier          = previewClassifier      #
                item.PreferredClassifier        = previewClassifier      #
                item.CollectClassifier          = collectClassifier      #
        return models




