#!D:/IDE/anaconda3/envs/Microscope_Scan python
# -*- coding: UTF-8 -*-
"""
@FileName：CameraImplInterface.py
@Description：
@Author：XSH
@Time：2025/11/11 12:53
@Department：研发部
@Copyright：©2025 乐辰生物
"""
from abc import abstractmethod
from pypylon import pylon
import numpy as np
import cv2
from AppInterfaces.ImplInterface import ImplInterface
from AppContexts.Contexts import CameraContext
from AppUtils import AppUtils


class CameraImplInterface(ImplInterface):
    Devices                 : list[pylon.DeviceInfo]    #
    Manager                 : pylon.InstantCamera       #
    DeviceInfo              : pylon.DeviceInfo          #
    TlFactory               : pylon.TlFactory           #
    Parameter               : CameraContext             #
    Model                   : 'CameraInterface'         #
    Level                   : int




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

    @property
    def parameter(self) -> CameraContext:
        return None if not self.hasParameter else self.Parameter

    @property
    def level(self) -> int:
        return 7 if not self.hasLevel else self.Level


    @property
    def hasDevices                 (self) -> bool:
        return hasattr(self, 'Devices'    ) and isinstance(self.Devices                 , (tuple, list)                      )

    @property
    def device_size(self) -> int:
        return 0 if not self.hasDevices else len(self.Devices)

    @property
    def hasManager                 (self) -> bool:
        return hasattr(self, 'Manager'    ) and isinstance(self.Manager                 , pylon.InstantCamera       )

    @property
    def hasDeviceInfo              (self) -> bool:
        return hasattr(self, 'DeviceInfo' ) and isinstance(self.DeviceInfo              , pylon.DeviceInfo          )

    @property
    def hasTlFactory               (self) -> bool:
        return hasattr(self, 'TlFactory'  ) and isinstance(self.TlFactory               , pylon.TlFactory           )

    @property
    def hasLevel(self) -> bool:
        return hasattr(self, 'Level') and isinstance(self.Level, int)

    @property
    def hasParameter               (self) -> bool:
        return hasattr(self, 'Parameter'  ) and isinstance(self.Parameter               , CameraContext             )

    @property
    def hasModel                   (self) -> bool:
        return hasattr(self, 'Model'      ) and self.Model is not None

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    @abstractmethod
    def waitForStopGrabbing(self, waittimes: int = 3000) -> bool:
        raise Exception('Interface Instance error')

    @abstractmethod
    def waitForClose(self, waittimes: int = 3000) -> bool:
        raise Exception('Interface Instance error')

    @abstractmethod
    def waitForFindDevice(self, waittimes: int = 3000) -> bool:
        raise Exception('Interface Instance error')

    @abstractmethod
    def waitForDeviceOpen(self, waittimes: int = 3000) -> bool:
        raise Exception('Interface Instance error')

    @abstractmethod
    def setModel(self, level: int):
        raise Exception('Interface Instance error')


    @abstractmethod
    def setPixelParameter(self, level: int):
        raise Exception('Interface Instance error')

    @abstractmethod
    def changedObjective(self, level: int, timeOut: int = 1000):
        raise Exception('Interface Instance error')

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

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


    @abstractmethod
    def GetNumpy(self, classifier: str = 'Aberration', **args) -> np.ndarray:
        raise Exception('Interface Instance error')

    @abstractmethod
    def StartFocusing(self, level: int, timeOut: int = 1000, **args):
        raise Exception('Interface Instance error')

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

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

    @abstractmethod
    def GetFocusingNumpy(self, classifier: str = 'Aberration', **args) -> np.ndarray:
        raise Exception('Interface Instance error')

    @abstractmethod
    def GetFocusingData(self, classifier: str = 'Aberration', **args) -> np.ndarray:
        raise Exception('Interface Instance error')

    @abstractmethod
    def GetRequestData(self, request: ('CameraRequest', 'SlideModelInterface'), classifier: str = 'Aberration', **args) -> int:
        raise Exception('Interface Instance error')

    @abstractmethod
    def GetNumpyData(self, classifier: str = 'Aberration', **args) -> np.ndarray:
        raise Exception('Interface Instance error')

    @abstractmethod
    def GetRequest(self, request: ('CameraRequest', 'SlideModelInterface'), classifier: str = 'Aberration', **args) -> int:
        raise Exception('Interface Instance error')

    @abstractmethod
    def RequestMultiple(self, parameter: 'CameraInterface', ExposureTimes: list[int], **args) -> list[np.ndarray]:
        raise Exception('Interface Instance error')

    @abstractmethod
    def RequestMultipleArray(self, parameter: 'CameraInterface', ExposureTimes: list[int], ImageArray: list[np.ndarray], **args):
        raise Exception('Interface Instance error')

    @abstractmethod
    def RequestNumpy(self, parameter: 'CameraInterface', classifier: str = 'Aberration', **args) -> np.ndarray:
        raise Exception('Interface Instance error')

    @abstractmethod
    def RequestMultipleImage(self, parameter: 'CameraInterface', ExposureTime: int, **args) -> np.ndarray:
        raise Exception('Interface Instance error')

    @abstractmethod
    def RequestMultipleNumpy(self, parameter: 'CameraInterface', ExposureTimes: list[int], **args) -> list[np.ndarray]:
        raise Exception('Interface Instance error')

    @abstractmethod
    def RequestMultipleNumpyArray(self, parameter: 'CameraInterface', ExposureTimes: list[int], ImageArray: list[np.ndarray], **args) -> list[np.ndarray]:
        raise Exception('Interface Instance error')

    @abstractmethod
    def CameraRequest(self, model: ('CameraRequest', 'SlideModelInterface'), parameter: 'CameraInterface', classifier: str = 'Aberration', **args):
        raise Exception('Interface Instance error')

    @abstractmethod
    def setGain(self, value):
        raise Exception('Interface Instance error')

    @abstractmethod
    def setGamma(self, value):
        raise Exception('Interface Instance error')

    @abstractmethod
    def setExposureTime(self, value):
        raise Exception('Interface Instance error')

    @abstractmethod
    def setImageROI(self, offsetX, offsetY, width, height, CenterX: bool = True, CenterY: bool = True):
        raise Exception('Interface Instance error')

    @abstractmethod
    def setPixelFormat(self, value: int):
        raise Exception('Interface Instance error')

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

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

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


    @staticmethod
    def ImageToColor(image: np.ndarray, pixel_fmt: str, isMono: bool = False) -> np.ndarray:
        img: np.ndarray = None
        try:
            if pixel_fmt == 'Mono8':
                img = cv2.cvtColor(image, cv2.COLOR_GRAY2RGB)
            elif pixel_fmt == 'BayerGR8':
                if isMono:
                    img = cv2.cvtColor(image, cv2.COLOR_BAYER_GR2GRAY)
                else:
                    img = cv2.cvtColor(image, cv2.COLOR_BAYER_GR2RGB)

            elif pixel_fmt == 'BayerRG8':
                if isMono:
                    img = cv2.cvtColor(image, cv2.COLOR_BAYER_RG2GRAY)
                else:
                    img = cv2.cvtColor(image, cv2.COLOR_BAYER_RG2RGB)
            elif pixel_fmt == 'BayerGB8':
                if isMono:
                    img = cv2.cvtColor(image, cv2.COLOR_BAYER_GB2GRAY)
                else:
                    img = cv2.cvtColor(image, cv2.COLOR_BAYER_BG2RGB)

            elif pixel_fmt == 'BayerBG8':
                if isMono:
                    img = cv2.cvtColor(image, cv2.COLOR_BAYER_BG2GRAY)
                else:
                    img = cv2.cvtColor(image, cv2.COLOR_BAYER_BG2RGB)

            elif pixel_fmt == 'BayerGR12':
                if isMono:
                    img = cv2.cvtColor(image, cv2.COLOR_BAYER_GR2GRAY)
                else:
                    img = cv2.cvtColor(image, cv2.COLOR_BAYER_GR2RGB)

            elif pixel_fmt == 'BayerGR12p':
                if isMono:
                    img = cv2.cvtColor(image, cv2.COLOR_BAYER_GR2GRAY)
                else:
                    img = cv2.cvtColor(image, cv2.COLOR_BAYER_GR2RGB)

            elif pixel_fmt == 'BayerRG12':
                if isMono:
                    img = cv2.cvtColor(image, cv2.COLOR_BAYER_RG2GRAY)
                else:
                    img = cv2.cvtColor(image, cv2.COLOR_BAYER_RG2RGB)

            elif pixel_fmt == 'BayerRG12p':
                if isMono:
                    img = cv2.cvtColor(image, cv2.COLOR_BAYER_RG2GRAY)
                else:
                    img = cv2.cvtColor(image, cv2.COLOR_BAYER_RG2RGB)

            elif pixel_fmt == 'BayerGB12':
                if isMono:
                    img = cv2.cvtColor(image, cv2.COLOR_BAYER_GB2GRAY)
                else:
                    img = cv2.cvtColor(image, cv2.COLOR_BAYER_GB2RGB)

            elif pixel_fmt == 'BayerGB12p':
                if isMono:
                    img = cv2.cvtColor(image, cv2.COLOR_BAYER_GB2GRAY)
                else:
                    img = cv2.cvtColor(image, cv2.COLOR_BAYER_GB2RGB)


            elif pixel_fmt == 'BayerBG12':
                if isMono:
                    img = cv2.cvtColor(image, cv2.COLOR_BAYER_BG2GRAY)
                else:
                    img = cv2.cvtColor(image, cv2.COLOR_BAYER_BG2RGB)

            elif pixel_fmt == 'BayerBG12p':
                if isMono:
                    img = cv2.cvtColor(image, cv2.COLOR_BAYER_BG2GRAY)
                else:
                    img = cv2.cvtColor(image, cv2.COLOR_BAYER_BG2RGB)

            elif pixel_fmt == 'RGB8':
                if isMono:
                    img = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
                else:
                    img = image

            elif pixel_fmt == 'BGR8':
                if isMono:
                    img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
                else:
                    img = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

            if img is not None and len(img.shape) <= 2:
                img = np.stack((img,) * 3, axis=-1)
        except Exception as e:
            AppUtils.print_Exception(e)

        return img

    @classmethod
    def ChangedCameraExposureTime(cls, camera: pylon.InstantCamera, ExposureTime: int, model = None):

        try:
            if not camera.IsOpen():
                return
            IsGrabbing = camera.IsGrabbing()
            try:
                camera.ExposureTime.Value = int(ExposureTime)  # 曝光时间
                from AppCore.AppDBModels.CameraModels.CameraInterface import CameraInterface
                if isinstance(model, CameraInterface):
                    camera.Gain.Value       = float(model.Gain      )  # 增益数值
                    camera.Gamma.Value      = float(model.Gamma     )  # 伽马数值
                    camera.BlackLevel.Value = float(model.BlackLevel)  # 黑电平值
            except Exception as cameraEx:
                AppUtils.print_Exception(cameraEx)
            if IsGrabbing and not camera.IsGrabbing():
                camera.StartGrabbing(pylon.GrabStrategy_LatestImages)
        except Exception as e:
            AppUtils.print_Exception(e)