import sys
sys.path.append('../../')

import struct

from utils.DBModels.DeviceParModels import *
from protocol.ModBus.DPV1Master import DPV1Master
from model.ProjectModel.ParmManage import Parm

class BlockType(Enum):
    class TB(Enum):
        phyTB = -1
        tempTB = -2
        levelTB = -3 # 物位转换块
        pressureTB = -4
    PB = 0
    FB = 1

class BlockManage():
    _instance = None
    _dpv1Master = None

    def __new__(cls, address):
        if not cls._instance:
            cls._instance = super().__new__(cls)
        return cls._instance

    def __init__(self, address = 66):
        self.address = address
        self.initBlocks()

    @property
    def DPV1Master(self):
        if not self._dpv1Master:
            self._dpv1Master = DPV1Master('192.168.3.10', 502)
        return self._dpv1Master
    
    def initBlocks(self):
        if not self.DPV1Master.judgeSlave(self.address):
            raise RuntimeError(f"连接从站{self.address}失败.")
        self.blockDict = {
        BlockType.PB : [],
        BlockType.TB : [],
        BlockType.FB : [],
        }
        dirHeadDatas = self.DPV1Master.readParm(address = self.address, slot = 1, index = 0, length = 12)
        DirID = dirHeadDatas[0]       # 目录id
        DirRevNum = dirHeadDatas[1]   # 目录版本号
        NumDirObj = dirHeadDatas[2]   # 目录对象的个数  (如果整个目录使用多于一个目录对象， 
                                      # 则这此元素被连续定义，就如同使用一个较大的对象。
                                      # 多个目录对象都被连续地列在该目录中。该对象计数整个目录所需的对象。Header对象不计人其)
        NumDirEntry = dirHeadDatas[3] # 目录登录项的总数 (应计算复合列表目录登录项和复合目录登录项的总个数；实际块数量为NumDirEntry - 3)
        FirstCompListDirEntry = dirHeadDatas[4] # 第1个复合列表目录登录项的目录登录项个数 (该数用来计数目录内的登录项， 而不包含该登
                                                # 录项的参数地址。第1 个目录登录项是在复合列表目录登录项中的物理块引用。在计数登录
                                                # 项时，复合列表目录登录项与复合目录登录项之间无间隔)
        NumCompListDirEntry = dirHeadDatas[5] # 功能块类型数量 复合列表目录登录项的个数 计数设备内的不同块类型(物理块、转换块和功能块)和对象类型
                                              #（在本标准范围内仅针对链接对象）

        dirLength = 4 * NumDirEntry
        dirDatas = self.DPV1Master.readParm(address = self.address, slot = 1, index = 1, length = dirLength)
        entryTuples = [(dirDatas[i], dirDatas[i+1]) for i in range(0, len(dirDatas), 2)]

        for typ in [BlockType.PB, BlockType.TB, BlockType.FB]:
            typeIndex = typ.value
            blkDirMesByte = struct.pack('>h', entryTuples[typeIndex][0])
            blkIndex = int(blkDirMesByte[0])  # 目录对象编号
            blkoffect = int(blkDirMesByte[1]) # 块从第几个Dir_Entry开始
            numBlk = entryTuples[typeIndex][1] # 块数量
            # print(blkIndex, blkoffect, numBlk)
            for i in range(numBlk):
                blkEntryListIndex = blkoffect - 1 + i
                blkPointerByte = struct.pack('>h', entryTuples[blkEntryListIndex][0])
                numBlkParms = entryTuples[blkEntryListIndex][1]
                blkSlot = int(blkPointerByte[0])
                blkStartIndex = int(blkPointerByte[1])

                block = Block(typ, self.DPV1Master)
                block.slot = blkSlot
                block.startIndex = blkStartIndex
                block.numParms = numBlkParms
                block.blockIndex = i
                block.address = self.address
                if not block.getTBType():
                self.blockDict[typ].append(block)
                # print(blkSlot, blkIndex)
        # print(self.blockDict)

    def getBlockValues(slef, blockType, blockIndex):
        pass





class Block():
    slot = None
    startIndex = None
    numParms = None
    blockIndex = None
    address = None
    def __init__(self, blockType, DPV1Master):
        self.parms = []
        self.blockType = blockType
        self.addParms()
        self.DPV1Master = DPV1Master
    
    def addParms(self):
        getParmsFunc = {
            BlockType.PB: PhysicalBlock.getallParame,
            BlockType.TB: AIFunctionBlock.getallParame,
            BlockType.FB: PressureTranslationBlock.getallParame,
        }.get(self.blockType, lambda: [])
        
        parmsData = getParmsFunc()
        for parmData in parmsData:
            parm = Parm(parmData, self.slot, self.startIndex, self.DPV1Master)

    def getTBType(self):
        return

    def setTBType(self):







if __name__ == '__main__':
    b = BlockManage(address = 55)
    c = BlockManage(address = 77)
    # b.initBlock()