#!D:\IDE\Anaconda3\envs\Microscope_Scan python
# -*- coding: UTF-8 -*-
"""
 @Author: Administrator
 @FileName: ScanTemplate.py
 @DateTime: 2025/6/22 15:24
 @SoftWare: PyCharm
 @Author  ：xsh
"""
from PyQt5 import Qt
from datetime import datetime, date
import copy
from AppSettings.Settings import RECODE_FAILURE, RECODE_SUCCEED, RECODE_WARNING
from AppCore.AppDBModels.CoreModel import (CoreModel, DBManager, dbController)
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
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 *
from AppCore.AppDBModels.TemplateModels.Collectsettings import Collectsettings
from AppCore.AppDBModels.TemplateModels.Previewsettings import Previewsettings
class ScanTemplate(CoreModel):
    __tablename__ = 't_ScanTemplate'
    ID                      : Mapped[int ] = mapped_column   (primary_key=True                                  , nullable=False, doc='扫描模板序号', comment='扫描模板序号')
    Template_name           : Mapped[str ] = mapped_column   (Text, default=''                                  , nullable=True , doc='扫描模板名称', comment='扫描模板名称')
    separator_no            : Mapped[str ] = mapped_column   (Text, default='-'                                 , nullable=True , doc='玻片号分割符', comment='玻片号分割符')
    line_no                 : Mapped[str ] = mapped_column   (Text, default='~'                                 , nullable=True , doc='样本线分割符', comment='样本线分割符')
    scan_matching           : Mapped[str ] = mapped_column   (Text, default='P'                                 , nullable=True , doc='模板匹配符号', comment='模板匹配符号')
    color                   : Mapped[str ] = mapped_column   (Text, default='#FF0000'                           , nullable=True , doc='扫描模板颜色', comment='扫描模板颜色')
    is_default              : Mapped[int ] = mapped_column   (      default=0                                   , nullable=True , doc='默认模板开关', comment='默认模板开关')
    focus_point_column      : Mapped[int ] = mapped_column   (      default=4                                   , nullable=True , doc='扫描定焦行数', comment='扫描定焦行数')
    focus_point_row         : Mapped[int ] = mapped_column   (      default=4                                   , nullable=True , doc='扫描定焦列数', comment='扫描定焦列数')
    left                    : Mapped[int ] = mapped_column   (      default=1                                   , nullable=True , doc='扫描起始行号', comment='扫描起始行号')
    top                     : Mapped[int ] = mapped_column   (      default=1                                   , nullable=True , doc='扫描起始列数', comment='扫描起始列数')
    width                   : Mapped[int ] = mapped_column   (      default=30                                  , nullable=True , doc='扫描范围宽度', comment='扫描范围宽度')
    height                  : Mapped[int ] = mapped_column   (      default=30                                  , nullable=True , doc='扫描范围高度', comment='扫描范围高度')
    previewsettings_ID      : Mapped[int ] = mapped_column   (ForeignKey("t_previewsettings.ID"), default=None  , nullable=True , doc='预览参数序号', comment='预览参数序号')
    collectsettings_ID      : Mapped[int ] = mapped_column   (ForeignKey("t_collectsettings.ID"), default=None  , nullable=True , doc='采集参数序号', comment='采集参数序号')
    previewsettings         : Mapped['Previewsettings' ] = relationship("Previewsettings" , backref="t_previewsettings", foreign_keys=[previewsettings_ID])
    collectsettings         : Mapped['Collectsettings' ] = relationship("Collectsettings" , backref="t_collectsettings", foreign_keys=[collectsettings_ID])
    def __init__(self, **args):
        super(ScanTemplate, self).__init__()
        self.initialize()
        self.initParameter(**args)
        self.initTemplate()

    def initParameter(self, **args):
        super(ScanTemplate, self).initParameter(**args)
        if args.get('collectsettings', None) is not None:
            self.init_collectsettings()
            self.collectsettings.deserialize(args.get('collectsettings', {}))
        if args.get('collectsettings', None) is not None:
            self.init_previewsettings()
            self.previewsettings.deserialize(args.get('previewsettings', {}))

    def initDefaultTemplate(self):
        self.ID                      = 1
        self.Template_name           = '畸变模板'
        self.separator_no            = '-'
        self.line_no                 = '~'
        self.scan_matching           = 'P'
        self.color                   = '#FF0000'
        self.is_default              = 0
        self.focus_point_column      = 2
        self.focus_point_row         = 10
        self.left                    = 1
        self.top                     = 1
        self.width                   = 20
        self.height                  = 20
        self.previewsettings_ID      = 1
        self.collectsettings_ID      = 1

    def initTemplate(self):
        self.init_previewsettings()
        self.init_collectsettings()

    def isAberration(self) -> bool:
        if not self.has_previewsettings_ID:
            return False
        previewsettings = Previewsettings.Primary(self.previewsettings_ID)
        return isinstance(previewsettings, Previewsettings) and previewsettings.has_classifier and previewsettings.classifier == 'Aberration'


    def isMicronucleus(self) -> bool:
        if not self.has_previewsettings_ID:
            return False
        previewsettings = Previewsettings.Primary(self.previewsettings_ID)
        return isinstance(previewsettings,
                          Previewsettings) and previewsettings.has_classifier and previewsettings.classifier == 'Micronucleus'

    def isKaryotyping(self) -> bool:
        if not self.has_previewsettings_ID:
            return False
        previewsettings = Previewsettings.Primary(self.previewsettings_ID)
        return isinstance(previewsettings,
                          Previewsettings) and previewsettings.has_classifier and previewsettings.classifier == 'Karyotyping'

    @classmethod
    def initModels(cls):

        items: list[cls] = [
            cls.instance(ID                      = 1            ,Template_name           = '畸变模板'  ,separator_no            = '-'          ,line_no                 = '~'          ,scan_matching           = 'P'          ,color                   = '#FF0000'    ,is_default              = 0            ,focus_point_column      = 3            ,focus_point_row         = 3            ,left                    = 2            ,top                     = 10           ,width                   = 20           ,height                  = 20           ,previewsettings_ID      = 1            ,collectsettings_ID      = 1            ),
            cls.instance(ID                      = 2            ,Template_name           = '微核模板'  ,separator_no            = '-'          ,line_no                 = '~'          ,scan_matching           = 'P'          ,color                   = '#FF0000'    ,is_default              = 0            ,focus_point_column      = 3            ,focus_point_row         = 3            ,left                    = 2            ,top                     = 10           ,width                   = 20           ,height                  = 20           ,previewsettings_ID      = 2            ,collectsettings_ID      = 2            ),
            cls.instance(ID                      = 3            ,Template_name           = '核型模板'  ,separator_no            = '-'          ,line_no                 = '~'          ,scan_matching           = 'P'          ,color                   = '#FF0000'    ,is_default              = 0            ,focus_point_column      = 3            ,focus_point_row         = 3            ,left                    = 2            ,top                     = 10           ,width                   = 20           ,height                  = 20           ,previewsettings_ID      = 3            ,collectsettings_ID      = 3            ),
        ]
        return items
    def serialize(self) -> dict[str, object]:
        buffer: dict[str, object] = super(ScanTemplate, self).serialize()
        buffer['collectsettings'] = self.getCollectsettings.to_field() if self.has_collectsettings else {}
        buffer['previewsettings'] = self.getPreviewsettings.to_field() if self.has_previewsettings else {}
        return buffer

    def deserialize(self, buffer: dict[str, object]):
        super(ScanTemplate, self).deserialize(buffer)
        self.init_collectsettings()
        self.init_previewsettings()
        self.previewsettings.deserialize(buffer.get('previewsettings', {}))
        self.collectsettings.deserialize(buffer.get('collectsettings', {}))

    def init_collectsettings(self):
        if self.has_collectsettings_ID:
            self.collectsettings = Collectsettings.Primary(self.collectsettings_ID)
    def init_previewsettings(self):
        if self.has_previewsettings_ID:
            self.previewsettings = Previewsettings.Primary(self.previewsettings_ID)



    def initValue(self):
        super(ScanTemplate, self).initValue()

    @property
    def getCollectsettings(self) -> Collectsettings:
        if not self.has_collectsettings:
            self.init_collectsettings()
        return None if not self.has_collectsettings else self.collectsettings

    @property
    def getPreviewsettings(self) -> Previewsettings:
        if not self.has_previewsettings:
            self.init_previewsettings()
        return None if not self.has_previewsettings else self.previewsettings

    def setCollectsettings(self, value: Collectsettings):
        self.collectsettings = None if not isinstance(value, Collectsettings) else value
        if self.has_collectsettings:
            self.collectsettings_ID = self.getCollectsettings.ID

    def setPreviewsettings(self, value: Previewsettings):
        self.previewsettings = None if not isinstance(value, Previewsettings) else value
        if self.has_previewsettings:
            self.previewsettings_ID = self.getPreviewsettings.ID
    @property
    def has_ID                      (self) -> bool:
        return hasattr(self, 'ID'                  ) and isinstance(self.ID                      , int            )

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    @property
    def has_collectsettings         (self) -> bool:
        return hasattr(self, 'collectsettings'     ) and self.previewsettings is not None



    """当前是否为样本的匹配模板"""
    def is_scan_matching(self, codeString: str) -> bool:
        is_matching: bool = False
        if not isinstance(codeString, str) or len(codeString) <= 0:
            return is_matching
        """获取匹配字符列表"""
        scan_matching = f'{self.scan_matching}'
        matching: list[str]
        if len(scan_matching.split(',')) > 1:
            matching = list(scan_matching.split(','))
        else:
            matching = [scan_matching]
        index_list: list[int] = []
        match_list: list[str] = []
        index: int
        content: bool
        for match in matching:
            content = match in codeString
            if content:
                try:
                    index = codeString.index(match)
                except Exception as e:
                    index = -1
            else:
                index = -1
            if content and index == 0:
                is_matching = True
                break

        return is_matching

    """根据样本二维码解析玻片号"""
    def get_slide_number(self, codeString: str) -> str:
        slide_no: str = ''
        if not isinstance(codeString, str) or len(codeString) <= 0:
            return slide_no
        SpecimenNumber: str
        SlideNumber   : str = None
        SlideNumbers  : list[str]
        code_no: str = f'{codeString}'
        slide_split_no: str = f'{self.separator_no}'
        if self.is_scan_matching(code_no):
            try:
                SlideNumbers = code_no.split(slide_split_no)
                SlideNumber = SlideNumbers[-1] if SlideNumbers is not None and len(SlideNumbers) >= 2 else None

            except Exception as e:
                pass
        return SlideNumber


    """根据样本二维码解析样本号"""
    def get_specimen_no(self, codeString: str) -> str:
        slide_no: str = ''
        if not isinstance(codeString, str) or len(codeString) <= 0:
            return slide_no
        SpecimenNumber      : str = None
        SlideNumbers        : list[str]
        code_no             : str = f'{codeString}'
        slide_split_no      : str = f'{self.separator_no}'
        if self.is_scan_matching(code_no):
            try:
                SlideNumbers = code_no.split(slide_split_no)
                SpecimenNumber = SlideNumbers[0] if SlideNumbers is not None and len(SlideNumbers) >= 1 else None

            except Exception as e:
                pass

        if not isinstance(SpecimenNumber, str) or len(SpecimenNumber) <= 0:
            SpecimenNumber = codeString
        return SpecimenNumber


    """根据样本二维码解析样本号 玻片号 线号"""
    def get_specimen_numbers(self, codeString: str) -> (str, str, str):
        slide_no: str = ''
        if not isinstance(codeString, str) or len(codeString) <= 0:
            return slide_no
        SpecimenNumber  : str = None
        SlideNumber     : str = None
        LineNumber      : str = None
        SlideNumbers: list[str]
        code_no: str = f'{codeString}'
        slide_split_no: str = f'{self.separator_no}'
        if self.is_scan_matching(code_no):
            try:
                SlideNumbers = code_no.split(slide_split_no)
                SlideNumber = SlideNumbers[-1] if SlideNumbers is not None and len(SlideNumbers) >= 2 else None
                SpecimenNumber = code_no.replace(SlideNumber, '')[:-1] if SlideNumber is not None and len(SlideNumber) >= 1 else code_no
            except Exception as e:
                pass
        if not isinstance(SpecimenNumber, str) or len(SpecimenNumber) <= 0:
            SpecimenNumber = codeString
        return SpecimenNumber, SlideNumber, LineNumber
        pass

    @classmethod
    def all(cls) -> list:
        _item: cls
        items: list[cls]
        try:
            dbController.initEngine()
            with Session(dbController.Engine) as session:
                items = session.query(cls).order_by(cls.ID.asc()).all()
                for _item in items:
                    cls.refreshItem(_item, session)
                session.close()
        except Exception as e:
            from AppLog.logHelper import logDB
            logDB << AppUtils.toString(e)
            items = []
        return items

    @classmethod
    def CodeStringTemplate(cls, CodeString: str):
        item: cls = None
        _item: cls
        if not isinstance(CodeString, str) or len(CodeString) <= 0:
            return item
        items: list[cls] = cls.all()

        for _item in items:
            if _item.is_scan_matching(CodeString):
                item = _item
                break
        return item

    @classmethod
    def default_template(cls):
        item: cls = None
        items: list[cls] = cls.all()
        for _item in items:
            if _item.is_default:
                item = _item
                break
        if item is None:
            item = items[0]
        return item

    @classmethod
    def getTemplate(cls, CodeString: str):
        item: cls = None
        _item: cls
        if not isinstance(CodeString, str) or len(CodeString) <= 0:
            return item
        items: list[cls] = cls.all()

        for _item in items:
            if _item.is_scan_matching(CodeString):
                item = _item
                break
        if item is None:
            for _item in items:
                if _item.is_default:
                    item = _item
                    break
        if item is None:
            item = items[0]
        return item

    @classmethod
    def getCodeStringTemplate(cls, CodeString: str):
        item            : cls               = None
        previewsettings : Previewsettings   = None
        collectsettings : Collectsettings   = None
        _item: cls
        if not isinstance(CodeString, str) or len(CodeString) <= 0:
            return item, previewsettings, collectsettings
        items: list[cls] = cls.all()

        for _item in items:
            if _item.is_scan_matching(CodeString):
                item = _item
                break
        if item is not None:
            previewsettings = Previewsettings.Primary(item.previewsettings_ID)
            collectsettings = Collectsettings.Primary(item.collectsettings_ID)
        return item, previewsettings, collectsettings

    @classmethod
    def ScanningTemplate(cls, name: str):
        item: cls = None
        try:
            dbController.initEngine()
            with Session(dbController.Engine) as session:
                item = session.query(cls).filter(cls.Template_name.in_([f'{name}'])).first()
                session.close()
        except Exception as e:
            from AppLog.logHelper import logDB
            logDB << AppUtils.toString(e)
        return item
    @classmethod
    def getCurrentTemplate(cls, chamber_number: int, row_number: int):
        item: cls = None
        _item: cls
        from AppCore.AppDBModels.SlideModels.ChamberStatusModel import ChamberStatusModel
        model: ChamberStatusModel = ChamberStatusModel.getStatusModel(chamber_number, row_number)
        if model is None or not model.has_CodeString or model.isEmpty():
            return item
        items: list[cls] = cls.all()
        specimen_no : str
        slide_no    : str
        line_no     : str
        for _item in items:
            if _item.is_scan_matching(model.CodeString):
                item = _item
                break
        return item

    @classmethod
    def VerifySpecimenNumber(cls, CodeString: str) -> (str, str, str):
        item: cls = None
        specimen_no : str = None
        slide_no    : str = None
        line_no     : str = None
        try:
            _item: cls
            items: list[cls] = cls.all()
            if not isinstance(CodeString, str) or len(CodeString) <= 0:
                return specimen_no, slide_no, line_no
            for _item in items:
                if _item.is_scan_matching(CodeString):
                    item = _item
                    specimen_no, slide_no, line_no = _item.get_specimen_numbers(CodeString)
                    break
        except Exception as e:
            AppUtils.print_Exception(e)

        return specimen_no, slide_no, line_no

    @classmethod
    def getScanTemplate(cls, level: int):
        item: cls = None
        _item: cls
        from AppCore.AppDBModels.SlideModels.TraySlideModel import TraySlideModel
        from AppCore.AppDBModels.SlideModels.ChamberStatusModel import ChamberStatusModel
        model: TraySlideModel = TraySlideModel.getTraySlideItem(level)
        if model is None or not model.has_CodeString or model.isEmpty():
            return item
        items: list[cls] = cls.all()

        for _item in items:
            if _item.is_scan_matching(model.CodeString):
                item = _item
                specimen_no, slide_no, line_no = _item.get_specimen_numbers(model.CodeString)
                ChamberStatusModel.model_update(ChamberStatusModel.ID == model.ID,
                                                {
                                                    'SpecimenNumber': specimen_no   ,
                                                    'SlideNumber'   : slide_no      ,
                                                    'LineNumber'    : line_no       ,
                                                })

                break
        return item















    __field__ = (
        'ID'                  ,
        'Template_name'       ,
        'separator_no'        ,
        'line_no'             ,
        'scan_matching'       ,
        'color'               ,
        'is_default'          ,
        'focus_point_column'  ,
        'focus_point_row'     ,
        'left'                ,
        'top'                 ,
        'width'               ,
        'height'              ,
        'previewsettings_ID'  ,
        'collectsettings_ID'  ,
    )

    __types__ = (
        int                   ,
        str                   ,
        str                   ,
        str                   ,
        str                   ,
        str                   ,
        int                   ,
        int                   ,
        int                   ,
        int                   ,
        int                   ,
        int                   ,
        int                   ,
        int                   ,
        int                   ,
    )