#!D:/IDE/anaconda3/envs/Microscope_Scan python
# -*- coding: UTF-8 -*-
"""
@FileName：SlideOilingBusiness.py
@Description：
@Author：XSH
@Time：2025/11/15 13:02
@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 SlideOilingBusiness(Qt.QObject, AppBusinessController):
    def __init__(self, parent: AppBusinessInterface = None):
        super(SlideOilingBusiness, self).__init__(parent=parent if parent is not None else parent.m_Control)
        self.initialize()
        self.ScanLevel = ScanStatusLevel.OilDripping_Status
        self.initModules(parent)

    def initScanLevel(self):
        self.ScanLevel = ScanStatusLevel.OilDripping_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

    @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.SlideOiling(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.SlideOiling(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 SlideOiling(self, chamber_number: int, row_number: int, isSafe: bool = False, **args) -> int:
        isWrong: int = RECODE_FAILURE
        if not self.isAvailable:
            return isWrong
        OilSlideActions     : list[SlideModel]
        begin_action        : SlideModel
        """默认10倍物镜"""
        tray_number         : int = TrayLevel.getTrayNumber(row_number)
        low_objective: int = ObjectiveLevel.Objective10
        hig_objective: int = ObjectiveLevel.Objective100
        """获取当前玻片的数据模型 和是否使用黑白模式  """
        classifier = self.getChamberSlideClassifier(chamber_number, row_number)
        self.ChangedScanningStatus(chamber_number, row_number, self.ScanLevel, low_objective)
        """如果当前模式为彩色模式 则说明是微核 不用滴油 直接退出"""
        if self.isMicronucleus(classifier):
            """添加玻片到已经扫描的表中"""
            self.finishAnointing(chamber_number, row_number, tray_number)
            return RECODE_SUCCEED
        """处理扫描状态: 暂停 退出 跳过"""
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            self.finishAnointing(chamber_number, row_number, tray_number)
            return RECODE_SUCCEED
        isWrong = self.readyOiling(chamber_number, row_number, tray_number, low_objective, isSafe)
        if RECODE_SUCCEED != isWrong:
            """添加玻片到已经扫描的表中"""
            self.finishAnointing(chamber_number, row_number, tray_number)
            return isWrong
        """处理扫描状态: 暂停 退出 跳过"""
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            self.finishAnointing(chamber_number, row_number, tray_number)
            return RECODE_SUCCEED



        isWrong = self.oiling(chamber_number, row_number, tray_number, low_objective, **args)

        if RECODE_SUCCEED != isWrong:
            """添加玻片到已经扫描的表中"""
            self.finishAnointing(chamber_number, row_number, tray_number)
            return isWrong
        """处理扫描状态: 暂停 退出 跳过"""
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            self.finishAnointing(chamber_number, row_number, tray_number)
            return RECODE_SUCCEED
        self.ChangedScanningStatus(chamber_number, row_number, self.ScanLevel, hig_objective)
        isWrong = self.readyAnointing(chamber_number, row_number, tray_number, low_objective, hig_objective, **args)
        if RECODE_SUCCEED != isWrong:
            """添加玻片到已经扫描的表中"""
            self.finishAnointing(chamber_number, row_number, tray_number)
            return isWrong
        """处理扫描状态: 暂停 退出 跳过"""
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            self.finishAnointing(chamber_number, row_number, tray_number)
            return RECODE_SUCCEED

        isWrong = self.anointing(chamber_number, row_number, tray_number, low_objective, hig_objective, **args)

        """处理扫描状态: 暂停 退出 跳过"""
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            self.finishAnointing(chamber_number, row_number, tray_number)
            return RECODE_SUCCEED
        """添加玻片到已经扫描的表中"""
        self.status.setSlideTableAlreadyScanned(tray_number)
        self.finishAnointing(chamber_number, row_number, tray_number)
        return isWrong

    def finishAnointing(self, chamber_number: int, row_number: int, tray_number: int):
        """准备涂抹镜油"""
        """设置光源100倍物镜光源"""
        self.save_specimen(chamber_number, row_number, tray_number)
        self.manipulator.reload_axis_speed()
        self.motion.microscope.changedLightIntensity(ObjectiveLevel.ObjectiveNone)
        return RECODE_SUCCEED



    def readyOiling(self, chamber_number: int, row_number: int, tray_number: int, objective: int, isSafe: bool = True) -> int:
        """准备滴油"""
        isWrong                     : int = RECODE_FAILURE
        if not self.isAvailable:
            return isWrong
        OilSlideSlides      : list[SlideModel]                                   #
        FrontPoint          : SlideModel                                         #
        Anointing            : AnointingModel                                     #
        """处理扫描状态: 暂停 退出 跳过"""
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            return RECODE_SUCCEED
        """如果不能找到模板 则直接退出"""
        template, Preview, Collect = self.status.getSlideScanTemplate(chamber_number, row_number)
        if template is None or Preview is None or Collect is None:
            return isWrong
        """获取所有核型小图的点"""
        CellArrays: list[CellModel] = CellModel.all()
        CellCount: int = len(CellArrays) if isinstance(CellArrays, list) else 0
        """如果没有识别到细胞 直接退出"""
        if CellCount <= 0:
            self.sendMessage(f"{chamber_number}号片仓{row_number}行玻片没有识别到细胞")
            return RECODE_FAILURE
        """如果核型数量小于预设的最小数量"""
        try:
            if CellCount <= Preview.warning_value and Preview.warning_value > 0:
                if not Preview.is_warning_scan:
                    self.sendMessage(f"{chamber_number}号片仓{row_number}行玻片细胞数量{CellCount}小于预警值{Preview.warning_value} 不进行高倍扫描")
                    return RECODE_FAILURE
        except Exception as e:
            AppUtils.print_Exception(e)

        Objective   : ObjectiveModel = ObjectiveModel.getObjectiveConfig(objective)
        Anointing   = AnointingModel.getConfig(objective)
        FrontPoint  , OilSlideSlides = self.getOilingArrays(chamber_number, row_number, tray_number, objective)
        if not isinstance(FrontPoint, SlideModelInterface) or not isinstance(OilSlideSlides, list) or len(OilSlideSlides) <= 0:
            return isWrong
        Position_X: float = FrontPoint.Position_X
        Position_Y: float = FrontPoint.Position_Y
        Position_Z: float = Anointing.OilDaub_Position
        """初始化Z轴范围"""
        self.microscope.init_z_range()
        """设置Z轴移动速度"""
        self.microscope.set_z_speed(Objective.Default_Speed)
        isWrong, position = self.microscope.get_position_z()
        if RECODE_SUCCEED != isWrong or not isinstance(position, (int, float)) or int(position) < Objective.Safe_Limit:
            isWrong = self.motion.waitmove_drop_scanning_xy(Position_X, Position_Y)
            if RECODE_SUCCEED != isWrong:
                return isWrong
            self.microscope.waitmove_z(Objective.Safe_Limit)

        isWrong = self.microscope.waitmove_z(Position_Z)
        if RECODE_SUCCEED != isWrong:
            return isWrong
        old_objective   : int
        _, old_objective = self.microscope.get_objective()
        ObjectiveConfig1: ObjectiveModel = ObjectiveModel.getConfig(ObjectiveLevel.Objective1)
        if RECODE_SUCCEED != _ or old_objective != objective:
            self.microscope.waitmove_z(ObjectiveConfig1.Safe_Limit)
            _ = self.microscope.changedObjective(level=objective, is_lower_limit=False)
        if RECODE_SUCCEED != _:
            AppTimeLoop.processEvents(500)
            _, _objective = self.microscope.get_objective()
            if not isinstance(_objective, int) or _objective != objective:
                return isWrong
        self.manipulator.reload_axis_speed()
        isWrong = self.motion.waitmove_drop_scanning_xy(Position_X, Position_Y)
        if RECODE_SUCCEED != isWrong:
            return isWrong
        self.microscope.changedLightIntensity(Objective.Level, isChanged=True)
        self.manipulator.waitmove_xy(Position_X, Position_Y)

        _, _objective = self.microscope.get_objective()
        if RECODE_SUCCEED != _ or _objective != objective:
            AppTimeLoop.processEvents(500)
            _, _objective = self.microscope.get_objective()

        return RECODE_SUCCEED if _objective == objective and RECODE_SUCCEED == _ else RECODE_FAILURE


    def oiling(self, chamber_number: int, row_number: int, tray_number: int, objective: int, **args) -> int:
        """玻片滴油"""
        from AppLog.logHelper import logSCANNING
        isWrong                 : int = RECODE_FAILURE
        if not self.isAvailable:
            return isWrong
        FrontOilPoint                   : SlideModelInterface                                                       #
        DropOilSlides                   : list[SlideModelInterface]                                                 #
        FrontOilPoint, DropOilSlides = self.getOilingArrays(chamber_number, row_number, tray_number, objective, True)
        if not isinstance(FrontOilPoint, SlideModelInterface) or not isinstance(DropOilSlides, list) or len(DropOilSlides) <= 0:
            return isWrong
        Anointing                       : AnointingModel    = AnointingModel.getConfig(objective)
        OilDropingSpeed                 : float             = Anointing.OilDropingSpeed                 #   滴油油泵速度
        OilDaub_Position                : float             = Anointing.OilDaub_Position                #   滴油Z轴位置
        OilTimes                        : float                                                         #   滴油时间
        FinishWaitTimes                 : float                                                         #   滴油完成等待时间
        ClearOilPosition                : float                                                         #   滴油后清油的Z轴位置
        OilingStatus                    : int                                                           #   滴油后油管状态
        OilEndTime                      : Qt.QDateTime                                                  #
        Position_X                      : float  = FrontOilPoint.Position_X                             #
        Position_Y                      : float  = FrontOilPoint.Position_Y                             #
        Position_Z                      : float  = OilDaub_Position                                     #
        OilWaitTimes                    : int    #
        logSCANNING << f"滴油位置 x: {Position_X} y: {Position_Y} z: {Anointing.OilDaub_Position} row: {FrontOilPoint.RowNumber} col: {FrontOilPoint.ColNumber}"
        """处理扫描状态: 暂停 退出 跳过"""
        Anointing = AnointingModel.getConfig(objective)  #
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            return RECODE_SUCCEED
        """设置滴油速度"""
        self.startOilDripping(OilDropingSpeed)
        AppTimeLoop.processEvents(100)
        """移动Z轴到滴油位置"""
        self.microscope.set_z_upper_limit(Anointing.ClearOil_Position)
        isWrong = self.microscope.waitmove_z(Position_Z)
        if RECODE_SUCCEED != isWrong:
            return isWrong
        self.manipulator.reload_oil_speed()
        self.motion.waitmove_drop_scanning_xy(Position_X, Position_Y)

        """滴油动作"""
        for index, Action in enumerate(DropOilSlides):
            """处理扫描状态: 暂停 退出 跳过"""
            SCANNING_STATUS = self.process_scanning_status()
            if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
                break
            Anointing                   = AnointingModel.getConfig(objective)       #
            OilTimes                    = Anointing.OilDropingTimes                 #   滴油时间
            FinishWaitTimes             = Anointing.OilDropingFinishWaitTimes       #   滴油完成等待时间
            Action.Position_Z           = Anointing.OilDaub_Position                #   滴油Z轴位置
            """移动Z到滴油位置"""
            self.motion.waitmove_drop_scanning_xy(Action.Position_X, Action.Position_Y)
            _, Position_Z = self.microscope.get_position()
            if RECODE_SUCCEED == _ and Float(round(Position_Z, 1)) != float(round(OilDaub_Position, 1)):
                self.microscope.waitmove_z(OilDaub_Position)
            """打开油泵并等待一定时长后关闭"""
            self.oilDripping(OilTimes, FinishWaitTimes)
            """处理扫描状态: 暂停 退出 跳过"""
            SCANNING_STATUS = self.process_scanning_status()
            if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
                break

        ClearOilPosition    = Anointing.ClearOil_Position           # 滴油后清油的Z轴位置
        Position_X          = FrontOilPoint.Position_X              #
        Position_Y          = FrontOilPoint.Position_Y              #
        Position_Z          = Anointing.OilDaub_Position            #
        try:
            # self.microscope.set_objective(ObjectiveLevel.Objective1)
            isWrong = self.motion.waitmove_drop_scanning_xy(Position_X, Position_Y)
            if RECODE_SUCCEED == isWrong:
                self.microscope.waitmove_z(ClearOilPosition)
                AppTimeLoop.processEvents(500)

        except Exception as e:
            AppUtils.print_Exception(e)

        isWrong = self.microscope.waitmove_z(Position_Z)
        # if RECODE_SUCCEED == isWrong:
        #     self.microscope.set_objective(objective)
        return isWrong

    def readyAnointing(self, chamber_number: int, row_number: int, tray_number: int, low_objective: int, hig_objective: int, **args) -> int:
        isWrong: int = RECODE_FAILURE
        if not self.isAvailable:
            return isWrong
        Position_X              : float
        Position_Y              : float
        Position_Z              : float
        _objective              : int
        FrontPoint              : SlideModelInterface
        Objective               : ObjectiveModel = ObjectiveModel.getConfig(hig_objective)
        Anointing_Model         : AnointingModel = AnointingModel.getConfig(hig_objective)
        ObjectiveConfig1        : ObjectiveModel = ObjectiveModel.getConfig(ObjectiveLevel.Objective1)
        """获取滴油位置"""
        FrontPoint = self.getFrontOilingSlide(chamber_number, row_number, tray_number, low_objective, False)
        """如果滴油位置为None 退出"""
        if FrontPoint is None:
            return RECODE_FAILURE
        """处理扫描状态: 暂停 退出 跳过"""
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            return RECODE_SUCCEED
        Position_X = FrontPoint.Position_X
        Position_Y = FrontPoint.Position_Y
        Position_Z = Anointing_Model.OilDaub_Position
        """初始化Z轴范围"""
        self.microscope.init_z_range()
        """设置Z轴最大位置"""
        # self.microscope.set_z_upper_limit(Anointing_Model.OilDaub_Position + 10000)
        self.microscope.set_z_speed(Objective.Default_Speed)
        _, _objective = self.microscope.get_objective()
        if RECODE_SUCCEED != _ or _objective != hig_objective:
            # 移动Z轴到6mm安全位置
            self.microscope.waitmove_z(ObjectiveConfig1.Safe_Limit)
            self.manipulator.waitmove_xy(Position_X, Position_Y)
            _ = self.microscope.set_objective(level=hig_objective, is_lower_limit=False)

        if RECODE_SUCCEED != _:
            AppTimeLoop.processEvents(500)
            _, _objective = self.microscope.get_objective()
            if not isinstance(_objective, int) or _objective != hig_objective:
                return isWrong
        self.microscope.set_objective_dip()
        """设置光源参数为空的光源 防止100倍光源太强 刺眼"""
        self.microscope.changedLightIntensity(ObjectiveLevel.ObjectiveNone, isChanged=True)
        self.manipulator.reload_axis_speed()
        self.manipulator.waitmove_xy(Position_X, Position_Y)
        self.microscope.waitmove_z(Position_Z)
        _, _objective = self.microscope.get_objective()
        if RECODE_SUCCEED != _ or _objective != hig_objective:
            AppTimeLoop.processEvents(500)
            _, _objective = self.microscope.get_objective()
        return RECODE_SUCCEED if _objective == hig_objective and RECODE_SUCCEED == _ else RECODE_FAILURE

    def anointing(self, chamber_number: int, row_number: int, tray_number: int, low_objective: int, hig_objective: int, **args) -> int:
        isWrong: int = RECODE_FAILURE
        if not self.isAvailable:
            return isWrong
        Position_X              : float                                                         #
        Position_Y              : float                                                         #
        Position_Z              : float                                                         #
        _objective              : int                                                           #
        FrontPoint              : SlideModelInterface                                           #
        AnointingArrays1        : list[SlideModel]                                              #
        AnointingArrays2        : list[SlideModel]                                              #
        AnointingArrays1_       : list[SlideModel]                                              #
        AnointingArrays2_       : list[SlideModel]                                              #
        AnointingTimes          : int                                                           # 移动暂停时长
        Anointing               : AnointingModel    = AnointingModel.getConfig(hig_objective)   #
        """获取滴油位置"""
        FrontPoint = self.getFrontOilingSlide(chamber_number, row_number, tray_number, low_objective, False)
        """如果滴油位置为None 退出"""
        if FrontPoint is None:
            return RECODE_FAILURE
        """处理扫描状态: 暂停 退出 跳过"""
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
            return RECODE_SUCCEED
        Position_X = FrontPoint.Position_X
        Position_Y = FrontPoint.Position_Y
        Position_Z = FrontPoint.Position_Z
        AnointingArrays1, AnointingArrays2 = self.getAnointingArrays(chamber_number, row_number, tray_number, hig_objective)
        if not isinstance(AnointingArrays1, list) or len(AnointingArrays1) <= 0:
            return RECODE_FAILURE
        if not isinstance(AnointingArrays2, list) or len(AnointingArrays2) <= 0:
            return RECODE_FAILURE
        AnointingCount      : int   = max(1, abs(int(Anointing.AnointingCount)))            # 涂抹镜油次数
        AnointingPosition_Z : float = Anointing.OilDaub_Position                            # 涂抹镜油高度
        self.manipulator.waitmove_xy(Position_X, Position_Y)
        self.microscope .waitmove_z (AnointingPosition_Z)
        """设置光源参数为空的光源 防止100倍光源太强 刺眼"""
        self.microscope.changedLightIntensity(ObjectiveLevel.ObjectiveNone, isChanged=True)
        self.manipulator.reload_anointing_speed()
        MaxCount: int = 5
        for count in range(0, MaxCount):
            """处理扫描状态: 暂停 退出 跳过"""
            SCANNING_STATUS = self.process_scanning_status()
            if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
                break
            Anointing               = AnointingModel.getConfig(hig_objective)
            if count >= AnointingCount:
                break
            AnointingCount          = Anointing.AnointingCount  # 涂抹镜油次数
            AnointingPosition_Z     = Anointing.OilDaub_Position  # 涂抹镜油高度
            AnointingTimes          = min(max(int(Anointing.AnointingTimes), 50), 1000)  # 移动暂停时长
            _, position_z           = self.microscope.get_position()
            if RECODE_SUCCEED != _ or Float(round(position_z, 1)) != float(round(position_z, 1)):
                self.microscope.waitmove_z(AnointingPosition_Z)

            if count % 2 == 0:
                AnointingArrays1_ = AnointingArrays1[::]
                AnointingArrays2_ = AnointingArrays2[::]
            else:
                AnointingArrays1_ = AnointingArrays2[::-1]
                AnointingArrays2_ = AnointingArrays1[::-1]
            for index, Action in enumerate(AnointingArrays1_):
                """处理扫描状态: 暂停 退出 跳过"""
                SCANNING_STATUS = self.process_scanning_status()
                if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
                    break
                """移动XY到起始位置"""
                self.motion.wait_anointing_scanning_xy(Action.Position_X, Action.Position_Y)
                """移动到位后停留一定时长"""
                AppTimeLoop.processEvents(AnointingTimes)
                """处理扫描状态: 暂停 退出 跳过"""
                SCANNING_STATUS = self.process_scanning_status()
                if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
                    break
            for index, Action in enumerate(AnointingArrays2_):
                """处理扫描状态: 暂停 退出 跳过"""
                SCANNING_STATUS = self.process_scanning_status()
                if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
                    break
                """移动XY到起始位置"""
                self.motion.wait_anointing_scanning_xy(Action.Position_X, Action.Position_Y)
                """移动到位后停留一定时长"""
                AppTimeLoop.processEvents(AnointingTimes)
                """处理扫描状态: 暂停 退出 跳过"""
                SCANNING_STATUS = self.process_scanning_status()
                if SCANNING_STATUS == RECODE_CHANGED or SCANNING_STATUS == RECODE_JUMPING:
                    break
        # self.microscope.waitmove_z(Position_Z)
        isWrong = self.manipulator.waitmove_xy(FrontPoint.Position_X, FrontPoint.Position_Y)
        return isWrong





    def getOilingArrays(self, chamber_number: int, row_number: int, tray_number: int, objective: int, isOffset: bool = True, **args) -> (SlideModelInterface, list[SlideModelInterface]):
        FrontPoint          : SlideModelInterface                                               #
        models              : list[SlideModelInterface]                                         #
        Anointing           : AnointingModel    = AnointingModel.getConfig(objective)           #
        tray_model          : TrayModel         = TrayModel.getConfig(tray_number)              #
        OffsetRowNumber     : int = 0                                                           #
        OffsetColNumber     : int = 0                                                           #
        DropingPoints       : list[list[int]]                                                   #
        middle              : list[int]                                                         #
        if isOffset:
            OffsetRowNumber      = Anointing.OffsetRowNumber
            OffsetColNumber      = Anointing.OffsetColNumber
        DropingPoints, middle = self.getOilArrays(chamber_number, row_number, tray_number, objective)
        models  = SlideModel.getOilDropingItems(tray_model, DropingPoints, OffsetRowNumber, OffsetColNumber, chamber_number, row_number, objective)
        _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, models


    def getFrontOilingSlide(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 getAnointingArrays(self, chamber_number: int, row_number: int, tray_number: int, objective: int) -> list[SlideModel]:
        AnointingModel1     : list[SlideModel] = []
        AnointingModel2     : list[SlideModel] = []
        AnointingPoints1    : list[list[int]]
        AnointingPoints2    : list[list[int]]
        middle              : list[int]
        Anointing           : AnointingModel = AnointingModel.getConfig(objective)
        OffsetRowNumber     : int = 0
        OffsetColNumber     : int = 0
        AnointingNumber     : int = Anointing.AnointingNumber
        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 AnointingModel1, AnointingModel2
        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   #
        AnointingRowNumber: int
        AnointingColNumber: int
        try:
            AnointingRowNumber, AnointingColNumber = self.algorithm.getAnointingPointCount(width, height)
        except Exception as e:
            AnointingRowNumber, AnointingColNumber = 4, 4
        AnointingPoints1, AnointingPoints2 = self.algorithm.SlideAnointingArray(
            left        =       max(left, MinRowNumber)             ,
            top         =       max(top , MinColNumber)             ,
            width       =       min(width , MaxRowNumber - left)    ,
            height      =       min(height, MaxColNumber - top )    ,
            max_row     =       MaxRowNumber + 4                    ,
            max_col     =       MaxColNumber + 4                    ,
            drop_rows   =       AnointingRowNumber                  ,
            drop_cols   =       AnointingColNumber                  )

        AnointingModel1 = SlideModel.getOilDropingItems(tray_model, AnointingPoints1, OffsetRowNumber, OffsetColNumber,chamber_number, row_number, objective)
        AnointingModel2 = SlideModel.getOilDropingItems(tray_model, AnointingPoints2, OffsetRowNumber, OffsetColNumber,chamber_number, row_number, objective)
        for item in AnointingModel1:
            item.Level                = ScanStatusLevel.OilDripping_Status
            item.ObjectiveLevel       = objective
            item.ChamberGroupNumber   = chamber_number
            item.ChamberRowNumber     = row_number
            item.TrayNumber           = tray_number
            item.Position_Z           = Anointing.OilDaub_Position

        for item in AnointingModel2:
            item.Level                = ScanStatusLevel.OilDripping_Status
            item.ObjectiveLevel       = objective
            item.ChamberGroupNumber   = chamber_number
            item.ChamberRowNumber     = row_number
            item.TrayNumber           = tray_number
            item.Position_Z           = Anointing.OilDaub_Position

        return AnointingModel1, AnointingModel2