using System;
using System.Collections.Generic;
using System.Net;
using System.Runtime.InteropServices;
using TouchSocket.Core.ByteManager;
using TouchSocket.Sockets;

namespace Rdh.SocketServer.Client.Models
{
    public class RfidUdpDataHandlingAdapter : UdpDataHandlingAdapter
    {
        public override bool CanSendRequestInfo => false;

        public override bool CanSplicingSend => false;

        public int HeaderLength => 5;

        /// <summary>
        /// 临时包，此包仅当前实例储存
        /// </summary>
        private ByteBlock tempByteBlock;
        /// <summary>
        /// 包剩余长度
        /// </summary>
        private byte surPlusLength;

        protected override void PreviewReceived(EndPoint remoteEndPoint, ByteBlock byteBlock)
        {
            byte[] buffer = byteBlock.Buffer;
            int r = byteBlock.Len;
            if (this.tempByteBlock == null)//如果没有临时包，则直接分包。
            {
                SplitPackage(remoteEndPoint, buffer, 0, r);
            }
            else
            {
                if (surPlusLength == r)//接收长度正好等于剩余长度，组合完数据以后直接处理数据。
                {
                    this.tempByteBlock.Write(buffer, 0, surPlusLength);
                    PreviewHandle(remoteEndPoint, this.tempByteBlock);
                    this.tempByteBlock = null;
                    surPlusLength = 0;
                }
                else if (surPlusLength < r)//接收长度大于剩余长度，先组合包，然后处理包，然后将剩下的分包。
                {
                    this.tempByteBlock.Write(buffer, 0, surPlusLength);
                    PreviewHandle(remoteEndPoint, this.tempByteBlock);
                    this.tempByteBlock = null;
                    SplitPackage(remoteEndPoint, buffer, surPlusLength, r);
                }
                else//接收长度小于剩余长度，无法处理包，所以必须先组合包，然后等下次接收。
                {
                    this.tempByteBlock.Write(buffer, 0, r);
                    surPlusLength -= (byte)r;
                }
            }
        }
        /// <summary>
        /// 分解包
        /// </summary>
        /// <param name="dataBuffer"></param>
        /// <param name="index"></param>
        /// <param name="r"></param>
        private void SplitPackage(EndPoint remoteEndPoint, byte[] dataBuffer, int index, int r)
        {
            while (index < r)
            {
                byte length = dataBuffer[index];
                int recedSurPlusLength = r - index - 1;
                if (recedSurPlusLength >= length)
                {
                    ByteBlock byteBlock = BytePool.GetByteBlock(length);
                    byteBlock.Write(dataBuffer, index + 1, length);
                    PreviewHandle(remoteEndPoint, byteBlock);
                    surPlusLength = 0;
                }
                else//半包
                {
                    this.tempByteBlock = BytePool.GetByteBlock(length);
                    surPlusLength = (byte)(length - recedSurPlusLength);
                    this.tempByteBlock.Write(dataBuffer, index + 1, recedSurPlusLength);
                }
                index += length + 1;
            }
        }
        /// <summary>
        /// 处理数据
        /// </summary>
        /// <param name="byteBlock"></param>
        private void PreviewHandle(EndPoint remoteEndPoint, ByteBlock byteBlock)
        {
            try
            {
                var requestInfo = new RfidFixedHeaderRequestInfo();
                byteBlock.Read(out byte[] header, this.HeaderLength);
                requestInfo.OnParsingHeader(header);
                byteBlock.Read(out byte[] body, requestInfo.BodyLength);
                requestInfo.OnParsingBody(body);

                this.GoReceived(remoteEndPoint, byteBlock, requestInfo);
            }
            finally
            {
                byteBlock.Dispose();//在框架里面将内存块释放
            }
        }


        protected override void Reset()
        {

        }

        protected override void PreviewSend(EndPoint endPoint, byte[] buffer, int offset, int length, bool isAsync)
        {
            this.GoSend(endPoint, buffer, offset, length, isAsync);
        }

        protected override void PreviewSend(IRequestInfo requestInfo, bool isAsync)
        {

        }

        protected override void PreviewSend(EndPoint endPoint, IList<ArraySegment<byte>> transferBytes, bool isAsync)
        {
            throw new System.NotImplementedException();
        }
    }

    public class RfidFixedHeaderRequestInfo : IFixedHeaderRequestInfo
    {
        private const int head = 0xA5;
        /// <summary>
        /// 数据包头
        /// </summary>
        public static int Head { get { return head; } }

        private int bodyLength;
        public int BodyLength
        {
            get { return bodyLength; }
        }

        private byte[] reserved;
        /// <summary>
        /// 485地址码
        /// </summary>
        public byte[] Reserved { get { return reserved; } }

        private int cmd;
        /// <summary>
        /// 指令码
        /// </summary>
        public int CMD { get { return cmd; } }

        private byte[] header;
        public byte[] Header { get { return header; } }

        private byte[] body;
        public byte[] Body
        {
            get { return body; }
        }

        public bool OnParsingBody(byte[] body)
        {
            this.bodyLength = body.Length;
            this.body = body;
            return true;
        }

        public bool OnParsingHeader(byte[] header)
        {
            if (header.Length == 5 && header[0] == 0xA5)
            {
                this.bodyLength = header[1];
                this.reserved = new byte[2];
                Buffer.BlockCopy(header, 2, this.reserved, 0, 2);
                this.cmd = header[4];

                this.header = header;
                return true;
            }
            return false;
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct MtBarcodeResponseProtocol
    {
        #region Properties
        /// <summary>
        /// 起始位
        /// </summary>
        public Byte Head { get { return 0xA5; } }
        /// <summary>
        /// Length（不含）之后的数据长度
        /// </summary>
        public Byte Length { get; set; }
        /// <summary>
        /// 低字节在前，高字节在后
        /// </summary>
        public UInt16 Password { get; set; }
        /// <summary>
        /// 指令码
        /// </summary>
        public Byte Command { get; set; }
        /// <summary>
        /// 0x01:数据包标识
        /// </summary>
        public Byte Flags { get; set; }
        /// <summary>
        /// 读取的频点
        /// </summary>
        public Byte Frequency { get; set; }
        /// <summary>
        /// 天线号
        /// </summary>
        public Byte Anntennea { get; set; }
        /// <summary>
        /// 标签的 PC 协议控制字,固定 2Byte
        /// </summary>
        public UInt16 PC { get; set; }
        /// <summary>
        /// 标签的 EPC 号(条码)，长度可变化
        /// </summary>
        public String EPC { get; set; }
        /// <summary>
        /// 标签的 CRC，固定 2Byte
        /// </summary>
        public UInt16 CRC { get; set; }
        /// <summary>
        /// 标签的实时 RSSI，固定 2Byte
        /// </summary>
        public UInt16 RSSI { get; set; }
        /// <summary>
        /// 校验和(除校验本身以外所有字节求和后，按位取反，再加 1)
        /// </summary>
        public Byte Check { get; set; }
        #endregion
        public Byte[] GetBytes()
        {
            return StructToBytes<MtBarcodeResponseProtocol>(this);
        }
        public override string ToString()
        {
            return ToString(" ");
        }
        public String ToString(String seperator)
        {
            return String.Join(seperator, GetBytes());
        }
        public static MtBarcodeResponseProtocol? ReadFromBytes(Byte[] source, Int32 dataLength)
        {
            if (dataLength < 16 || source.Length < 16)
            {
                return null;
            }
            MtBarcodeResponseProtocol rlt = new MtBarcodeResponseProtocol();
            rlt.Length = source[1];
            rlt.Password = (UInt16)(source[2] | (source[3] << 8));
            rlt.Command = source[4];
            rlt.Flags = source[5];
            rlt.Frequency = source[6];
            rlt.Anntennea = source[7];
            rlt.PC = (UInt16)(source[8] | (source[9] << 8));
            Int32 epcDataLength = rlt.Length - 13;
            for (Int32 i = 0; i < epcDataLength; i++)
            {
                rlt.EPC += source[10 + i].ToString("X2");
            }
            rlt.Check = source[dataLength - 1];
            rlt.RSSI = (UInt16)(source[dataLength - 2] << 8 | source[dataLength - 3]);
            rlt.CRC = (UInt16)(source[dataLength - 4] | source[dataLength - 5]);
            return rlt;
        }

        public static MtBarcodeResponseProtocol? ReadFromBytes(Byte[] source)
        {
            var dataLength = source.Length;
            if (dataLength < 16 || source.Length < 16)
            {
                return null;
            }
            MtBarcodeResponseProtocol rlt = new MtBarcodeResponseProtocol();
            rlt.Length = source[1];
            rlt.Password = (UInt16)(source[2] | (source[3] << 8));
            rlt.Command = source[4];
            rlt.Flags = source[5];
            rlt.Frequency = source[6];
            rlt.Anntennea = source[7];
            rlt.PC = (UInt16)(source[8] | (source[9] << 8));
            Int32 epcDataLength = rlt.Length - 13;
            for (Int32 i = 0; i < epcDataLength; i++)
            {
                rlt.EPC += source[10 + i].ToString("X2");
            }
            rlt.Check = source[dataLength - 1];
            rlt.RSSI = (UInt16)(source[dataLength - 2] << 8 | source[dataLength - 3]);
            rlt.CRC = (UInt16)(source[dataLength - 4] | source[dataLength - 5]);
            return rlt;
        }

        public static byte[] StructToBytes<T>(T structObj)
        {
            int size = Marshal.SizeOf(structObj);
            IntPtr buffer = Marshal.AllocHGlobal(size);
            try
            {
                Marshal.StructureToPtr(structObj, buffer, false);
                byte[] bytes = new byte[size];
                Marshal.Copy(buffer, bytes, 0, size);
                return bytes;
            }
            finally
            {
                Marshal.FreeHGlobal(buffer);
            }

        }
    }
}
