#!D:/IDE/anaconda3/envs/Microscope_Scan python
# -*- coding: UTF-8 -*-
"""
@FileName：SlideFocusingBusiness.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
class SlideFocusingBusiness(Qt.QObject, AppBusinessController):
    def __init__(self, parent: AppBusinessInterface = None):
        super(SlideFocusingBusiness, self).__init__(parent=parent if parent is not None else parent.m_Control)
        self.initialize()
        self.ScanLevel = ScanStatusLevel.Low_First_Focus_Status
        self.initModules(parent)

    def initScanLevel(self):
        self.ScanLevel = ScanStatusLevel.Low_First_Focus_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.hasAxisZ and self.hasMicroscope and self.hasAxisH

    def Done(self, **kwargs) -> 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.SlideFocusing(chamber_number, row_number, isSafe, **_args)
        except Exception as e:
            AppUtils.print_Exception(e)
        self.devices.setHeartbeat(True)
        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.SlideFocusing(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 ready_slide_focusing(self, chamber_number: int, row_number: int, objective: int, **args) -> (int, list):
        isWrong             : int = RECODE_FAILURE
        TrayFocusArrays     : list[SlideFocusingModel] = []
        if not self.isAvailable:
            return isWrong, TrayFocusArrays

        tray_number  : int           = TrayLevel.getTrayNumber(row_number)
        tray_model   : TrayModel     = TrayModel.getTrayModel(tray_number)
        self.status.setPreviewCount(chamber_number, row_number, tray_number, objective, 0)

        Objective       : ObjectiveModel = ObjectiveModel.getObjectiveConfig(objective)
        TrayFocusArrays = self.getArrays(chamber_number, row_number, objective, **args)
        MaxLength       = len(TrayFocusArrays)
        if MaxLength <= 0:
            return isWrong, TrayFocusArrays
        Begin = TrayFocusArrays[0]
        Begin.Position_Z = Objective.Focus_Lower_Limit
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            self.microscope.stop_z()
            return RECODE_SUCCEED

        self.manipulator.reload_axis_speed()
        self.microscope.stop_z()
        self.microscope.init_z_range()
        self.microscope.set_z_speed(Objective.Default_Speed)

        ObjectiveConfig1: ObjectiveModel = ObjectiveModel.getConfig(ObjectiveLevel.Objective1)

        old_objective: int
        _, old_objective = self.microscope.get_objective()

        if RECODE_SUCCEED != _ or old_objective != objective:
            self.microscope.waitmove_z(ObjectiveConfig1.Safe_Limit)
            self.manipulator.reset_moving(tray_model.Position_X, tray_model.Position_Y)
            _ = self.microscope.set_objective(level=objective, is_lower_limit=False)
        if RECODE_SUCCEED != _:
            _, old_objective = self.microscope.get_objective()
            if RECODE_SUCCEED != _ or old_objective != objective:
                _ = self.microscope.set_objective(level=objective, is_lower_limit=False)

        if RECODE_SUCCEED != _:
            _, old_objective = self.microscope.get_objective()
            if RECODE_SUCCEED != _ or old_objective != objective:
                return isWrong, TrayFocusArrays
        self.manipulator.waitmove_xy(Begin.Position_X, Begin.Position_Y)
        self.microscope.stop_z()
        self.microscope.waitmove_z(Begin.Position_Z)
        """初始化定焦评分线程"""
        if not self.hasFocusing:
            self.initEventBus()
            self.eventbus.initFocusing()
        if self.status.waitForExitRunning():
            return isWrong, TrayFocusArrays
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            return isWrong, TrayFocusArrays
        self.microscope.changedLightIntensity(Objective.Level, isChanged=True)
        if not self.camera.IsOpen:
            self.camera.ReOpen(objective)
        else:
            self.camera.setModel(objective)
        self.camera.StartFocusing(objective)
        if ObjectiveLevel.isMicronucleus(objective):
            self.camera.WhiteAutoOnce()
        _, old_objective = self.microscope.get_objective()
        isWrong = RECODE_SUCCEED if self.camera.IsGrabbing and RECODE_SUCCEED == _ and old_objective == objective else RECODE_FAILURE
        return isWrong, TrayFocusArrays

    def SlideFocusing(self, chamber_number: int, row_number: int, isSafe: bool = False, **args) -> int:
        isWrong: int = RECODE_FAILURE
        TrayNumber                      : int
        RowNumber                       : int
        ChamberNumber                   : int
        MinChamberNumber                : int
        MaxChamberNumber                : int
        MinRowNumber                    : int
        MaxRowNumber                    : int
        FocusPointNumber                : int
        objective_level                 : int
        MaxLength                       : int
        Index                           : int
        old_objective                   : int
        MaxTrayRowNumber                : int
        MaxTrayColNumber                : int
        classifier                      : str
        isMono                          : bool
        focus_model                     : SlideFocusingModel
        begin                           : Qt.QDateTime
        tray_model                      : TrayModel
        objective_config                : ObjectiveModel
        TrayBeginAction                 : SlideFocusingModel
        model                           : SlideFocusingModel
        Begin                           : SlideFocusingModel
        TrayFocusArrays                 : list[SlideFocusingModel]
        CellCount                       : int
        MinCellCount                    : int
        CellThreshold                   : int
        ImageScore                      : int
        FocusingThreshold               : int
        MinFocusCount                   : int
        FocusCompleteCount              : int
        classifier                      : str
        isUpWard                        : int = 0
        """默认10倍物镜"""
        objective_level = ObjectiveLevel.Objective10
        """获取当前玻片的数据模型 和是否使用黑白模式  """
        classifier = self.getChamberSlideClassifier(chamber_number, row_number)
        """如果当前模式为彩色模式 则说明是微核 则物镜使用20倍物镜"""
        if self.isMicronucleus(classifier):
            objective_level = ObjectiveLevel.Objective20
        self.ChangedScanningStatus(chamber_number, row_number, self.ScanLevel, objective_level)
        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, TrayFocusArrays = self.ready_slide_focusing(chamber_number, row_number, objective_level)
        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
        if RECODE_SUCCEED != isWrong or not isinstance(TrayFocusArrays, list):
            self.microscope.stop_z()
            self.microscope.init_z_range()
            return isWrong
        tray_number     : int = TrayLevel.getTrayNumber(row_number)
        slide           : ChamberStatusModel = ChamberStatusModel.getChamberSlide(chamber_number, row_number)
        """设置样本扫描时间"""

        ChamberStatusModel.setChamberSlideScanningDateTime(chamber_number, row_number, Qt.QDateTime.currentDateTime())
        self.status.setTrayTableSlide(chamber_number=chamber_number, row_number=row_number, tray_number=tray_number, CodeString=slide.CodeString, objective=objective_level)
        """清空扫描识别的核型数据"""
        CellModel.clear()
        start_focusing_time: Qt.QDateTime = Qt.QDateTime.currentDateTime()
        tray_model          = TrayModel.getTrayModel(tray_number)
        low_focusing_status : int = ScanStatusLevel.Low_First_Focus_Status
        MaxFocusingCount    : int = FocusingConfigModel.RetryCount(objective_level, low_focusing_status)
        objective_config    = ObjectiveModel.getObjectiveConfig(objective_level)
        MaxLength           = len(TrayFocusArrays)
        if MaxLength <= 0:
            return isWrong
        Begin = TrayFocusArrays[0]
        Begin.Position_Z                = objective_config.Focus_Lower_Limit
        FocusPoints = []
        FocusItems: list[SlideFocusingModel] = []
        self.status.setTrayFocusingCount(tray_number, len(FocusPoints))
        focus_model     = None
        begin           = Qt.QDateTime.currentDateTime()
        Index           = 0
        FocusingCount   : int = 0
        template_model, previewsettings, collectsettings = self.status.getSlideScanTemplate(chamber_number, row_number)
        if not isinstance(template_model, ScanTemplate):
            return isWrong

        Locations: list[list[int]] = self.get_grid_locations(template_model)
        self.manipulator.waitmove_xy(Begin.Position_X, Begin.Position_Y)
        """为了防止刚开始定焦时，因重新打开相机和设置参数之后 获取图像错误问题  重新打开相机后等3秒开始定焦"""
        self.waitForStartClassifierFocusing(Begin.copy(), classifier, 2000)
        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
        MaxArrayLength: int = len(TrayFocusArrays)
        while Index < MaxArrayLength:
            MaxArrayLength = len(TrayFocusArrays)
            self.ChangedScanningStatus(chamber_number, row_number, self.ScanLevel, objective_level)
            """处理扫描状态: 暂停 退出 跳过"""
            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
            objective_config = ObjectiveModel.getConfig(objective_level)
            self.camera.setModel(objective_level)
            self.microscope.changedLightIntensity(objective_level)

            try:
                model = TrayFocusArrays[Index]
                """处理扫描状态: 暂停 退出 跳过"""
                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
                """移动XY"""
                self.manipulator.waitmove_xy(model.Position_X, model.Position_Y)
                begin = Qt.QDateTime.currentDateTime()
                isWrong, Lower_Limit, Upper_Limit, low_focusing_status, focus_model, isUpWard = self.tray_slide_focusing(objective_level, model)
                if RECODE_SUCCEED == isWrong and isinstance(focus_model, SlideFocusingModel):
                    focusing_status: int = ScanStatusLevel.Low_First_Focus_Status
                    FocusingModel: FocusingConfigModel = FocusingConfigModel.getConfig(model.ObjectiveLevel, focusing_status)
                    """增加定焦之后检测焦点图像是否有东西"""
                    Upper_Limit = min(focus_model.Position_Z + FocusingModel.FocusingRange,objective_config.Focus_Upper_Limit)
                    Lower_Limit = min(focus_model.Position_Z - FocusingModel.FocusingRange,objective_config.Focus_Lower_Limit)
                    if self.isFocusingCellAvailable(focus_model):
                        FocusItems.append(focus_model.copy())
                        FocusPoints.append([focus_model.Index, focus_model.RowNumber, focus_model.ColNumber, focus_model.Position_Z,focus_model.ImageScore])
                        if not self.algorithm.scansurface.isAvailable:
                            self.begin_algorithm_points(Lower_Limit, Upper_Limit, focus_model)
                        else:
                            self.update_algorithm_points(Lower_Limit, Upper_Limit, focus_model)
                        FocusingCount = 0
                    else:
                        MaxFocusingCount = FocusingConfigModel.RetryCount(model.ObjectiveLevel, ScanStatusLevel.Low_First_Focus_Status)
                        MaxFocusingCount = min(8, MaxFocusingCount)
                        if FocusingCount <= MaxFocusingCount:
                            self.changed_focusing_item_point(model, Locations)
                            FocusingCount += 1
                else:
                    MaxFocusingCount = FocusingConfigModel.RetryCount(model.ObjectiveLevel, ScanStatusLevel.Low_First_Focus_Status)
                    MaxFocusingCount = min(8, MaxFocusingCount)
                    if FocusingCount <= MaxFocusingCount:
                        self.changed_focusing_item_point(model, Locations)
                        FocusingCount += 1
            except Exception as e:
                AppUtils.print_Exception(e)
                from AppLog.logHelper import logSCANNING
                logSCANNING << AppUtils.toString(e)

            """处理扫描状态: 暂停 退出 跳过"""
            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
            print(f"一帧速度为:{begin.msecsTo(Qt.QDateTime.currentDateTime())}ms {Index} {len(TrayFocusArrays)} {len(FocusPoints)}")
            begin = Qt.QDateTime.currentDateTime()
            Index += 1

        SlideLoggerModel.append_all(FocusItems)
        self.ChangedScanningStatus(chamber_number, row_number, self.ScanLevel, objective_level)
        isWrong = self.finish_slide_focusing(chamber_number, row_number, objective_level, len(FocusPoints), isSafe=isSafe, **args)
        return isWrong


    def appendTrayFocusingArray(self, FocusingCount: int, Index: int ,model: SlideModelInterface, tray_model: TrayModel, TrayFocusArrays: list[SlideModelInterface]) -> int:
        isWrong: int = RECODE_FAILURE
        MaxTrayRowNumber: int = tray_model.MaxRowNumber
        MaxTrayColNumber: int = tray_model.MaxColNumber
        MinTrayRowNumber: int = tray_model.MinRowNumber
        MinTrayColNumber: int = tray_model.MinColNumber
        if ObjectiveLevel.isMicronucleus(model.ObjectiveLevel):
            MaxTrayRowNumber = tray_model.MaxRowNumber20X
            MaxTrayColNumber = tray_model.MaxColNumber20X
        if FocusingCount % 8 == 0:
            RowNumber = min(MaxTrayRowNumber, max(model.RowNumber - 1, MinTrayRowNumber))
            ColNumber = min(MaxTrayColNumber, max(model.ColNumber - 1, MinTrayColNumber))
        elif FocusingCount % 8 == 1:
            RowNumber = min(MaxTrayRowNumber, max(model.RowNumber + 1, MinTrayRowNumber))
            ColNumber = min(MaxTrayColNumber, max(model.ColNumber - 1, MinTrayColNumber))
        elif FocusingCount % 8 == 2:
            RowNumber = min(MaxTrayRowNumber, max(model.RowNumber - 1, MinTrayRowNumber))
            ColNumber = min(MaxTrayColNumber, max(model.ColNumber + 1, MinTrayColNumber))
        elif FocusingCount % 8 == 3:
            RowNumber = min(MaxTrayRowNumber, max(model.RowNumber + 1, MinTrayRowNumber))
            ColNumber = min(MaxTrayColNumber, max(model.ColNumber + 1, MinTrayColNumber))
        elif FocusingCount % 8 == 4:
            RowNumber = min(MaxTrayRowNumber, max(model.RowNumber - 0, MinTrayRowNumber))
            ColNumber = min(MaxTrayColNumber, max(model.ColNumber - 1, MinTrayColNumber))
        elif FocusingCount % 8 == 5:
            RowNumber = min(MaxTrayRowNumber, max(model.RowNumber + 0, MinTrayRowNumber))
            ColNumber = min(MaxTrayColNumber, max(model.ColNumber - 1, MinTrayColNumber))
        elif FocusingCount % 8 == 6:
            RowNumber = min(MaxTrayRowNumber, max(model.RowNumber + 0, MinTrayRowNumber))
            ColNumber = min(MaxTrayColNumber, max(model.ColNumber + 1, MinTrayColNumber))
        elif FocusingCount % 8 == 7:
            RowNumber = min(MaxTrayRowNumber, max(model.RowNumber - 0, MinTrayRowNumber))
            ColNumber = min(MaxTrayColNumber, max(model.ColNumber + 1, MinTrayColNumber))
        else:
            return isWrong
        if RowNumber > MaxTrayRowNumber:
            return isWrong
        if ColNumber > MaxTrayColNumber:
            return isWrong

        item: SlideFocusingModel = model.copy()
        item.asObject(model)
        item.RowNumber = RowNumber
        item.ColNumber = ColNumber
        SlideFocusingModel.setModelPosition(tray_model, item)
        TrayFocusArrays.append(item)
        return RECODE_SUCCEED

    def finish_slide_focusing(self, chamber_number: int, row_number: int, objective: int, focusingCount: int, **args) -> int:
        tray_number         : int = row_number
        isSafe              : bool= AppConvert.ObjectConvert(args.get('isSafe'       , False), bool)
        tray_model          : TrayModel = TrayModel.getConfig(tray_number)
        objective_config    = ObjectiveModel.getObjectiveConfig(objective)
        self.status.setTrayFocusingCount(tray_number, focusingCount)
        self.microscope.set_z_speed(objective_config.Default_Speed)
        self.microscope.stop_z()
        if isSafe:
            self.microscope.waitmove_z(objective_config.Safe_Limit)
            self.manipulator.waitmove_xy(tray_model.Position_X, tray_model.Position_Y)
        else:
            self.microscope.waitmove_z(objective_config.Focus_Lower_Limit)
        """如果定焦点大于参数中设置的最小定焦点 """
        isWrong = RECODE_SUCCEED if focusingCount >= objective_config.FocusingCount else RECODE_FAILURE
        self.camera.StopFocusing()
        return isWrong

    def tray_slide_focusing(self, objective: int, slide: SlideModelInterface) -> (int, int, int, int, SlideFocusingModel):
        from AppLog.logHelper import logOTHER, logINFO
        isWrong                         : int = RECODE_FAILURE
        Objective                       : ObjectiveModel = ObjectiveModel.getConfig(objective)
        item                            : SlideFocusingModel
        Index                           : int
        focusing_b_z                    : int
        focusing_e_z                    : int
        focusing_speed                  : int
        focusing_status                 : int = ScanStatusLevel.Low_First_Focus_Status
        focusing_range                  : int
        is_Algorithm_Available          : bool
        FocusingCount                   : int = int(Objective.FocusingCount)
        last_focusing_model             : SlideFocusingModel = None
        next_focusing_model             : SlideFocusingModel = None
        focusing_model                  : SlideFocusingModel = None
        FocusingModel                   : FocusingConfigModel
        classifier                      : str
        isUpWard                        : int = 0
        classifier                      = self.getFocusingClassifier(slide)
        isWrong = self.waitForStartClassifierFocusing(slide, classifier, 500)
        if RECODE_SUCCEED != isWrong:
            focusing_model      = None
            return RECODE_FAILURE, None, None, focusing_status, None, isUpWard
        Objective       = ObjectiveModel.getConfig(objective)
        focusing_b_z    = Objective.Focus_Lower_Limit
        focusing_e_z    = Objective.Focus_Upper_Limit
        """处理扫描状态: 暂停 退出 跳过"""
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            return RECODE_FAILURE, None, None, focusing_status, None, isUpWard
        """设置光源"""
        self.microscope.changedLightIntensity(objective)
        Algorithm_Available = self.algorithm.scansurface.isAvailable

        for Index in range(0, min(max(FocusingCount if Algorithm_Available else FocusingCount + 1, 1), 3)):
            self.camera.setModel(objective)
            """处理扫描状态: 暂停 退出 跳过"""
            SCANNING_STATUS = self.process_scanning_status()
            if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
                focusing_model = None
                return RECODE_FAILURE, None, None, focusing_status, None, isUpWard
            is_Algorithm_Available = self.algorithm.scansurface.isAvailable
            Objective = ObjectiveModel.getObjectiveConfig(objective)
            if Index == 0:
                focusing_status = ScanStatusLevel.Low_Second_Focus_Status
                if not is_Algorithm_Available:
                    focusing_status = ScanStatusLevel.Low_First_Focus_Status
            elif Index == 1:
                focusing_status = ScanStatusLevel.Low_Three_Focus_Status
                if not is_Algorithm_Available:
                    focusing_status = ScanStatusLevel.Low_Second_Focus_Status
            else:
                if Algorithm_Available:
                    focusing_status = ScanStatusLevel.Low_Three_Focus_Status
                    if not is_Algorithm_Available:
                        focusing_status = ScanStatusLevel.Low_Second_Focus_Status
                else:
                    focusing_status = ScanStatusLevel.Low_Three_Focus_Status
            item = slide.copy()
            item.Level = focusing_status
            FocusingModel = FocusingConfigModel.FocusingConfig(objective, focusing_status)
            focusing_speed = FocusingModel.FocusingSpeed
            focusing_range = FocusingModel.FocusingRange
            focusing_base_z: float
            """如果已经初始化拟合函数"""

            if is_Algorithm_Available:
                if isinstance(last_focusing_model, SlideModelInterface):
                    focusing_base_z = max(last_focusing_model.Position_Z - int(focusing_range), Objective.Focus_Lower_Limit)
                else:
                    _, __, Position_Z = self.algorithm.scansurface.get_point(item.RowNumber, item.ColNumber)
                    if isinstance(Position_Z, (int, float)):
                        focusing_base_z = max(Position_Z - int(focusing_range), Objective.Focus_Lower_Limit)
                    else:
                        focusing_base_z = Objective.Focus_Lower_Limit
            else:
                if isinstance(last_focusing_model, SlideModelInterface):
                    focusing_base_z = max(last_focusing_model.Position_Z - int(focusing_range), Objective.Focus_Lower_Limit)
                else:
                    focusing_range = abs(Objective.Focus_Upper_Limit - Objective.Focus_Lower_Limit)
                    if isUpWard < 0:
                        focusing_base_z = Objective.Focus_Lower_Limit
                    elif isUpWard == 0:
                        focusing_base_z = Objective.Focus_Lower_Limit
                    else:
                        focusing_base_z = min(Objective.Focus_Lower_Limit + int(focusing_range), Objective.Focus_Upper_Limit - int(focusing_range))

            focusing_b_z = max(focusing_base_z, Objective.Focus_Lower_Limit)
            focusing_e_z = min(focusing_b_z + focusing_range * 2, Objective.Focus_Upper_Limit)
            isWrong, focusing_b_z, focusing_e_z, next_focusing_model, isUpWard = self.StartCustomClassifierFocusing(item, Objective, focusing_b_z, focusing_e_z, focusing_speed, focusing_status, classifier, True, True)
            if isWrong == RECODE_SUCCEED and isinstance(next_focusing_model, SlideModelInterface):
                last_focusing_model = next_focusing_model
        self.microscope.stop_z()
        self.microscope.init_z_range()
        self.microscope.set_z_speed(Objective.Default_Speed)
        if isinstance(last_focusing_model, SlideFocusingModel):
            focusing_model = last_focusing_model
        elif isinstance(next_focusing_model, SlideFocusingModel):
            focusing_model = next_focusing_model
        else:
            focusing_b_z = Objective.Focus_Lower_Limit
            focusing_e_z = Objective.Focus_Upper_Limit
            focusing_model = None
        try:
            if isinstance(focusing_model, SlideFocusingModel):
                image: np.ndarray   = focusing_model.toImage()
                isMicronucleus: bool = focusing_model.hasPreview and focusing_model.preview.isMicronucleus()
                self.SendFocusingImage(image.copy(), isMicronucleus)
                logOTHER << f'{focusing_model.CodeString} \trow:{focusing_model.RowNumber}\t col:{focusing_model.ColNumber}\t x:{focusing_model.Position_X}\t y:{focusing_model.Position_Y}\t z:{focusing_model.Position_Z}'
        except Exception as e:
            AppUtils.print_Exception(e)
            logINFO << AppUtils.toString(e)
        return RECODE_SUCCEED, focusing_b_z, focusing_e_z, focusing_status, focusing_model, isUpWard

    def getArrays(self, chamber_number: int, row_number: int, objective: int, **args) -> list[SlideModelInterface]:
        slide_model         : SlideModelInterface
        model               : SlideFocusingModel
        template_model      : ScanTemplate
        previewsettings     : Previewsettings
        collectsettings     : Collectsettings
        FocusPoints         : list[list[int]]
        IsSave              : int
        LState              : int
        RState              : int
        SpecimenNumber      : str
        SlideNumber         : str
        LineNumber          : str
        CodeString          : str
        template_id         : int
        MaxTrayRowNumber    : int
        MaxTrayColNumber    : int
        MinTrayRowNumber    : int
        MinTrayColNumber    : int
        ChamberGroupNumber  : int = chamber_number
        ChamberRowNumber    : int = row_number
        TrayNumber          : int = row_number
        models              : list[SlideFocusingModel] = []
        tray_model          : TrayModel             = TrayModel     .getConfig      (TrayNumber)
        Objective           : ObjectiveModel        = ObjectiveModel.getConfig      (objective)
        slide_model         = self.status.getChamberSlide(ChamberGroupNumber, ChamberRowNumber)
        if slide_model is None or tray_model is None or Objective is None:
            return models
        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
        tray_model.initTray(TrayNumber)
        LState                  = slide_model   .LState             #
        RState                  = slide_model   .RState             #
        SpecimenNumber          = slide_model   .SpecimenNumber     #
        SlideNumber             = slide_model   .SlideNumber        #
        LineNumber              = slide_model   .LineNumber         #
        CodeString              = slide_model   .CodeString         #
        MaxTrayRowNumber: int = tray_model.MaxRowNumber
        MaxTrayColNumber: int = tray_model.MaxColNumber
        if ObjectiveLevel.isMicronucleus(objective):
            MaxTrayRowNumber = tray_model.MaxRowNumber20X
            MaxTrayColNumber = tray_model.MaxColNumber20X
        MinTrayRowNumber        = tray_model    .MinRowNumber       #
        MinTrayColNumber        = tray_model    .MinColNumber       #
        previewClassifier       = PreviewClassifierModel.Classifier(previewsettings.classifier)
        collectClassifier       = CollectClassifierModel.Classifier(collectsettings.classifier)
        IsSave                  = previewsettings.is_save                       #
        template_id             = template_model.ID                             #
        Left                    = template_model.left
        Top                     = template_model.top
        Width                   = template_model.width
        Height                  = template_model.height
        focus_point_row         : int = template_model.focus_point_row
        focus_point_column      : int = template_model.focus_point_column

        self.status.setScanningSlide(ChamberGroupNumber, ChamberRowNumber, TrayNumber, objective, self.ScanLevel, template_id, CodeString)
        self.webserverevent.SendEvent(Request.APIInstance(WebAPILevel.pushTemplate))

        if not self.algorithm.hasScanSurface:
            self.algorithm.initScanSurface()

        FocusPoints           = self.algorithm.SlideFocusingArray(
            left            = max(Left       , MinTrayRowNumber)                             ,
            top             = max(Top        , MinTrayColNumber)                             ,
            width           = min(Width      , MaxTrayRowNumber)                             ,
            height          = min(Height     , MaxTrayColNumber)                             ,
            max_row         = MaxTrayRowNumber + 1                                           ,
            max_col         = MaxTrayColNumber + 1                                           ,
            focus_rows      = max(3                         , focus_point_row   )            ,
            focus_cols      = max(3                         , focus_point_column)            ,
            re_row_col      =   previewsettings.path_mode == 1
        )
        models = SlideFocusingModel.getFocusingItems(tray_model, FocusPoints, ChamberGroupNumber, ChamberRowNumber, objective, IsSave)
        self.algorithm.scansurface.initAlgorithm(MinTrayRowNumber       , MinTrayColNumber      ,
                                                 MaxTrayRowNumber + 1   , MaxTrayColNumber + 1  ,
                                                 float(Objective.Focus_Lower_Limit)             ,
                                                 float(Objective.Focus_Upper_Limit)             )
        for index, item in enumerate(models):
            item.ID                         = None                   #
            item.Focusing                   = None                   #
            item.Level                      = self.ScanLevel         #
            item.ChamberGroupNumber         = ChamberGroupNumber     #
            item.ChamberRowNumber           = ChamberRowNumber       #
            item.TrayNumber                 = TrayNumber             #
            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      #
            item.Position_Z                 = Objective.Focus_Lower_Limit  #
        return models

    def update_algorithm_points(self, min_z: int, max_z: int, slide: SlideModelInterface):
        if isinstance(slide, SlideModelInterface) and int(min_z) <= int(slide.Position_Z) <= int(max_z):
            self.algorithm.scansurface.append_point(slide.RowNumber, slide.ColNumber, slide.Position_Z)


    def begin_algorithm_points(self, min_z: int, max_z: int, slide: SlideModelInterface):
        if isinstance(slide, SlideModelInterface) and int(min_z) <= int(slide.Position_Z) <= int(max_z):
            self.algorithm.scansurface.set_begin_point(slide.RowNumber, slide.ColNumber, slide.Position_Z)

    def get_grid_location(self, item: SlideModelInterface, grids: list[list[int]]) -> int:
        point: list[int] = [item.RowNumber, item.ColNumber]
        location: int = GridLocation.Center
        for index, grid in enumerate(grids):
            if point in grid:
                location = index
                break
        return location
    def changed_focusing_item_point(self, item: SlideModelInterface, grids: list[list[int]]) -> SlideModelInterface:
        location: int = self.get_grid_location(item, grids)
        row: int
        col: int
        if   location == GridLocation.LeftTop    :
            row = item.RowNumber + 1
            col = item.ColNumber + 1
        elif location == GridLocation.Top        :
            row = item.RowNumber
            col = item.ColNumber + 1
        elif location == GridLocation.RightTop   :
            row = item.RowNumber - 1
            col = item.ColNumber + 1
        elif location == GridLocation.Left       :
            row = item.RowNumber + 1
            col = item.ColNumber
        elif location == GridLocation.Center     :
            if item.RowNumber % 2 == 0 and item.ColNumber % 2 == 0:
                row = item.RowNumber - 1
                col = item.ColNumber - 1
            elif item.RowNumber % 2 == 1 and item.ColNumber % 2 == 0:
                row = item.RowNumber + 1
                col = item.ColNumber
            elif item.RowNumber % 2 == 0 and item.ColNumber % 2 == 1:
                row = item.RowNumber
                col = item.ColNumber + 1
            elif item.RowNumber % 2 == 1 and item.ColNumber % 2 == 1:
                row = item.RowNumber + 1
                col = item.ColNumber + 1
            else:
                row = item.RowNumber + 1
                col = item.ColNumber + 1
        elif location == GridLocation.Right      :
            row = item.RowNumber - 1
            col = item.ColNumber
        elif location == GridLocation.LeftBottom :
            row = item.RowNumber + 1
            col = item.ColNumber - 1
        elif location == GridLocation.Bottom     :
            row = item.RowNumber
            col = item.ColNumber - 1
        elif location == GridLocation.RightBottom:
            row = item.RowNumber - 1
            col = item.ColNumber - 1
        else:
            row = item.RowNumber + 1
            col = item.ColNumber + 1
        model: SlideFocusingModel = item.copy()
        model.asObject(item)
        model.RowNumber = row
        model.ColNumber = col
        SlideFocusingModel.setModelPosition(item.SlideTable, model)
        return model


    def get_grid_locations(self, template_model: ScanTemplate) -> list[list[int]]:
        left                    = template_model.left           #
        top                     = template_model.top            #
        width                   = template_model.width          #
        height                  = template_model.height         #

        space_x: int = int(width    / 3)
        space_y: int = int(height   / 3)

        LeftTop     : list[list[int]] = []
        Top         : list[list[int]] = []
        RightTop    : list[list[int]] = []
        Left        : list[list[int]] = []
        Center      : list[list[int]] = []
        Right       : list[list[int]] = []
        LeftBottom  : list[list[int]] = []
        Bottom      : list[list[int]] = []
        RightBottom : list[list[int]] = []


        row: int
        col: int
        for row in range(left, left + space_x):
            for col in range(top, top + space_y):
                LeftTop.append([row, col])

            for col in range(top + space_y, top + space_y + space_y):
                Left.append([row, col])

            for col in range(top + space_y + space_y, top + height):
                LeftBottom.append([row, col])

        for row in range(left + space_x, left + space_x + space_x):
            for col in range(top, top + space_y):
                Top.append([row, col])

            for col in range(top + space_y, top + space_y + space_y):
                Center.append([row, col])

            for col in range(top + space_x + space_y, top + height):
                Bottom.append([row, col])
        for row in range(left + space_x + space_x, left + width):
            for col in range(top, top + space_y):
                RightTop.append([row, col])

            for col in range(top + space_y, top + space_y + space_y):
                Right.append([row, col])

            for col in range(top + space_y + space_y, top + height):
                RightBottom.append([row, col])

        return [LeftTop     ,Top         ,RightTop    ,Left        ,Center      ,Right       ,LeftBottom  ,Bottom      ,RightBottom]
