#!D:/IDE/anaconda3/envs python
# -*- coding: UTF-8 -*-
"""
 @Author: Administrator
 @FileName：TrayModelInterface.py\n
 @DateTime: 2025/6/23 17:44\n
 @Author  ：xsh
"""
from PyQt5 import Qt
from datetime import datetime, date
import copy
from AppSettings.Settings import MAX_SLIDE_WIDTH, MAX_SLIDE_HEIGHT
from AppInterfaces.AppDBInterface import (DBManager, dbController, DBInterface)
from sqlalchemy.orm import declarative_base, mapper, sessionmaker, Session
from sqlalchemy.orm import (declarative_base, Mapped, mapped_column, relationship, mapper, sessionmaker)
from sqlalchemy import Table, Engine, create_engine, Column, ForeignKey, and_, or_, insert, delete, update, select, func, ColumnElement,distinct
from sqlalchemy.types import (Text, VARCHAR, REAL, Float, Integer, String, SmallInteger, DateTime, Date, ARRAY,Boolean, JSON)
from sqlalchemy.orm.decl_api import DeclarativeBase, MetaData
from AppUtils.utils import *
from AppCore.Levels import *


class TrayModelInterface(DBInterface, DeclarativeBase):
    Information         : str   #
    Level               : int   #
    MinRowNumber        : int   #
    MinColNumber        : int   #
    MaxRowNumber        : int   #
    MaxColNumber        : int   #
    MaxRowNumber20X     : int   #
    MaxColNumber20X     : int   #
    SlideWidth          : float #
    SlideHeight         : float #
    Image_W             : int   #
    Image_H             : int   #
    Image_20X_W         : int   #
    Image_20X_H         : int   #
    FocusingCount       : int   #
    Position_X          : float #
    Position_Y          : float #
    Position_Z          : float #
    Step_X              : float #
    Step_Y              : float #
    Step_X_20X          : float #
    Step_Y_20X          : float #
    Step_X_40X          : float #
    Step_Y_40X          : float #
    Step_X_100X         : float #
    Step_Y_100X         : float #
    IsCalibrate         : int   #

    __field__ = (
        'Information'        ,
        'Level'              ,
        'MinRowNumber'       ,
        'MinColNumber'       ,
        'MaxRowNumber'       ,
        'MaxColNumber'       ,
        'MaxRowNumber20X'    ,
        'MaxColNumber20X'    ,
        'SlideWidth'         ,
        'SlideHeight'        ,
        'Image_W'            ,
        'Image_H'            ,
        'Image_20X_W'        ,
        'Image_20X_H'        ,
        'FocusingCount'      ,
        'Position_X'         ,
        'Position_Y'         ,
        'Position_Z'         ,
        'Step_X'             ,
        'Step_Y'             ,
        'Step_X_20X'         ,
        'Step_Y_20X'         ,
        'Step_X_40X'         ,
        'Step_Y_40X'         ,
        'Step_X_100X'        ,
        'Step_Y_100X'        ,
        'IsCalibrate'        ,
    )
    __types__ = (
        str   ,
        int   ,
        int   ,
        int   ,
        int   ,
        int   ,
        int   ,
        int   ,
        float ,
        float ,
        int   ,
        int   ,
        int   ,
        int   ,
        int   ,
        float ,
        float ,
        float ,
        float ,
        float ,
        float ,
        float ,
        float ,
        float ,
        float ,
        float ,
        int   ,


    )
    __header__ = (
        '　　说明信息　　',
        '　　托盘序号　　',
        '　　最小行数　　',
        '　　最小列数　　',
        '　　最大行数　　',
        '　　最大列数　　',
        '　　最大行数　　',
        '　　最大列数　　',
        '　　图像高度　　',
        '　　图像宽度　　',
        '　　图像宽度　　',
        '　　图像高度　　',
        '　玻片定焦点数　',
        '　　起始位置　　',
        '　　起始位置　　',
        '　　起始位置　　',
        '　　移动步长　　',
        '　　移动步长　　',
        '　　移动步长　　',
        '　　移动步长　　',
        '　　移动步长　　',
        '　　移动步长　　',
        '　　移动步长　　',
        '　　移动步长　　',
        '　　是否校准　　',
    )
    @classmethod
    def Instance(cls, level: int):
        result: cls = cls.__new__(cls)
        result.__init__()
        result.initTray(level)
        return result

    @classmethod
    def UpdateMaxLocation(cls):
        from AppCore.AppDBModels.ConfigModels.TrayConfigModel import TrayConfigModel
        all_tray: list[int] = TrayLevel.all()
        if cls.has_limit(len(all_tray)):
            for TrayNumber in all_tray:
                item: cls = cls.instance(Information=f'托盘玻片位置{TrayNumber}', Level=TrayNumber)
                item.initTray(TrayNumber)
                cls.changed({
                    cls.Information         : item.GetInformation         ,
                    cls.MinRowNumber        : item.GetMinRowNumber        ,
                    cls.MinColNumber        : item.GetMinColNumber        ,
                    cls.MaxRowNumber        : item.GetMaxRowNumber        ,
                    cls.MaxColNumber        : item.GetMaxColNumber        ,
                    cls.MaxRowNumber20X     : item.GetMaxRowNumber20X     ,
                    cls.MaxColNumber20X     : item.GetMaxColNumber20X     ,
                    cls.Image_W             : item.GetImage_W             ,
                    cls.Image_H             : item.GetImage_H             ,
                    cls.Image_20X_W         : item.GetImage_20X_W         ,
                    cls.Image_20X_H         : item.GetImage_20X_H         ,
                    cls.FocusingCount       : item.GetFocusingCount       ,
                    cls.Position_X          : item.GetPosition_X          ,
                    cls.Position_Y          : item.GetPosition_Y          ,
                    cls.Position_Z          : item.GetPosition_Z          ,
                    cls.Step_X              : item.GetStep_X              ,
                    cls.Step_Y              : item.GetStep_Y              ,
                    cls.Step_X_20X          : item.GetStep_X_20X          ,
                    cls.Step_Y_20X          : item.GetStep_Y_20X          ,
                    cls.Step_X_40X          : item.GetStep_X_40X          ,
                    cls.Step_Y_40X          : item.GetStep_Y_40X          ,
                    cls.Step_X_100X         : item.GetStep_X_100X         ,
                    cls.Step_Y_100X         : item.GetStep_Y_100X         ,
                }, cls.Level == TrayNumber)
        else:
            cls.append_all(cls.initModels())





    @classmethod
    def setFocusingCount(cls, level: int, focusingNumber: int):
        _level: int = TrayLevel.getTrayNumber(level)
        try:
            dbController.initEngine()
            with Session(dbController.Engine) as session:
                try:
                    session.query(cls).filter(cls.Level == _level).update({cls.FocusingCount: 0 if not isinstance(focusingNumber, int) else focusingNumber})
                    session.commit()
                except Exception as dbEx:
                    AppUtils.print_Exception(dbEx)
                    session.rollback()
                session.close()
        except Exception as e:
            AppUtils.print_Exception(e)


    @classmethod
    def getFocusingCount(cls, level: int) -> int:
        tray: cls = None
        _level: int = TrayLevel.getTrayNumber(level)
        try:
            dbController.initEngine()
            with Session(dbController.Engine) as session:
                tray = session.query(cls).filter(cls.Level == _level).first()
                session.close()
        except Exception as e:
            AppUtils.print_Exception(e)
            tray = cls.instance()
            tray.initTray1()

        return tray.FocusingCount

    @classmethod
    def getTrayModels(cls) -> ('TrayModelInterface', 'TrayModelInterface'):
        tray1: cls = None
        tray2: cls = None
        try:
            dbController.initEngine()
            with Session(dbController.Engine) as session:
                items = session.query(cls).filter(cls.Level == ModuleLevel.ModuleTraySlide1, cls.Level == ModuleLevel.ModuleTraySlide2).all()

                session.close()
            if len(items) >= 2:
                [tray1, tray2] = items[:2]
        except Exception as e:
            tray1 = None
            tray2 = None

        return tray1, tray2

    @classmethod
    def getTrayModel(cls, level: int) -> 'TrayModelInterface':
        tray: cls = None
        _level: int = TrayLevel.getTrayNumber(level)
        try:
            dbController.initEngine()
            with Session(dbController.Engine) as session:
                tray = session.query(cls).filter(cls.Level == _level).first()
                session.close()
        except Exception as e:
            tray = cls.instance()
            tray.initTray1()
        if tray is None:
            tray = cls.instance()
            tray.initTray1()
        return tray
    @classmethod
    def instance(cls, **args):
        result: cls = cls.__new__(cls)
        result.__init__(**args)
        return result

    @classmethod
    def getTrayConfig(cls, level: int):
        tray: cls = None
        _level: int = TrayLevel.getTrayNumber(level)
        try:
            dbController.initEngine()
            with Session(dbController.Engine) as session:
                tray = session.query(cls).filter(cls.Level == _level).first()
                session.close()
        except Exception as e:
            tray = cls.instance()
            tray.initTray(level)

        return tray

    @classmethod
    def getConfig(cls, level: int):
        tray: cls = None
        _level: int = TrayLevel.getTrayNumber(level)
        try:
            dbController.initEngine()
            with Session(dbController.Engine) as session:
                tray = session.query(cls).filter(cls.Level == _level).first()
                session.close()
        except Exception as e:
            tray = cls.instance()

        return tray
    def getRowNumberRange(self) -> (int, int):
        return self.MinRowNumber, self.MaxRowNumber

    def getColNumberRange(self) -> (int, int):
        return self.MinColNumber, self.MaxColNumber




    def initTray(self, level: int = 1):
        TrayNumber  : int
        TraySpacing : float
        x           : float
        y           : float
        from AppCore.AppDBModels.ConfigModels.TrayConfigModel   import TrayConfigModel      #
        config: TrayConfigModel = TrayConfigModel.first()
        TrayNumber  = TrayLevel.getTrayNumber(level)
        if not self.IsCalibrate:
            x, y    = config.getPosition_xy()
            TraySpacing = config.getSlideSpacing()
            self.Position_X             = x - (TrayNumber - 1) * abs(TraySpacing)           #
            self.Position_Y             = y                                                 #
            self.SlideWidth             = config.GetSlideWidth
            self.SlideHeight            = config.GetSlideHeight
            self.SlideWidth = config.GetSlideWidth
        self.SlideHeight = config.GetSlideHeight

        self.Information            = f'托盘玻片位置{TrayNumber}'                 # 说明信息
        self.Level                  = TrayNumber                                # 玻片位置
        self.Image_20X_W            = 4000                                      #
        self.Image_20X_H            = 3000                                      #
        self.Image_W                = 2048                                      #
        self.Image_H                = 2048                                      #
        self.FocusingCount          = 0                                         #
        self.Position_Z             = config.GetPosition_Z                      #
        self.Step_X                 = config.GetStep_X                          #
        self.Step_Y                 = config.GetStep_Y                          #
        self.Step_X_20X             = config.GetStep_X_20X                      #
        self.Step_Y_20X             = config.GetStep_Y_20X                      #
        self.Step_X_40X             = config.GetStep_X_40X                      #
        self.Step_Y_40X             = config.GetStep_Y_40X                      #
        self.Step_X_100X            = config.GetStep_X_100X                     #
        self.Step_Y_100X            = config.GetStep_Y_100X                     #
        self.MinRowNumber           = 1                                         #
        self.MinColNumber           = 1                                         #
        self.MaxRowNumber           = int(round(self.SlideWidth             / self.Step_X      , 4))
        self.MaxColNumber           = int(round(self.SlideHeight            / self.Step_Y      , 4))
        self.MaxRowNumber20X        = int(round(self.SlideWidth             / self.Step_X_20X  , 4))
        self.MaxColNumber20X        = int(round(self.SlideHeight            / self.Step_Y_20X  , 4))


    @classmethod
    def initModels(cls):
        TrayNumber  : int
        items: list[cls] = []
        for TrayNumber in TrayLevel.all():
            item: cls = cls.instance(Information    = f'托盘玻片位置{TrayNumber}', Level          = TrayNumber)
            item.initTray(TrayNumber)
            items.append(item)
        return items

    def SetInformation         (self, value):
        if isinstance(value, str          ):
            self.Information          = str  (value)

    def SetLevel               (self, value):
        if isinstance(value, (int, float) ):
            self.Level                = int  (value)

    def SetMinRowNumber        (self, value):
        if isinstance(value, (int, float) ):
            self.MinRowNumber         = int  (value)

    def SetMinColNumber        (self, value):
        if isinstance(value, (int, float) ):
            self.MinColNumber         = int  (value)

    def SetMaxRowNumber        (self, value):
        if isinstance(value, (int, float) ):
            self.MaxRowNumber         = int  (value)

    def SetMaxColNumber        (self, value):
        if isinstance(value, (int, float) ):
            self.MaxColNumber         = int  (value)

    def SetMaxRowNumber20X     (self, value):
        if isinstance(value, (int, float) ):
            self.MaxRowNumber20X      = int  (value)

    def SetMaxColNumber20X     (self, value):
        if isinstance(value, (int, float) ):
            self.MaxColNumber20X      = int  (value)

    def SetImage_W             (self, value):
        if isinstance(value, (int, float) ):
            self.Image_W              = int  (value)

    def SetImage_H             (self, value):
        if isinstance(value, (int, float) ):
            self.Image_H              = int  (value)

    def SetImage_20X_W         (self, value):
        if isinstance(value, (int, float) ):
            self.Image_20X_W          = int  (value)

    def SetImage_20X_H         (self, value):
        if isinstance(value, (int, float) ):
            self.Image_20X_H          = int  (value)

    def SetFocusingCount       (self, value):
        if isinstance(value, (int, float) ):
            self.FocusingCount        = int  (value)

    def SetPosition_X          (self, value):
        if isinstance(value, (int, float) ):
            self.Position_X           = float(value)

    def SetPosition_Y          (self, value):
        if isinstance(value, (int, float) ):
            self.Position_Y           = float(value)

    def SetPosition_Z          (self, value):
        if isinstance(value, (int, float) ):
            self.Position_Z           = float(value)

    def SetStep_X              (self, value):
        if isinstance(value, (int, float) ):
            self.Step_X               = float(value)

    def SetStep_Y              (self, value):
        if isinstance(value, (int, float) ):
            self.Step_Y               = float(value)

    def SetStep_X_20X          (self, value):
        if isinstance(value, (int, float) ):
            self.Step_X_20X           = float(value)

    def SetStep_Y_20X          (self, value):
        if isinstance(value, (int, float) ):
            self.Step_Y_20X           = float(value)

    def SetStep_X_40X          (self, value):
        if isinstance(value, (int, float) ):
            self.Step_X_40X           = float(value)

    def SetStep_Y_40X          (self, value):
        if isinstance(value, (int, float) ):
            self.Step_Y_40X           = float(value)

    def SetStep_X_100X         (self, value):
        if isinstance(value, (int, float) ):
            self.Step_X_100X          = float(value)

    def SetStep_Y_100X         (self, value):
        if isinstance(value, (int, float) ):
            self.Step_Y_100X          = float(value)

    @property
    def GetInformation         (self) -> str   :
        return None if not self.hasInformation          else self.Information         #

    @property
    def GetLevel               (self) -> int   :
        return None if not self.hasLevel                else self.Level               #

    @property
    def GetMinRowNumber        (self) -> int   :
        return None if not self.hasMinRowNumber         else self.MinRowNumber        #

    @property
    def GetMinColNumber        (self) -> int   :
        return None if not self.hasMinColNumber         else self.MinColNumber        #

    @property
    def GetMaxRowNumber        (self) -> int   :
        return None if not self.hasMaxRowNumber         else self.MaxRowNumber        #

    @property
    def GetMaxColNumber        (self) -> int   :
        return None if not self.hasMaxColNumber         else self.MaxColNumber        #

    @property
    def GetMaxRowNumber20X     (self) -> int   :
        return None if not self.hasMaxRowNumber20X      else self.MaxRowNumber20X     #

    @property
    def GetMaxColNumber20X     (self) -> int   :
        return None if not self.hasMaxColNumber20X      else self.MaxColNumber20X     #

    @property
    def GetImage_W             (self) -> int   :
        return None if not self.hasImage_W              else self.Image_W             #

    @property
    def GetImage_H             (self) -> int   :
        return None if not self.hasImage_H              else self.Image_H             #

    @property
    def GetImage_20X_W         (self) -> int   :
        return None if not self.hasImage_20X_W          else self.Image_20X_W         #

    @property
    def GetImage_20X_H         (self) -> int   :
        return None if not self.hasImage_20X_H          else self.Image_20X_H         #

    @property
    def GetFocusingCount       (self) -> int   :
        return None if not self.hasFocusingCount        else self.FocusingCount       #

    @property
    def GetPosition_X          (self) -> float :
        return None if not self.hasPosition_X           else self.Position_X          #

    @property
    def GetPosition_Y          (self) -> float :
        return None if not self.hasPosition_Y           else self.Position_Y          #

    @property
    def GetPosition_Z          (self) -> float :
        return None if not self.hasPosition_Z           else self.Position_Z          #

    @property
    def GetStep_X              (self) -> float :
        return None if not self.hasStep_X               else self.Step_X              #

    @property
    def GetStep_Y              (self) -> float :
        return None if not self.hasStep_Y               else self.Step_Y              #

    @property
    def GetStep_X_20X          (self) -> float :
        return None if not self.hasStep_X_20X           else self.Step_X_20X          #

    @property
    def GetStep_Y_20X          (self) -> float :
        return None if not self.hasStep_Y_20X           else self.Step_Y_20X          #

    @property
    def GetStep_X_40X          (self) -> float :
        return None if not self.hasStep_X_40X           else self.Step_X_40X          #

    @property
    def GetStep_Y_40X          (self) -> float :
        return None if not self.hasStep_Y_40X           else self.Step_Y_40X          #

    @property
    def GetStep_X_100X         (self) -> float :
        return None if not self.hasStep_X_100X          else self.Step_X_100X         #

    @property
    def GetStep_Y_100X         (self) -> float :
        return None if not self.hasStep_Y_100X          else self.Step_Y_100X         #



    @property
    def hasInformation         (self) -> bool:
        return hasattr(self, 'Information'    ) and isinstance(self.Information         , str   )

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

    @property
    def hasMinRowNumber        (self) -> bool:
        return hasattr(self, 'MinRowNumber'   ) and isinstance(self.MinRowNumber        , (int, float)   )

    @property
    def hasMinColNumber        (self) -> bool:
        return hasattr(self, 'MinColNumber'   ) and isinstance(self.MinColNumber        , (int, float)   )

    @property
    def hasMaxRowNumber        (self) -> bool:
        return hasattr(self, 'MaxRowNumber'   ) and isinstance(self.MaxRowNumber        , (int, float)   )

    @property
    def hasMaxColNumber        (self) -> bool:
        return hasattr(self, 'MaxColNumber'   ) and isinstance(self.MaxColNumber        , (int, float)   )

    @property
    def hasMaxRowNumber20X     (self) -> bool:
        return hasattr(self, 'MaxRowNumber20X') and isinstance(self.MaxRowNumber20X     , (int, float)   )

    @property
    def hasMaxColNumber20X     (self) -> bool:
        return hasattr(self, 'MaxColNumber20X') and isinstance(self.MaxColNumber20X     , (int, float)   )

    @property
    def hasImage_W             (self) -> bool:
        return hasattr(self, 'Image_W'        ) and isinstance(self.Image_W             , (int, float)   )

    @property
    def hasImage_H             (self) -> bool:
        return hasattr(self, 'Image_H'        ) and isinstance(self.Image_H             , (int, float)   )

    @property
    def hasImage_20X_W         (self) -> bool:
        return hasattr(self, 'Image_20X_W'    ) and isinstance(self.Image_20X_W         , (int, float)   )

    @property
    def hasImage_20X_H         (self) -> bool:
        return hasattr(self, 'Image_20X_H'    ) and isinstance(self.Image_20X_H         , (int, float)   )

    @property
    def hasFocusingCount       (self) -> bool:
        return hasattr(self, 'FocusingCount'  ) and isinstance(self.FocusingCount       , (int, float)   )

    @property
    def hasPosition_X          (self) -> bool:
        return hasattr(self, 'Position_X'     ) and isinstance(self.Position_X          , (int, float) )

    @property
    def hasPosition_Y          (self) -> bool:
        return hasattr(self, 'Position_Y'     ) and isinstance(self.Position_Y          , (int, float) )

    @property
    def hasPosition_Z          (self) -> bool:
        return hasattr(self, 'Position_Z'     ) and isinstance(self.Position_Z          , (int, float) )

    @property
    def hasStep_X              (self) -> bool:
        return hasattr(self, 'Step_X'         ) and isinstance(self.Step_X              , (int, float) )

    @property
    def hasStep_Y              (self) -> bool:
        return hasattr(self, 'Step_Y'         ) and isinstance(self.Step_Y              , (int, float) )

    @property
    def hasStep_X_20X          (self) -> bool:
        return hasattr(self, 'Step_X_20X'     ) and isinstance(self.Step_X_20X          , (int, float) )

    @property
    def hasStep_Y_20X          (self) -> bool:
        return hasattr(self, 'Step_Y_20X'     ) and isinstance(self.Step_Y_20X          , (int, float) )

    @property
    def hasStep_X_40X          (self) -> bool:
        return hasattr(self, 'Step_X_40X'     ) and isinstance(self.Step_X_40X          , (int, float) )

    @property
    def hasStep_Y_40X          (self) -> bool:
        return hasattr(self, 'Step_Y_40X'     ) and isinstance(self.Step_Y_40X          , (int, float) )

    @property
    def hasStep_X_100X         (self) -> bool:
        return hasattr(self, 'Step_X_100X'    ) and isinstance(self.Step_X_100X         , (int, float) )

    @property
    def hasStep_Y_100X         (self) -> bool:
        return hasattr(self, 'Step_Y_100X'    ) and isinstance(self.Step_Y_100X         , (int, float) )



    @property
    def hasSlideWidth  (self) -> bool:
        return hasattr(self, 'SlideWidth'  ) and isinstance(self.SlideWidth , (int, float))

    @property
    def hasSlideHeight (self) -> bool:
        return hasattr(self, 'SlideHeight' ) and isinstance(self.SlideHeight, (int, float))
