using System;
using System.Collections.Generic;
using System.Linq;

namespace Modbus.Net.Siemens
{
    /// <summary>
    ///     西门子数据类型
    /// </summary>
    public enum SiemensTypeCode : byte
    {
        /// <summary>
        ///     布尔
        /// </summary>
        Bool = 0x01,

        /// <summary>
        ///     字节
        /// </summary>
        Byte = 0x02,

        /// <summary>
        ///     字
        /// </summary>
        Word = 0x03,

        /// <summary>
        ///     双字
        /// </summary>
        DWord = 0x04,

        /// <summary>
        ///     计数器
        /// </summary>
        C = 0x1E,

        /// <summary>
        ///     计时器
        /// </summary>
        T = 0x1F,

        /// <summary>
        ///     高速计数器
        /// </summary>
        HC = 0x20
    }

    /// <summary>
    ///     西门子通讯报错信息
    /// </summary>
    public enum SiemensAccessResult : byte
    {
        /// <summary>
        ///     无错误
        /// </summary>
        NoError = 0xFF,

        /// <summary>
        ///     硬件错误
        /// </summary>
        HardwareFault = 0x01,

        /// <summary>
        ///     非法对象访问（Area错误）
        /// </summary>
        IllegalObjectAccess = 0x03,

        /// <summary>
        ///     非法地址访问
        /// </summary>
        InvalidAddress = 0x05,

        /// <summary>
        ///     不支持的数据类型
        /// </summary>
        DataTypeNotSupport = 0x06,

        /// <summary>
        ///     对象不存在或长度超出允许范围
        /// </summary>
        ObjNotExistOrLengthError = 0x0A
    }

    /// <summary>
    ///     西门子数据访问类型
    /// </summary>
    public enum SiemensDataType : byte
    {
        /// <summary>
        ///     错误
        /// </summary>
        Error = 0x00,

        /// <summary>
        ///     比特位访问
        /// </summary>
        BitAccess = 0x03,

        /// <summary>
        ///     一般访问
        /// </summary>
        OtherAccess = 0x04
    }

    /// <summary>
    ///     西门子协议
    /// </summary>
    public abstract class SiemensProtocol : BaseProtocol
    {
        /// <summary>
        ///     构造函数
        /// </summary>
        /// <param name="slaveAddress">从站号</param>
        /// <param name="masterAddress">主站号</param>
        protected SiemensProtocol(byte slaveAddress, byte masterAddress)
            : base(slaveAddress, masterAddress, Endian.BigEndianLsb)
        {
        }
    }

    #region 串口连接建立

    internal class ComCreateReferenceSiemensInputStruct : IInputStruct
    {
        public ComCreateReferenceSiemensInputStruct(byte slaveAddress, byte masterAddress)
        {
            SlaveAddress = slaveAddress;
            MasterAddress = masterAddress;
        }

        public byte SlaveAddress { get; set; }
        public byte MasterAddress { get; set; }
    }

    internal class ComCreateReferenceSiemensOutputStruct : IOutputStruct
    {
        public ComCreateReferenceSiemensOutputStruct(byte slaveAddress, byte masterAddress, byte confirmMessage)
        {
            SlaveAddress = slaveAddress;
            MasterAddress = masterAddress;
            ConfirmMessage = confirmMessage;
        }

        public byte SlaveAddress { get; set; }
        public byte MasterAddress { get; set; }
        public byte ConfirmMessage { get; set; }
    }

    [SpecialProtocolUnit]
    internal class ComCreateReferenceSiemensProtocol : ProtocolUnit
    {
        public override byte[] Format(IInputStruct message)
        {
            var r_message = (ComCreateReferenceSiemensInputStruct) message;
            var crc = (r_message.SlaveAddress + r_message.MasterAddress + 0x49) % 256;
            return Format((byte) 0x10, r_message.SlaveAddress, r_message.MasterAddress, (byte) 0x49, (byte) crc,
                (byte) 0x16);
        }

        public override IOutputStruct Unformat(byte[] messageBytes, ref int pos)
        {
            pos = 1;
            var masterAddress = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
            var slaveAddress = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
            var confirmMessage = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
            return new ComCreateReferenceSiemensOutputStruct(slaveAddress, masterAddress, confirmMessage);
        }
    }

    #endregion

    #region 以太网建立连接

    internal class CreateReferenceSiemensInputStruct : IInputStruct
    {
        public byte TdpuSize;

        public ushort TsapDst;

        public ushort TsapSrc;

        public CreateReferenceSiemensInputStruct(byte tdpuSize, ushort srcTsap, ushort dstTsap)
        {
            TdpuSize = tdpuSize;
            TsapSrc = srcTsap;
            TsapDst = dstTsap;
        }
    }

    internal class CreateReferenceSiemensOutputStruct : IOutputStruct
    {
        public CreateReferenceSiemensOutputStruct(byte tdpuSize, ushort srcTsap, ushort dstTsap)
        {
            TdpuSize = tdpuSize;
            TsapSrc = srcTsap;
            TsapDst = dstTsap;
        }

        public byte TdpuSize { get; }
        public ushort TsapSrc { get; }
        public ushort TsapDst { get; }
    }

    [SpecialProtocolUnit]
    internal class CreateReferenceSiemensProtocol : ProtocolUnit
    {
        public override byte[] Format(IInputStruct message)
        {
            var r_message = (CreateReferenceSiemensInputStruct) message;
            const ushort head = 0x0300;
            const ushort len = 0x0016;
            const byte contentLen = 0x11;
            const byte typeCode = 0xe0;
            const ushort dstRef = 0x0000;
            const ushort srcRef = 0x000c;
            const byte reserved = 0x00;
            const ushort tdpuSizeCode = 0xc001;
            var tdpuSizeContent = r_message.TdpuSize;
            const ushort srcTsapCode = 0xc102;
            var srcTsapContent = r_message.TsapSrc;
            const ushort dstTsapCode = 0xc202;
            var dstTsapContent = r_message.TsapDst;
            return Format(head, len, contentLen, typeCode, dstRef, srcRef, reserved, tdpuSizeCode, tdpuSizeContent,
                srcTsapCode, srcTsapContent, dstTsapCode, dstTsapContent);
        }

        public override IOutputStruct Unformat(byte[] messageBytes, ref int pos)
        {
            pos = 11;
            byte tdpuSize = 0;
            ushort srcTsap = 0, dstTsap = 0;
            switch (messageBytes[pos])
            {
                case 0xc0:
                {
                    pos += 2;
                    tdpuSize = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
                    break;
                }
                case 0xc1:
                {
                    pos += 2;
                    srcTsap = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref pos);
                    break;
                }
                case 0xc2:
                {
                    pos += 2;
                    dstTsap = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref pos);
                    break;
                }
            }
            return new CreateReferenceSiemensOutputStruct(tdpuSize, srcTsap, dstTsap);
        }
    }

    #endregion

    #region 串口消息确认 

    /// <summary>
    ///     串口消息确认输入
    /// </summary>
    public class ComConfirmMessageSiemensInputStruct : IInputStruct
    {
        /// <summary>
        ///     构造函数
        /// </summary>
        /// <param name="slaveAddress">从站号</param>
        /// <param name="masterAddress">主站号</param>
        public ComConfirmMessageSiemensInputStruct(byte slaveAddress, byte masterAddress)
        {
            SlaveAddress = slaveAddress;
            MasterAddress = masterAddress;
        }

        /// <summary>
        ///     从站号
        /// </summary>
        public byte SlaveAddress { get; set; }

        /// <summary>
        ///     主站号
        /// </summary>
        public byte MasterAddress { get; set; }
    }

    /// <summary>
    ///     串口消息确认输出
    /// </summary>
    public class ComConfirmMessageSiemensOutputStruct : IOutputStruct
    {
        /// <summary>
        ///     构造函数
        /// </summary>
        /// <param name="confirmByte">确认字节</param>
        public ComConfirmMessageSiemensOutputStruct(byte confirmByte)
        {
            ConfirmByte = confirmByte;
        }

        /// <summary>
        ///     确认字节
        /// </summary>
        public byte ConfirmByte { get; set; }
    }

    /// <summary>
    ///     串口消息确认协议
    /// </summary>
    [SpecialProtocolUnit]
    public class ComConfirmMessageSiemensProtocol : ProtocolUnit
    {
        /// <summary>
        ///     格式化
        /// </summary>
        /// <param name="message">输入参数</param>
        /// <returns>格式化数据</returns>
        public override byte[] Format(IInputStruct message)
        {
            var r_message = (ComConfirmMessageSiemensInputStruct) message;
            var crc = r_message.SlaveAddress + r_message.MasterAddress + 0x5c % 256;
            return Format((byte) 0x10, r_message.SlaveAddress, r_message.MasterAddress, (byte) 0x5c, (byte) crc,
                (byte) 0x16);
        }

        /// <summary>
        ///     反格式化
        /// </summary>
        /// <param name="messageBytes">设备返回的数据</param>
        /// <param name="pos">当前反格式化的位置</param>
        /// <returns>输出数据</returns>
        public override IOutputStruct Unformat(byte[] messageBytes, ref int pos)
        {
            var confirmByte = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
            return new ComConfirmMessageSiemensOutputStruct(confirmByte);
        }
    }

    #endregion

    #region 以太网连接确认

    internal class EstablishAssociationSiemensInputStruct : IInputStruct
    {
        public EstablishAssociationSiemensInputStruct(ushort pduRef, ushort maxCalling, ushort maxCalled, ushort maxPdu)
        {
            PduRef = pduRef;
            MaxCalling = maxCalling;
            MaxCalled = maxCalled;
            MaxPdu = maxPdu;
        }

        public ushort PduRef { get; }
        public ushort MaxCalling { get; }
        public ushort MaxCalled { get; }
        public ushort MaxPdu { get; }
    }

    internal class EstablishAssociationSiemensOutputStruct : IOutputStruct
    {
        public EstablishAssociationSiemensOutputStruct(ushort pduRef, ushort maxCalling, ushort maxCalled,
            ushort maxPdu)
        {
            PduRef = pduRef;
            MaxCalling = maxCalling;
            MaxCalled = maxCalled;
            MaxPdu = maxPdu;
        }

        public ushort PduRef { get; }
        public ushort MaxCalling { get; }
        public ushort MaxCalled { get; }
        public ushort MaxPdu { get; }
    }

    internal class EstablishAssociationSiemensProtocol : ProtocolUnit
    {
        public override byte[] Format(IInputStruct message)
        {
            var r_message = (EstablishAssociationSiemensInputStruct) message;
            const byte protoId = 0x32;
            const byte rosctr = 0x01;
            const ushort redId = 0x0000;
            var pduRef = r_message.PduRef;
            const ushort parLg = 0x0008;
            const ushort datLg = 0x0000;
            const byte serviceId = 0xf0;
            const byte reserved = 0x00;
            var maxCalling = r_message.MaxCalling;
            var maxCalled = r_message.MaxCalled;
            var maxPdu = r_message.MaxPdu;
            return Format(new byte[7], protoId, rosctr, redId, pduRef, parLg, datLg, serviceId, reserved, maxCalling,
                maxCalled, maxPdu);
        }

        public override IOutputStruct Unformat(byte[] messageBytes, ref int pos)
        {
            pos = 4;
            var pduRef = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref pos);
            pos = 14;
            var maxCalling = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref pos);
            var maxCalled = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref pos);
            var maxPdu = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref pos);
            return new EstablishAssociationSiemensOutputStruct(pduRef, maxCalling, maxCalled, maxPdu);
        }
    }

    #endregion

    #region 读数据请求

    /// <summary>
    ///     读数据输入
    /// </summary>
    public class ReadRequestSiemensInputStruct : IInputStruct
    {
        /// <summary>
        ///     构造函数
        /// </summary>
        /// <param name="slaveAddress">从站号</param>
        /// <param name="masterAddress">主站号</param>
        /// <param name="pduRef">报文索引</param>
        /// <param name="getType">获取数据类型</param>
        /// <param name="startAddress">开始地址</param>
        /// <param name="getCount">获取个数</param>
        /// <param name="addressTranslator">地址转换器</param>
        public ReadRequestSiemensInputStruct(byte slaveAddress, byte masterAddress, ushort pduRef,
            SiemensTypeCode getType, string startAddress, ushort getCount, AddressTranslator addressTranslator)
        {
            SlaveAddress = slaveAddress;
            MasterAddress = masterAddress;
            PduRef = pduRef;
            TypeCode = (byte) getType;
            var address = addressTranslator.AddressTranslate(startAddress, true);
            Offset = address.Address;
            var area = address.Area;
            Area = (byte) (area % 256);
            DbBlock = Area == 0x84 ? (ushort) (area / 256) : (ushort) 0;
            NumberOfElements = getCount;
        }

        /// <summary>
        ///     从站号
        /// </summary>
        public byte SlaveAddress { get; set; }

        /// <summary>
        ///     主站号
        /// </summary>
        public byte MasterAddress { get; set; }

        /// <summary>
        ///     报文索引
        /// </summary>
        public ushort PduRef { get; }

        /// <summary>
        ///     地址类型
        /// </summary>
        public byte TypeCode { get; }

        /// <summary>
        ///     读取的个数
        /// </summary>
        public ushort NumberOfElements { get; }

        /// <summary>
        ///     DB块
        /// </summary>
        public ushort DbBlock { get; }

        /// <summary>
        ///     区域
        /// </summary>
        public byte Area { get; }

        /// <summary>
        ///     起始偏移量
        /// </summary>
        public int Offset { get; }
    }

    /// <summary>
    ///     读数据输出
    /// </summary>
    public class ReadRequestSiemensOutputStruct : IOutputStruct
    {
        /// <summary>
        ///     构造函数
        /// </summary>
        /// <param name="pduRef">报文索引</param>
        /// <param name="accessResult">访问结果</param>
        /// <param name="dataType">数据类型</param>
        /// <param name="getLength">获取个数</param>
        /// <param name="value">读取值</param>
        public ReadRequestSiemensOutputStruct(ushort pduRef, SiemensAccessResult accessResult, SiemensDataType dataType,
            ushort getLength, byte[] value)
        {
            PduRef = pduRef;
            AccessResult = accessResult;
            DataType = dataType;
            GetLength = getLength;
            GetValue = value;
        }

        /// <summary>
        ///     报文索引
        /// </summary>
        public ushort PduRef { get; }

        /// <summary>
        ///     访问结果
        /// </summary>
        public SiemensAccessResult AccessResult { get; }

        /// <summary>
        ///     数据类型
        /// </summary>
        public SiemensDataType DataType { get; }

        /// <summary>
        ///     获取个数
        /// </summary>
        public ushort GetLength { get; }

        /// <summary>
        ///     读取值
        /// </summary>
        public byte[] GetValue { get; }
    }

    /// <summary>
    ///     读数据协议
    /// </summary>
    public class ReadRequestSiemensProtocol : ProtocolUnit
    {
        /// <summary>
        ///     格式化
        /// </summary>
        /// <param name="message">输入参数</param>
        /// <returns>格式化数据</returns>
        public override byte[] Format(IInputStruct message)
        {
            var r_message = (ReadRequestSiemensInputStruct) message;
            var slaveAddress = r_message.SlaveAddress;
            var masterAddress = r_message.MasterAddress;
            const byte protoId = 0x32;
            const byte rosctr = 0x01;
            const ushort redId = 0x0000;
            var pduRef = r_message.PduRef;
            const ushort parLg = 14; // 参数字节数（2+12的倍数），目前仅为14
            const ushort datLg = 0; // 数据字节数
            const byte serviceId = 0x04;
            const byte numberOfVariables = 1;
            const byte variableSpec = 0x12;
            const byte vAddrLg = 0x0A;
            const byte syntaxId = 0x10;
            var type = r_message.TypeCode;
            var numberOfElements = r_message.NumberOfElements;
            var dbBlock = r_message.DbBlock;
            var area = r_message.Area;
            var offsetBit = r_message.Offset * 8;
            var offsetBitBytes = BigEndianValueHelper.Instance.GetBytes(offsetBit);
            return Format(new byte[4], slaveAddress, masterAddress, (byte) 0x6c, protoId, rosctr, redId, pduRef, parLg,
                datLg, serviceId, numberOfVariables
                , variableSpec, vAddrLg, syntaxId, type, numberOfElements, dbBlock, area,
                offsetBitBytes.Skip(1).ToArray());
        }

        /// <summary>
        ///     反格式化
        /// </summary>
        /// <param name="messageBytes">设备返回的数据</param>
        /// <param name="pos">当前反格式化的位置</param>
        /// <returns>输出数据</returns>
        public override IOutputStruct Unformat(byte[] messageBytes, ref int pos)
        {
            pos = 4;
            var pduRef = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref pos);
            pos = 14;
            var accessResult = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
            var dataType = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
            var length = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref pos);
            var byteLength = length / 8;
            var values = new byte[byteLength];
            Array.Copy(messageBytes, pos, values, 0, byteLength);
            return new ReadRequestSiemensOutputStruct(pduRef, (SiemensAccessResult) accessResult,
                (SiemensDataType) dataType, length, values);
        }
    }

    #endregion

    #region 写数据请求

    /// <summary>
    ///     写数据输入
    /// </summary>
    public class WriteRequestSiemensInputStruct : IInputStruct
    {
        /// <summary>
        ///     构造函数
        /// </summary>
        /// <param name="slaveAddress">从站地址</param>
        /// <param name="masterAddress">主站地址</param>
        /// <param name="pduRef">报文索引</param>
        /// <param name="startAddress">开始地址</param>
        /// <param name="writeValue">写入值</param>
        /// <param name="addressTranslator">地址转换器</param>
        public WriteRequestSiemensInputStruct(byte slaveAddress, byte masterAddress, ushort pduRef, string startAddress,
            object[] writeValue, AddressTranslator addressTranslator)
        {
            SlaveAddress = slaveAddress;
            MasterAddress = masterAddress;
            PduRef = pduRef;
            var address = addressTranslator.AddressTranslate(startAddress, true);
            Offset = address.Address;
            var area = address.Area;
            Area = (byte) (area % 256);
            DbBlock = Area == 0x84 ? (ushort) (area / 256) : (ushort) 0;
            WriteValue = writeValue;
        }

        /// <summary>
        ///     从站地址
        /// </summary>
        public byte SlaveAddress { get; set; }

        /// <summary>
        ///     主站地址
        /// </summary>
        public byte MasterAddress { get; set; }

        /// <summary>
        ///     报文索引
        /// </summary>
        public ushort PduRef { get; }

        /// <summary>
        ///     DB块
        /// </summary>
        public ushort DbBlock { get; }

        /// <summary>
        ///     区域
        /// </summary>
        public byte Area { get; }

        /// <summary>
        ///     写入偏移量
        /// </summary>
        public int Offset { get; }

        /// <summary>
        ///     写入值
        /// </summary>
        public object[] WriteValue { get; }
    }

    /// <summary>
    ///     写数据输出
    /// </summary>
    public class WriteRequestSiemensOutputStruct : IOutputStruct
    {
        /// <summary>
        ///     构造函数
        /// </summary>
        /// <param name="pduRef">报文索引</param>
        /// <param name="accessResult">访问结果</param>
        public WriteRequestSiemensOutputStruct(ushort pduRef, SiemensAccessResult accessResult)
        {
            PduRef = pduRef;
            AccessResult = accessResult;
        }

        /// <summary>
        ///     报文索引
        /// </summary>
        public ushort PduRef { get; }

        /// <summary>
        ///     访问结果
        /// </summary>
        public SiemensAccessResult AccessResult { get; }
    }

    /// <summary>
    ///     写数据协议
    /// </summary>
    public class WriteRequestSiemensProtocol : ProtocolUnit
    {
        /// <summary>
        ///     格式化
        /// </summary>
        /// <param name="message">输入参数</param>
        /// <returns>格式化数据</returns>
        public override byte[] Format(IInputStruct message)
        {
            var r_message = (WriteRequestSiemensInputStruct) message;
            var valueBytes = BigEndianValueHelper.Instance.ObjectArrayToByteArray(r_message.WriteValue);
            var slaveAddress = r_message.SlaveAddress;
            var masterAddress = r_message.MasterAddress;
            const byte protoId = 0x32;
            const byte rosctr = 0x01;
            const ushort redId = 0x0000;
            var pduRef = r_message.PduRef;
            const ushort parLg = 14; // 参数字节数（2+12的倍数），目前仅为14
            var datLg = (ushort) (4 + valueBytes.Length); // 数据字节数
            const byte serviceId = 0x05;
            const byte numberOfVariables = 1;
            const byte variableSpec = 0x12;
            const byte vAddrLg = 0x0A;
            const byte syntaxId = 0x10;
            const byte typeR = (byte) SiemensTypeCode.Byte;
            var numberOfElements = (ushort) valueBytes.Length;
            var dbBlock = r_message.DbBlock;
            var area = r_message.Area;
            var offsetBit = r_message.Offset * 8;
            var offsetBitBytes = BigEndianValueHelper.Instance.GetBytes(offsetBit);
            const byte reserved = 0x00;
            const byte type = (byte) SiemensDataType.OtherAccess;
            var numberOfWriteBits = (ushort) (valueBytes.Length * 8);
            return Format(new byte[4], slaveAddress, masterAddress, (byte) 0x7c, protoId, rosctr, redId, pduRef, parLg,
                datLg, serviceId, numberOfVariables
                , variableSpec, vAddrLg, syntaxId, typeR, numberOfElements, dbBlock, area,
                offsetBitBytes.Skip(1).ToArray(), reserved, type, numberOfWriteBits, valueBytes);
        }

        /// <summary>
        ///     反格式化
        /// </summary>
        /// <param name="messageBytes">设备返回的数据</param>
        /// <param name="pos">当前反格式化的位置</param>
        /// <returns>输出数据</returns>
        public override IOutputStruct Unformat(byte[] messageBytes, ref int pos)
        {
            if (messageBytes.Length == 1)
            {
                var accessResult = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
                return new WriteRequestSiemensOutputStruct(0,
                    accessResult == 0xe5 ? SiemensAccessResult.NoError : SiemensAccessResult.InvalidAddress);
            }
            else
            {
                pos = 4;
                var pduRef = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref pos);
                pos = 14;
                var accessResult = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
                return new WriteRequestSiemensOutputStruct(pduRef, (SiemensAccessResult) accessResult);
            }
        }
    }

    #endregion

    /*
    #region 读时间请求
    public class ReadTimeSiemensInputStruct : IInputStruct
    {
        public ReadTimeSiemensInputStruct(ushort pduRef)
        {
            PduRef = pduRef;
        }

        public ushort PduRef { get; private set; }
    }

    public class ReadTimeSiemensOutputStruct : IOutputStruct
    {
        public ReadTimeSiemensOutputStruct(ushort pduRef, DateTime dateTime, TodClockStatus todClockStatus)
        {
            PduRef = pduRef;
            DateTime = dateTime;
            TodClockStatus = todClockStatus;
        }

        public ushort PduRef { get; private set; }
        public DateTime DateTime { get; private set; }
        public TodClockStatus TodClockStatus { get; private set; }
    }

    public class ReadTimeSiemensProtocol : ProtocolUnit
    {
        public override byte[] Format(IInputStruct message)
        {
            throw new NotImplementedException();
        }

        public override IOutputStruct Unformat(byte[] messageBytes, ref int pos)
        {
            throw new NotImplementedException();
        }
    }

    #endregion

    #region 写时间请求
    
    public class WriteTimeSiemensInputStruct : IInputStruct
    {
        public WriteTimeSiemensInputStruct(ushort pduRef, DateTime dateTime, TodClockStatus todClockStatus)
        {
            PduRef = pduRef;
            DateTime = dateTime;
            TodClockStatus = todClockStatus;
        }

        public ushort PduRef { get; private set; }
        public DateTime DateTime { get; private set; }
        public TodClockStatus TodClockStatus { get; private set; }
    }

    public class WriteTimeSiemensOutputStruct : IOutputStruct
    {
        public WriteTimeSiemensOutputStruct(ushort pduRef, byte errCod)
        {
            PduRef = pduRef;
            ErrCod = errCod;
        }

        public ushort PduRef { get; private set; }
        public byte ErrCod { get;private set; }
    }

    public class WriteTimeSiemensProtocol : ProtocolUnit
    {
        public override byte[] Format(IInputStruct message)
        {
            throw new NotImplementedException();
        }

        public override IOutputStruct Unformat(byte[] messageBytes, ref int pos)
        {
            throw new NotImplementedException();
        }
    }

    #endregion
    */

    /// <summary>
    ///     西门子通讯报错信息
    /// </summary>
    public class SiemensProtocolErrorException : ProtocolErrorException
    {
        private static readonly Dictionary<int, string> ProtocolErrorDictionary = new Dictionary<int, string>
        {
            {0x00, "No Error"},
            {0x81, "Error in the application Id of the request"},
            {0x82, "Error in the object definition"},
            {0x83, "No recources available"},
            {0x84, "Error in the sructure of the service request"},
            {0x85, "Error in the communitcation equipment"},
            {0x87, "Access Error"},
            {0xD2, "OVS error"},
            {0xD4, "Diagnostic error"},
            {0xD6, "Protection system error"},
            {0xD8, "BuB error"},
            {0xEF, "Layer 2 specific error"}
        };

        private static readonly Dictionary<int, string> ProtocolErrorDetailDictionary = new Dictionary<int, string>
        {
            {0x8304, "Resource not available,\r\n there are no more resources available for application associations to be established" },
            {0x8104, "Context is not supported:\r\n -Error in PDU structure\r\n -Unknown service" },
            {0x8404, "Fatal error detected.\r\n Service or function aborted" },
            {0x8500, "PDU size error"}
        };

        /// <summary>
        ///     构造函数
        /// </summary>
        /// <param name="errCls">错误分类</param>
        /// <param name="errCod">错误码</param>
        public SiemensProtocolErrorException(int errCls, int errCod)
            : base((ProtocolErrorDictionary.ContainsKey(errCls)
                       ? ProtocolErrorDictionary[errCls]
                       : "Unknown error") + " \r\n " +
                   (ProtocolErrorDetailDictionary.ContainsKey(errCls * 256 + errCod)
                       ? ProtocolErrorDetailDictionary[errCls * 256 + errCod]
                       : "Unknown error detail"))
        {
            ErrorClass = errCls;
            ErrorCode = errCod;
        }

        /// <summary>
        ///     错误分类
        /// </summary>
        public int ErrorClass { get; }

        /// <summary>
        ///     错误码
        /// </summary>
        public int ErrorCode { get; }
    }
}