#!D:/IDE/anaconda3/envs/Microscope_Scan python
# -*- coding: UTF-8 -*-
"""
@FileName：MotionReaderInterface.py
@Description：
@Author：XSH
@Time：2025/11/11 15:05
@Department：研发部
@Copyright：©2025 乐辰生物
"""
from PyQt5 import Qt
from abc import abstractmethod
from AppInterfaces.AppImplInterfaces.ModBusPoolInterface           import ModBusPoolInterface, ModBusImplInterface, ModBusRegister, ModBusContext
from AppInterfaces.AppImplInterfaces.AxisImplInterface             import AxisContext, AxisRegisterContext, AxisImplInterface, AxisLevel
from AppInterfaces.AppImplInterfaces.DetectionImplInterface        import DetectionImplInterface, DetectionContext, ModBusPoolInterface
from AppInterfaces.AppReaderInterfaces.ManipulatorReaderInterface  import ManipulatorReaderInterface, HookImplInterface
from AppInterfaces.AppReaderInterfaces.MicroscopeReaderInterface   import MicroscopeReaderInterface
from AppSettings.Settings   import *
from AppInterfaces.utils    import *
from AppCore.Levels         import *
from AppUtils.HardWareUnit import HardWareUnit
from AppInterfaces.ReaderInterface import ReaderInterface
class MotionReaderInterface(ReaderInterface):
    Manipulator :   ManipulatorReaderInterface  #
    Microscope  :   MicroscopeReaderInterface   #
    Manager     :   ModBusPoolInterface         #
    @property
    def hasManager(self) -> bool:
        return hasattr(self, 'Manager') and isinstance(self.Manager, ModBusPoolInterface)

    @property
    def manager(self) -> ModBusPoolInterface:
        return self.Manager if self.hasManager else None


    @property
    def manipulator(self) -> ManipulatorReaderInterface:
        return None if not self.hasManipulator else self.Manipulator

    @property
    def microscope(self) -> MicroscopeReaderInterface:
        return None if not self.hasMicroscope else self.Microscope


    @property
    def hasManipulator (self) -> bool:
        return hasattr(self, 'Manipulator') and isinstance(self.Manipulator , ManipulatorReaderInterface)

    @property
    def hasMicroscope  (self) -> bool:
        return hasattr(self, 'Microscope' ) and isinstance(self.Microscope  , MicroscopeReaderInterface )



    @abstractmethod
    def initManipulator (self):
        raise Exception('Interface Instance error')

    @abstractmethod
    def initMicroscope  (self):
        raise Exception('Interface Instance error')

    @property
    @abstractmethod
    def isAvailable(self) -> bool:
        raise Exception('Interface Instance error')

    @property
    @abstractmethod
    def isValid(self) -> bool:
        raise Exception('Interface Instance error')

    @property
    @abstractmethod
    def IsOpen(self) -> bool:
        raise Exception('Interface Instance error')

    @abstractmethod
    def Open(self, **args) -> int:
        raise Exception('Interface Instance error')

    @abstractmethod
    def Close(self, **args) -> int:
        raise Exception('Interface Instance error')

    @abstractmethod
    def initManager(self, **args):
        raise Exception('Interface Instance error')

    @abstractmethod
    def deleManager(self, **args):
        raise Exception('Interface Instance error')



    @property
    def axis_x(self) -> AxisImplInterface:
        return self.Manipulator.AxisX if self.hasAxisX else None

    @property
    def axis_y(self) -> AxisImplInterface:
        return self.Manipulator.AxisY if self.hasAxisY else None

    @property
    def axis_h(self) -> HookImplInterface:
        return self.Manipulator.AxisH if self.hasAxisH else None

    @property
    def scan_x(self) -> AxisImplInterface:
        return self.Manipulator.ScanX if self.hasScanX else None

    @property
    def scan_y(self) -> AxisImplInterface:
        return self.Manipulator.ScanY if self.hasScanY else None

    @property
    def slow_x(self) -> AxisImplInterface:
        return self.Manipulator.SlowX if self.hasSlowX else None

    @property
    def slow_y(self) -> AxisImplInterface:
        return self.Manipulator.SlowY if self.hasSlowY else None

    @property
    def drop_x(self) -> AxisImplInterface:
        return self.Manipulator.DropX if self.hasDropX else None

    @property
    def drop_y(self) -> AxisImplInterface:
        return self.Manipulator.DropY if self.hasDropY else None

    @property
    def axis_z(self) -> AxisImplInterface:
        return self.Manipulator.AxisZ if self.hasAxisZ else None

    @property
    def detector(self) -> DetectionImplInterface:
        return self.Detector if self.hasDetector else None

    @property
    def hasAxisX(self) -> bool:
        return False if not self.hasManipulator else self.Manipulator.hasAxisX

    @property
    def hasAxisY(self) -> bool:
        return False if not self.hasManipulator else self.Manipulator.hasAxisY

    @property
    def hasAxisH(self) -> bool:
        return False if not self.hasManipulator else self.Manipulator.hasAxisH

    @property
    def hasScanX(self) -> bool:
        return False if not self.hasManipulator else self.Manipulator.hasScanX

    @property
    def hasScanY(self) -> bool:
        return False if not self.hasManipulator else self.Manipulator.hasScanY

    @property
    def hasSlowX(self) -> bool:
        return False if not self.hasManipulator else self.Manipulator.hasSlowX

    @property
    def hasSlowY(self) -> bool:
        return False if not self.hasManipulator else self.Manipulator.hasSlowY

    @property
    def hasDropX(self) -> bool:
        return False if not self.hasManipulator else self.Manipulator.hasDropX

    @property
    def hasDropY(self) -> bool:
        return False if not self.hasManipulator else self.Manipulator.hasDropY

    @property
    def hasAxisZ(self) -> bool:
        return False if not self.hasManipulator else self.Manipulator.hasAxisZ

    def ReOpen(self, timeOut: int = 1000, **args) -> int:
        self.Close(timeOut=timeOut, **args)
        return self.Open(timeOut=timeOut, **args)


    def getPosition_z(self) -> (int, int):
        isWrong: int = RECODE_FAILURE
        position: int = 0
        if self.hasMicroscope:
            isWrong, position = self.Microscope.get_position()
        return isWrong, position


    def get_position_z(self) -> (int, int):
        isWrong: int = RECODE_FAILURE
        position: int = 0
        if self.hasMicroscope:
            isWrong, position = self.Microscope.get_position()
        return isWrong, position

    def get_position_xyzhm(self) -> (int, float, float, float, float, float, float):
        isWrong: int = RECODE_FAILURE
        x: float = None
        y: float = None
        z: float = None
        h: float = None
        m: float = None
        if self.hasManipulator:
            isWrong , x = self.manipulator.position_x()
            if RECODE_SUCCEED != isWrong:
                return isWrong, x, y, z, h, m
            isWrong , y = self.manipulator.position_y()
            if RECODE_SUCCEED != isWrong:
                return isWrong, x, y, z, h, m
            isWrong , z = self.manipulator.position_z()
            if RECODE_SUCCEED != isWrong:
                return isWrong, x, y, z, h, m
            isWrong , h = self.manipulator.position_h()
            if RECODE_SUCCEED != isWrong:
                return isWrong, x, y, z, h, m
        if self.hasMicroscope:
            isWrong, m = self.microscope.get_position()
        return isWrong, x, y, z, h, m


    def get_scanning_position_xyz(self) -> (int, float, float, float):
        isWrong: int = RECODE_FAILURE
        x: float = None
        y: float = None
        z: float = None
        if self.hasManipulator:
            isWrong , x = self.manipulator.position_x()
            if RECODE_SUCCEED != isWrong:
                return isWrong, x, y, z
            isWrong , y = self.manipulator.position_y()
            if RECODE_SUCCEED != isWrong:
                return isWrong, x, y, z
        if self.hasMicroscope:
            isWrong, z = self.microscope.get_position()
        return isWrong, x, y, z


    def stop_z(self) -> int:
        isWrong: int = RECODE_FAILURE
        if self.hasMicroscope:
            isWrong = self.microscope.stop_move()
        return isWrong


    def rel_move_z(self, value: (int, float), mode: int = 0, **args) -> int:
        isWrong: int = RECODE_FAILURE
        if self.hasMicroscope:
            isWrong = self.microscope.rel_move(value, mode, **args)
        return isWrong


    def waitmove_z(self, position: (int, float), mode: int = 1, **args) -> int:
        isWrong: int = RECODE_FAILURE
        if self.hasMicroscope:
            isWrong = self.microscope.waitmove(position, mode, **args)
        return isWrong


    def changedObjective(self, level: int, is_lower_limit: bool = False) -> int:
        isWrong: int = RECODE_FAILURE
        if self.hasMicroscope:
            isWrong = self.microscope.set_objective(level, is_lower_limit)
        return isWrong

    def set_objective(self, level: int, is_lower_limit: bool = False) -> int:
        isWrong: int = RECODE_FAILURE
        if self.hasMicroscope:
            isWrong = self.microscope.set_objective(level, is_lower_limit)
        return isWrong


    def getObjective(self) -> int:
        objective: int = ObjectiveLevel.Objective1
        if self.hasMicroscope:
            objective = self.microscope.getObjective()
        return objective

    def get_objective(self) -> (int, int):
        isWrong: int = RECODE_FAILURE
        objective: int = ObjectiveLevel.Objective1
        if self.hasMicroscope:
            isWrong, objective = self.microscope.get_objective()
        return isWrong, objective

    def currentObjective(self) -> (int, int):
        isWrong: int = RECODE_FAILURE
        objective: int = ObjectiveLevel.Objective1
        if self.hasMicroscope:
            isWrong, objective = self.microscope.get_objective()
        return isWrong, objective

    def changedLightIntensity(self, level: int) -> int:
        isWrong: int = RECODE_FAILURE
        if self.hasMicroscope:
            isWrong = self.microscope.changedLightIntensity(level)
        return isWrong

    def waitmove_scanning_xyz(self, x: (float, int), y: (float, int), z: (float, int)) -> (int, str):
        isWrong: int
        _xPosition: float = round(float(x), 3)
        _yPosition: float = round(float(y), 3)
        _zPosition: float = round(float(z), 3)
        xy_move_time: int
        z_move_time: int
        HardWareUnit.axis_move_enable_xy(self.Manipulator.scan_x, self.Manipulator.scan_y, False)
        begin: Qt.QDateTime = Qt.QDateTime.currentDateTime()
        z_Wrong         = self.microscope.waitmove(_zPosition)
        z_move_time     = begin.msecsTo(Qt.QDateTime.currentDateTime())
        isWrong = HardWareUnit.axis_scan_move_enable_xy(self.Manipulator.scan_x, self.Manipulator.scan_y, _xPosition, _yPosition)
        if RECODE_SUCCEED == isWrong:
            step1 = begin.msecsTo(Qt.QDateTime.currentDateTime()) - z_move_time
            xy_Wrong = HardWareUnit.axis_move_complete_xy   (self.Manipulator.scan_x, self.Manipulator.scan_y, _xPosition, _yPosition)
            step2 = begin.msecsTo(Qt.QDateTime.currentDateTime()) - step1
            isWrong = RECODE_SUCCEED if xy_Wrong == RECODE_SUCCEED and z_Wrong == RECODE_SUCCEED else RECODE_FAILURE
            xy_move_time = begin.msecsTo(Qt.QDateTime.currentDateTime()) - z_move_time
            info: str = f"移动X Y Z 耗时: {begin.msecsTo(Qt.QDateTime.currentDateTime())} {step1} {step2} ms xy_move_time: {xy_move_time} z_move_time: {z_move_time}"

        else:
            xy_move_time = begin.msecsTo(Qt.QDateTime.currentDateTime()) - z_move_time
            info: str = f"移动X Y Z 耗时: {begin.msecsTo(Qt.QDateTime.currentDateTime())} ms xy_move_time: {xy_move_time} z_move_time: {z_move_time}"
        return isWrong, info



    def waitmove_slow_scanning_xy(self, x: (float, int), y: (float, int)) -> (int, str):
        isWrong: int
        _xPosition: float = round(float(x), 3)
        _yPosition: float = round(float(y), 3)
        xy_move_time: int
        begin: Qt.QDateTime = Qt.QDateTime.currentDateTime()
        HardWareUnit.axis_move_enable_xy(self.Manipulator.slow_x, self.Manipulator.slow_y, False)
        isWrong = HardWareUnit.axis_scan_move_enable_xy(self.Manipulator.slow_x, self.Manipulator.slow_y, _xPosition, _yPosition)
        if RECODE_SUCCEED == isWrong:
            step1 = begin.msecsTo(Qt.QDateTime.currentDateTime())
            xy_Wrong = HardWareUnit.axis_move_complete_xy(self.Manipulator.slow_x, self.Manipulator.slow_y, _xPosition, _yPosition)
            step2 = begin.msecsTo(Qt.QDateTime.currentDateTime()) - step1
            isWrong = RECODE_SUCCEED if xy_Wrong == RECODE_SUCCEED else RECODE_FAILURE
            xy_move_time = begin.msecsTo(Qt.QDateTime.currentDateTime())
            info: str = f"移动X Y Z 耗时: {begin.msecsTo(Qt.QDateTime.currentDateTime())} {step1} {step2} ms xy_move_time: {xy_move_time}"

        else:
            xy_move_time = begin.msecsTo(Qt.QDateTime.currentDateTime())
            info: str = f"移动X Y Z 耗时: {begin.msecsTo(Qt.QDateTime.currentDateTime())} ms xy_move_time: {xy_move_time}"
        return isWrong, info


    def waitmove_slow_scanning_xyz(self, x: (float, int), y: (float, int), z: (float, int)) -> (int, str):
        isWrong: int
        _xPosition: float = round(float(x), 3)
        _yPosition: float = round(float(y), 3)
        _zPosition: float = round(float(z), 3)
        xy_move_time: int
        z_move_time: int
        begin: Qt.QDateTime = Qt.QDateTime.currentDateTime()
        HardWareUnit.axis_move_enable_xy(self.Manipulator.slow_x, self.Manipulator.slow_y, False)
        z_Wrong = self.microscope.waitmove(_zPosition)
        z_move_time = begin.msecsTo(Qt.QDateTime.currentDateTime())
        isWrong = HardWareUnit.axis_scan_move_enable_xy(self.Manipulator.slow_x, self.Manipulator.slow_y, _xPosition, _yPosition)
        if RECODE_SUCCEED == isWrong:
            step1 = begin.msecsTo(Qt.QDateTime.currentDateTime()) - z_move_time
            xy_Wrong = HardWareUnit.axis_move_complete_xy(self.Manipulator.slow_x, self.Manipulator.slow_y, _xPosition, _yPosition)
            step2 = begin.msecsTo(Qt.QDateTime.currentDateTime()) - step1
            isWrong = RECODE_SUCCEED if xy_Wrong == RECODE_SUCCEED and z_Wrong == RECODE_SUCCEED else RECODE_FAILURE
            xy_move_time = begin.msecsTo(Qt.QDateTime.currentDateTime()) - z_move_time
            info: str = f"移动X Y Z 耗时: {begin.msecsTo(Qt.QDateTime.currentDateTime())} {step1} {step2} ms xy_move_time: {xy_move_time} z_move_time: {z_move_time}"

        else:
            xy_move_time = begin.msecsTo(Qt.QDateTime.currentDateTime()) - z_move_time
            info: str = f"移动X Y Z 耗时: {begin.msecsTo(Qt.QDateTime.currentDateTime())} ms xy_move_time: {xy_move_time} z_move_time: {z_move_time}"
        return isWrong, info

    def waitmove_drop_scanning_xy(self, x: (float, int), y: (float, int)) -> int:
        isWrong         : int
        _xPosition      : float = round(float(x), 3)
        _yPosition      : float = round(float(y), 3)
        HardWareUnit.axis_move_enable_xy(self.Manipulator.drop_x, self.Manipulator.drop_y, False)
        isWrong = HardWareUnit.axis_scan_move_enable_xy(self.Manipulator.drop_x, self.Manipulator.drop_y, _xPosition, _yPosition)
        if RECODE_SUCCEED == isWrong:
            xy_Wrong = HardWareUnit.axis_move_complete_xy(self.Manipulator.drop_x, self.Manipulator.drop_y, _xPosition, _yPosition)
            isWrong = RECODE_SUCCEED if xy_Wrong == RECODE_SUCCEED  else RECODE_FAILURE
        return isWrong

    def wait_anointing_scanning_xy(self, x: (float, int), y: (float, int)) -> int:
        isWrong         : int
        _xPosition      : float = round(float(x), 3)
        _yPosition      : float = round(float(y), 3)
        HardWareUnit.axis_move_enable_xy(self.Manipulator.drop_x, self.Manipulator.drop_y, False)
        isWrong = HardWareUnit.axis_scan_move_enable_xy(self.Manipulator.drop_x, self.Manipulator.drop_y, _xPosition, _yPosition)
        if RECODE_SUCCEED == isWrong:
            xy_Wrong = HardWareUnit.axis_move_complete_xy(self.Manipulator.drop_x, self.Manipulator.drop_y, _xPosition, _yPosition)
            isWrong = RECODE_SUCCEED if xy_Wrong == RECODE_SUCCEED  else RECODE_FAILURE
        return isWrong


    def setScanMoveEnable(self, enable: (int, bool)):
        HardWareUnit.axis_move_enable_xy(self.Manipulator.scan_x, self.Manipulator.scan_x, enable)


    def setMoveEnable(self, enable: (int, bool)):
        HardWareUnit.axis_move_enable_xy(self.Manipulator.axis_x, self.Manipulator.axis_y, enable)

    def setSlowEnable(self, enable: (int, bool)):
        HardWareUnit.axis_move_enable_xy(self.Manipulator.slow_x, self.Manipulator.slow_y, enable)

