#!D:/IDE/anaconda3/envs/Microscope_Scan python
# -*- coding: UTF-8 -*-
"""
@FileName：FocusingOperation.py
@Description：
@Author：XSH
@Time：2025/12/20 18:02
@Department：研发部
@Copyright：©2025 乐辰生物
"""
from abc                                    import abstractmethod                       #
from PyQt5                                  import Qt                                   #
from AppInterfaces.UiInterface              import UiInterface                          #
from AppInterfaces.globalSlot               import globalSlot, AppSlot                  #
from AppCore.Contexts                       import *                                    #
from AppCore.DBModels                       import *                                    #
from AppCore.Levels                         import *                                    #
from AppUtils.utils                         import *                                    #
from AppSettings.Settings                   import *                                    #
from AppHeadEnd.DBModelViews.ActionMenuBar  import ActionMenuBar                        #
class FocusingOperation(Qt.QTableWidget, UiInterface):
    PositionChangedSignal: Qt.pyqtSignal = Qt.pyqtSignal(object, object, object)
    Camera          : CameraModel                       #
    Offset          : ObjectiveOffsetModel              #
    Objective       : ObjectiveModel                    #
    MenuBar         : ActionMenuBar                     #
    Context         : FocusingContext                   #
    Contexts        : dict[int, FocusingContext]        #
    LastPositionX   : float                             #
    LastPositionY   : float                             #
    LastPositionZ   : float                             #
    PositionX       : float                             #
    PositionY       : float                             #
    PositionZ       : float                             #


    def __init__(self, parent: Qt.QWidget = None):
        super(FocusingOperation, self).__init__(parent)
        self.Initialization('FocusingOperation', self, parent)
        self.initContexts()

    def initValue(self):
        super(FocusingOperation, self).initValue()
        self.initMenuBar()

    def initProperty(self):
        super(FocusingOperation, self).initProperty()
        # 设置全部单元格可编辑

        max_length: int = len(FocusingContext.__slots__)
        self.setColumnCount(max_length)
        self.setHorizontalHeaderLabels(FocusingContext.__slots__)
        header = self.horizontalHeader()
        header.setSectionResizeMode(Qt.QHeaderView.Stretch)  # Make columns stretch to fill width
        header.setSectionResizeMode(0, Qt.QHeaderView.Interactive)
        header.setStretchLastSection(True)  # Stretch last column
        header.setSectionResizeMode(Qt.QHeaderView.Custom)
        # 设置表头字体大小
        headerFont = header.font()
        headerFont.setPixelSize(10)
        header.setFont(headerFont)

        self.setHorizontalHeader(header)
        self.verticalHeader().setDefaultSectionSize(40)
        self.setSelectionBehavior(Qt.QTableWidget.SelectRows)  # Select entire rows
        self.setSelectionMode(Qt.QTableWidget.SingleSelection)  # Single row selection
        # self.setEditTriggers(Qt.QTableWidget.NoEditTriggers)  # Read-only
        self.setAlternatingRowColors(False)  # 禁用隔行变色
        self.setShowGrid(True)  # Show grid lines
        self.verticalHeader().setVisible(False)  # Hide row numbers
        header.setSectionResizeMode(Qt.QHeaderView.Stretch)

    def initConnect(self):
        super(FocusingOperation, self).initConnect()
        TYPE: Qt.Qt.ConnectionType = Qt.Qt.ConnectionType(Qt.Qt.AutoConnection | Qt.Qt.UniqueConnection)
        self.cellClicked.connect(self.SlotCellClicked, TYPE)
        self.MenuBar.ActionSignal.connect(self.SlotActionSignal, TYPE)

    def SlotCellClicked(self, row: int, column: int):
        item: Qt.QTableWidgetItem = self.item(row, column)
        self.Camera           = None if not item else self.getItemCamera          (item)
        self.Offset           = None if not item else self.getItemOffset          (item)
        self.Objective        = None if not item else self.getItemObjective       (item)
        self.Context          = None if not item else self.getItemContext         (item)

    def SlotActionSignal(self, name: str):
        if name == '移动焦点':
            if not self.hasObjective or not self.hasContext:
                return
            Objective   : int   = self.Objective.Level
            Speed       : float = self.Objective.Default_Speed
            Position    : float = self.Context.ZPosition
            self.PositionChangedSignal.emit(Objective, Speed, Position)

            return
        if name == '刷新数据':
            self.flushItems()
            return
        if name == '保存数据':
            self.saveItems()
            return

    def mousePressEvent(self, ev: Qt.QMouseEvent) -> None:
        if ev.button() == Qt.Qt.RightButton:
            self.IsPress = True
        return super(FocusingOperation, self).mousePressEvent(ev)

    def mouseReleaseEvent(self, ev: Qt.QMouseEvent) -> None:
        if ev.button() == Qt.Qt.RightButton:
            if self.IsPress:
                self.MenuBar.draw(ev.globalPos())
                self.IsPress = False
        return super(FocusingOperation, self).mouseReleaseEvent(ev)

    def clearItems(self):
        while self.rowCount() > 0:
            self.removeRow(0)
        while len(self.Contexts) > 0:
            self.Contexts.popitem()
        self.Contexts = None

    def updateItem(self, item: Qt.QTableWidgetItem):
        if not isinstance(item, Qt.QTableWidgetItem):
            return



    def saveItems(self):
        if not self.hasContexts:
            return
        objective       : int                               #
        context         : FocusingContext                   #
        Camera          : CameraModel                       #
        Offset          : ObjectiveOffsetModel              #
        Objective       : ObjectiveModel                    #
        for objective, context in self.Contexts.items():
            Camera , Offset, Objective = self.getParameter(context)
            if isinstance(Camera, CameraModel):
                CameraModel.changed({CameraModel.ExposureTime            : context.ExposureTime,
                                CameraModel.AberrationExposureTime  : context.ExposureTime,
                                CameraModel.KaryotypingExposureTime : context.ExposureTime
                                }, CameraModel.Level == objective)
                ObjectiveOffsetModel.changed(
                    {ObjectiveOffsetModel.OffsetX       : context.OffsetX       ,
                     ObjectiveOffsetModel.OffsetY       : context.OffsetY       ,
                     ObjectiveOffsetModel.OffsetZ       : context.OffsetZ       ,
                     ObjectiveOffsetModel.IsCalibrate   : 1                     ,
                     ObjectiveOffsetModel.ZPosition     : context.ZPosition     ,
                     ObjectiveOffsetModel.ExposureTime  : context.ExposureTime  ,
                     }, ObjectiveOffsetModel.Level == objective)
                ObjectiveModel.changed(
                    {ObjectiveModel.Focus_Lower_Limit: context.ZPosition - 200000,
                     ObjectiveModel.Focus_Upper_Limit: context.ZPosition + 200000,
                     ObjectiveModel.Upper_Limit      : context.ZPosition + 500000,
                     ObjectiveModel.FocusingOffset   : context.OffsetZ           ,
                     ObjectiveModel.OilFocalDistance : context.OffsetZ           ,

                     },
                    ObjectiveModel.Level == objective
                )
                if objective == ObjectiveLevel.Objective63 or objective == ObjectiveLevel.Objective100:
                    AnointingModel.changed(
                        {
                            AnointingModel.OilDaub_Position : context.ZPosition - 200000,
                            AnointingModel.ClearOil_Position: context.ZPosition + 400000,
                        })
                else:
                    AnointingModel.changed(
                        {
                            AnointingModel.OilDaub_Position : context.ZPosition - 200000,
                            AnointingModel.ClearOil_Position: context.ZPosition - 200000,
                        })





    @property
    def last_x(self) -> float:
        return 0 if not self.hasLastPositionX else self.LastPositionX

    @property
    def last_y(self) -> float:
        return 0 if not self.hasLastPositionY else self.LastPositionY

    @property
    def last_z(self) -> float:
       return 0 if not self.hasLastPositionZ else self.LastPositionZ

    @property
    def position_x(self) -> float:
       return 0 if not self.hasPositionX else self.PositionX

    @property
    def position_y(self) -> float:
       return 0 if not self.hasPositionY else self.PositionY

    @property
    def position_z(self) -> float:
       return 0 if not self.hasPositionZ else self.PositionZ

    def setLastPosition(self, x: float, y: float):
        self.LastPositionX = x
        self.LastPositionY = y

    def setPosition(self, x: float, y: float):
        self.PositionX = x
        self.PositionY = y

    def setFocusing(self, z: float):
        self.PositionZ = z

    def initContexts(self):
        if not self.hasContexts:
            self.Contexts = {}
            Camera   : CameraModel
            Offset   : ObjectiveOffsetModel
            Objective: ObjectiveModel
            Context  : FocusingContext
            objective: int
            for objective in ObjectiveLevel.all():
                Objective   = ObjectiveModel.getConfig(objective)
                Camera      = CameraModel.getConfig(objective)
                Offset      = ObjectiveOffsetModel.getConfig(objective)
                Context     = FocusingContext()
                Context.Information                     = Objective.Information     #
                Context.Level                           = Objective.Level           #
                Context.ZPosition                       = Objective.Focus_Lower_Limit + (Objective.Focus_Upper_Limit - Objective.Focus_Lower_Limit) // 2      #
                Context.ExposureTime                    = Camera.ExposureTime       #
                Context.OffsetZ                         = Offset.OffsetZ            #
                Context.OffsetX                         = Offset.OffsetX            #
                Context.OffsetY                         = Offset.OffsetY            #
                Context.IsCalibrate                     = Offset.IsCalibrate        #
                self.setParameter( Context, Objective, Camera, Offset)
                self.Contexts[objective] = Context
                self.appendTableItem(self.rowCount(), Context, Objective, Camera, Offset)


    def appendTableItem(self, row: int, data: FocusingContext, Objective: ObjectiveModel, Camera: CameraModel, Offset: ObjectiveOffsetModel):
        if not isinstance(data, FocusingContext):
            return
        self.insertRow(row)
        for index, field in enumerate(FocusingContext.__slots__):
            value = getattr(data, field, '')
            item = Qt.QTableWidgetItem(f'{value}' if value is not None else '')
            item.setFlags(item.flags() & ~Qt.Qt.ItemIsEditable)
            self.setItemParameter(item, data, Objective, Camera, Offset)
            self.setItem(row, index, item)

    def flushItems(self):
        if not self.hasContexts:
            self.clearContents()
            return
        rows = self.rowCount()
        maxlength: int = len(self.Contexts)
        if maxlength < rows:
            for row in range(maxlength, rows):
                self.deleteTableItem(row)
        else:
            objective: int
            Objectives: list[int] = ObjectiveLevel.all()
            for row, objective in enumerate(Objectives):
                data        = self.Contexts[objective]
                Objective   = ObjectiveModel.getConfig(objective)
                Camera      = CameraModel.getConfig(objective)
                Offset      = ObjectiveOffsetModel.getConfig(objective)
                for column, field in enumerate(FocusingContext.__slots__):
                    item = self.item(row, column)
                    value = getattr(data, field, '')
                    item.setText(f'{value}' if value is not None else '')
                    self.setItemParameter(item, data, Objective, Camera, Offset)



    def deleteTableItem(self, row: int):
        self.removeRow(row)

    def setItemObjective(self, item: Qt.QTableWidgetItem, Objective: ObjectiveModel):
        if isinstance(item, Qt.QTableWidgetItem):
            setattr(item, 'Objective', Objective)

    def setItemCamera(self, item: Qt.QTableWidgetItem, Camera: CameraModel):
        if isinstance(item, Qt.QTableWidgetItem):
            setattr(item, 'Camera', Camera)

    def setItemOffset(self, item: Qt.QTableWidgetItem, Offset: ObjectiveOffsetModel):
        if isinstance(item, Qt.QTableWidgetItem):
            setattr(item, 'Offset', Offset)


    def setItemContext(self, item: Qt.QTableWidgetItem, Context: FocusingContext):
        if isinstance(item, Qt.QTableWidgetItem):
            setattr(item, 'Context', Context)

    def getItemObjective(self, item: Qt.QTableWidgetItem) -> ObjectiveModel:
        if isinstance(item, Qt.QTableWidgetItem):
            return getattr(item, 'Objective', None)
        return None

    def getItemCamera(self, item: Qt.QTableWidgetItem) -> CameraModel:
        if isinstance(item, Qt.QTableWidgetItem):
            return getattr(item, 'Camera', None)
        return None


    def getItemOffset(self, item: Qt.QTableWidgetItem) -> ObjectiveOffsetModel:
        if isinstance(item, Qt.QTableWidgetItem):
            return getattr(item, 'Offset', None)
        return None

    def getItemContext(self, item: Qt.QTableWidgetItem) -> FocusingContext:
        if not isinstance(item, Qt.QTableWidgetItem):
            return getattr(item, 'Context', None)
        return None

    def setItemParameter(self, item: Qt.QTableWidgetItem,context: FocusingContext, Objective: ObjectiveModel, Camera: CameraModel, Offset: ObjectiveOffsetModel):
        if not isinstance(item, Qt.QTableWidgetItem):
            return
        setattr(item, 'context'     , context   )
        setattr(item, 'Objective'   , Objective )
        setattr(item, 'Camera'      , Camera    )
        setattr(item, 'Offset'      , Offset    )





    def setObjective(self, context: FocusingContext, Objective: ObjectiveModel):
        if not isinstance(context, FocusingContext):
            return
        setattr(context, 'Objective', Objective)

    def setCamera(self, context: FocusingContext, Camera: CameraModel):
        if not isinstance(context, FocusingContext):
            return
        setattr(context, 'Camera', Camera)

    def setOffset(self, context: FocusingContext, Offset: ObjectiveOffsetModel):
        if not isinstance(context, FocusingContext):
            return
        setattr(context, 'Offset', Offset)

    def getObjective(self, context: FocusingContext) -> ObjectiveModel:
        if not isinstance(context, FocusingContext):
            return None
        return getattr(context, 'Objective', None)

    def getCamera(self, context: FocusingContext) -> CameraModel:
        if not isinstance(context, FocusingContext):
            return None
        return getattr(context, 'Camera', None)

    def getOffset(self, context: FocusingContext) -> ObjectiveOffsetModel:
        if not isinstance(context, FocusingContext):
            return None
        return getattr(context, 'Offset', None)

    def setParameter(self, context: FocusingContext, Objective: ObjectiveModel, Camera: CameraModel, Offset: ObjectiveOffsetModel):
        if not isinstance(context, FocusingContext):
            return
        setattr(context, 'Objective', Objective)
        setattr(context, 'Camera'   , Camera)
        setattr(context, 'Offset'   , Offset)

    def getParameter(self, context: FocusingContext) -> (ObjectiveModel, CameraModel, ObjectiveOffsetModel):
        if not isinstance(context, FocusingContext):
            return None, None, None
        return getattr(context, 'Objective', None), getattr(context, 'Camera', None), getattr(context, 'Offset', None)


    def initMenuBar(self):
        if not self.hasMenuBar:
            self.MenuBar = ActionMenuBar(['移动焦点', '刷新数据', '保存数据'])


    @property
    def hasLastPositionX   (self) -> bool:
        return self.has_field('LastPositionX' , (int, float))

    @property
    def hasLastPositionY   (self) -> bool:
        return self.has_field('LastPositionY' , (int, float))

    @property
    def hasLastPositionZ   (self) -> bool:
        return self.has_field('LastPositionZ' , (int, float))

    @property
    def hasPositionX       (self) -> bool:
        return self.has_field('PositionX'     , (int, float))

    @property
    def hasPositionY       (self) -> bool:
        return self.has_field('PositionY'     , (int, float))

    @property
    def hasPositionZ       (self) -> bool:
        return self.has_field('PositionZ'     , (int, float))

    @property
    def hasContexts(self) -> bool:
        return self.has_field('Contexts', dict)






    @property
    def hasCamera    (self) -> bool:
        return self.has_field('Camera'        , CameraModel         )

    @property
    def hasOffset    (self) -> bool:
        return self.has_field('Offset'        , ObjectiveOffsetModel)

    @property
    def hasObjective (self) -> bool:
        return self.has_field('Objective'     , ObjectiveModel      )

    @property
    def hasContext   (self) -> bool:
        return self.has_field('Context'       , FocusingContext     )

    @property
    def hasMenuBar  (self) -> bool:
        return self.has_field('MenuBar'       , Qt.QMenuBar         )
