"""
@Time    : 2019/1/9 10:19
@Author  : Sam
@Project : IEC101
@FileName: AppLayer.py
@Software: PyCharm
@Blog    : https://blog.muumlover.com
"""
import logging

from .Base import *
from .LinkLayer import LinkLayer


def pop_from_buffer(buffer, length):
    if length == 2:
        value = int.from_bytes(buffer[0:2], byteorder='little')
        buffer.pop(0)
        buffer.pop(0)
    else:
        value = buffer.pop(0)
    return value


class ICE101(LinkLayer):
    # region 属性
    # ICE地址
    @property
    def Addr(self):
        return self.id

    @Addr.setter
    def Addr(self, value):
        self.id = value
    #
    # # ICE名称
    # @property
    # def Name(self):
    #     return self.name
    #
    # @Name.setter
    # def Name(self, value):
    #     self.name = value

    # endregion

    # region 事件
    # public delegate void DeatYxDelegate(byte addrYx, bool valueYx)
    # public event DeatYxDelegate DeatYx
    #
    # public delegate void DeatYcDelegate(byte addrYc, double valueYc)
    # public event DeatYcDelegate DeatYc
    # endregion

    # region 方法
    # def ICE101(self):
    #     pass
    #
    # def ICE101(self, socketThread: SocketThread):
    #     BindSocket(socketThread)

    def SinglePoint(self, vsq, infoAddr, buffer, typeid):
        # 判断可变结构限定词类型
        if vsq.SQ:  # SQ==1元素序列
            # 判断是否为第一次读取遥信点
            if infoAddr == 0:
                infoAddr = pop_from_buffer(buffer, self.InfoAddrLength)
            else:
                infoAddr += 1
        else:  # SQ==0信息对象序列
            # 判断剩余长度是否充足
            if len(buffer) > self.InfoAddrLength:
                infoAddr = pop_from_buffer(buffer, self.InfoAddrLength)
            else:
                return None

        # 读取遥信起始地址
        addrYxStart = self.YxStartAddr if typeid == 1 else self.Yx2StartAddr  # Convert.ToInt16(SqliteProvider.ReadPara(SqliteProvider.icepara, (typeid == 1) ? "YXStartAddr" : "YX2StartAddr"))
        # 计算遥信地址
        addrYx = infoAddr - addrYxStart + 1
        # 读取遥信值
        valueYx = buffer.pop(0)
        # 遥信地址为0——无效的遥信点
        if addrYx > 0:
            value = (valueYx == 0x01) if (typeid == 1) else (valueYx == 0x10)
            # 处理遥信
            # DeatYx?.Invoke(addrYx, value)
            pass

    def Measurements(self, vsq, infoAddr, buffer, typeid):
        # 判断可变结构限定词类型
        if vsq.SQ:
            # SQ==1元素序列
            # 判断是否为第一次读取遥信点
            if infoAddr == 0:
                infoAddr = pop_from_buffer(buffer, self.InfoAddrLength)
            else:
                infoAddr += 1
        else:
            # SQ==0信息对象序列
            # 判断剩余长度是否充足
            if len(buffer) > self.InfoAddrLength:
                infoAddr = pop_from_buffer(buffer, self.InfoAddrLength)
            else:
                return None

        # 读取遥ce起始地址
        addrYcStart = self.YcStartAddr  # Convert.ToInt16(SqliteProvider.ReadPara(SqliteProvider.icepara, (typeid == 1) ? "YXStartAddr" : "YX2StartAddr"))
        # 计算遥信地址
        addrYc = (infoAddr - addrYcStart + 1)
        # 读取遥信值
        valueYc = buffer.pop(0)
        # 遥信地址为0——无效的遥信点
        if addrYc > 0:
            # 处理遥信
            # DeatYc?.Invoke(addrYc, valueYc)
            pass


    def Deal(self, data: bytearray):
        # 建立数据处理缓存区
        buffer = data[:]

        # 类型标识
        typeid = buffer.pop(0)
        typeIdName = self.TypeIdShow.get(typeid, '未知类型标识')
        # Convert.ToString(SqliteProvider.ReadIndexValue("typeidmap", "Name", typeid))

        # 可变结构限定词
        dataType = buffer.pop(0)

        # 建立VSQ解析实体
        vsq = VariableStructureQualifier()
        vsq.join_frame = dataType

        # 传送原因
        cause = 0
        if self.CauseLength == 2:
            # self.cause = System.BitConverter.ToInt16(buffer.ToArray(), 0)
            # buffer.RemoveRange(0, 2)
            cause = int.from_bytes(buffer[0:2], byteorder='little')
            buffer.pop(0)
            buffer.pop(0)
        else:
            cause = buffer.pop(0)
        causeName = self.CauseShow.get(cause, '未知传送原因')
        # Convert.ToString(SqliteProvider.ReadIndexValue("causemap", "Name", cause))
        # 应用层公共地址域
        publicAddr = 0
        if self.PublicAddrLength == 2:
            publicAddr = int.from_bytes(buffer[0:2], byteorder='little')
            buffer.pop(0)
            buffer.pop(0)
        else:
            publicAddr = buffer.pop(0)

        # logging.info("上报设备“{0}”。".format(self.name))
        logging.info("收到 {0}({1})。".format(typeIdName, causeName))

        # 信息体读取计数
        count = 0
        # 信息体地址
        infoAddr = 0

        # 处理所有信息体
        while count < vsq.length:
            count += 1
            # 读取信息体
            if typeid in [1, 3]:  # 单点信息 #双点信息
                # self.SinglePoint(vsq, infoAddr, buffer, typeid)
                pass
            elif typeid in [9]:  # 归一化值
                # self.Measurements(vsq, infoAddr, buffer, typeid)
                pass
            elif typeid in [70]:  # 初始化结束
                # bool obj = False
                if self.thisICEState == ICEState.LinkFinishSlave or self.thisICEState == ICEState.LinkFinishMaster:
                    self.thisICEState = ICEState.LinkFinish
                    logging.info("设备“{0}”初始化完毕。".format(self.name))
                if self.CallAfterInit:
                    return self.iec_call(False)
            else:
                buffer.clear()
        return None


if __name__ == '__main__':
    # logging.Formatter.default_msec_format = '%s.%03d'
    logging.basicConfig(level=logging.DEBUG,
                        format='%(threadName)s:  %(asctime)s.%(msecs)03d  '
                               '%(levelname)s %(process)d %(thread)d '
                               '[%(filename)s:%(lineno)d] --- [%(funcName)s]  '
                               '%(module)s :\t%(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S',
                        filename='./test.log',
                        filemode='w'  # ,
                        # stream=sys.stdout
                        )

    loop = asyncio.get_event_loop()
    # Each client connection will create a new protocol instance
    coro = loop.create_server(lambda: ICE101(loop), '127.0.0.1', 2404)
    server = loop.run_until_complete(coro)

    # Serve requests until Ctrl+C is pressed
    print('Serving on {}'.format(server.sockets[0].getsockname()))
    try:
        loop.run_forever()
    except KeyboardInterrupt:
        pass
