namespace PlcSiemens.O
{
    public static class ExtensionHelper
    {
        public static byte[] Reverse(this byte[] buf, int index, int length)
        {
            Array.Reverse(buf, index, length);
            return buf;
        }

        public static int CompareTo(this byte[] source, Int64 start, Int64 count, byte[] buffer, Int64 offset = 0, Int64 length = -1)
        {
            if (source == buffer) return 0;

            if (start < 0) start = 0;
            if (count <= 0 || count > source.Length - start) count = source.Length - start;
            if (length <= 0 || length > buffer.Length - offset) length = buffer.Length - offset;

            // 逐字节比较
            for (int i = 0; i < count && i < length; i++)
            {
                int rs = source[start + i].CompareTo(buffer[offset + i]);
                if (rs != 0) return i > 0 ? i : 1;
            }

            // 比较完成。如果长度不相等，则较长者较大
            if (count != length) return count > length ? 1 : -1;

            return 0;
        }
    }

    public class ByteBuffer
    {
        private readonly byte[] _bufferCache;

        /// <summary>
        /// 缓冲区
        /// </summary>
        public byte[] Buffer { get; private set; }

        /// <summary>
        /// 当前读取位置
        /// </summary>
        public int ReadIndex { get; private set; }

        /// <summary>
        /// 当前写入位置
        /// </summary>
        public int WriteIndex { get; private set; }

        /// <summary>
        /// 设置读取位置标记
        /// </summary>
        public int MarkReadIndex { get; private set; }

        /// <summary>
        /// 设置写入位置标记
        /// </summary>
        public int MarkWirteIndex { get; private set; }

        /// <summary>
        /// 当前缓冲大小
        /// </summary>
        public int Capacity { get; private set; }

        /// <summary>
        /// 缓冲扩充单位
        /// </summary>
        public int CapacityUnit { get; set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="capacity"></param>
        private ByteBuffer(int capacity = 1024)
        {
            _bufferCache = new byte[0x10];
            Buffer = new byte[capacity];
            Capacity = capacity;
            CapacityUnit = Capacity;
        }

        /// <summary>
        /// 构建一个<see cref="ByteBuffer"/>对象
        /// </summary>
        /// <param name="capacity"></param>
        /// <returns></returns>
        public static ByteBuffer Allocate(int capacity = 1024)
        {
            return new ByteBuffer(capacity);
        }

        /// <summary>
        /// 计算扩容需量
        /// </summary>
        /// <param name="length"></param>
        /// <returns></returns>
        private int FixLength(int length)
        {
            int n = 2;
            int b = 2;
            while (b < length)
            {
                b = 2 << n;
                n++;
            }
            return (b / CapacityUnit + 1) * CapacityUnit;
        }

        /// <summary>
        /// 长度不够扩充<see cref="Buffer"/>容量
        /// </summary>
        /// <param name="currLen"></param>
        /// <param name="futureLen"></param>
        /// <returns></returns>
        private int FixSizeAndReset(int currLen, int futureLen)
        {
            if (futureLen > currLen)
            {
                int size = FixLength(currLen) + Capacity;
                byte[] newbuf = new byte[size];
                Array.Copy(Buffer, 0, newbuf, 0, currLen);
                Buffer = newbuf;
                Capacity = newbuf.Length;
            }
            return futureLen;
        }

        #region 压入对象

        public void Push(byte[] bytes, int startIndex, int length)
        {
            lock (this)
            {
                int offset = length - startIndex;
                if (offset <= 0) return;
                int total = offset + WriteIndex;
                int len = Buffer.Length;
                FixSizeAndReset(len, total);
                for (int i = WriteIndex, j = startIndex; i < total; i++, j++)
                {
                    Buffer[i] = bytes[j];
                }
                WriteIndex = total;
            }
        }

        /// <summary>
        /// 写入字节数组
        /// </summary>
        /// <param name="bytes"></param>
        /// <param name="length"></param>
        /// <param name="reversed"></param>
        public void Push(byte[] bytes, int length, bool reversed = false)
        {
            if (reversed) bytes = bytes.Reverse(0, length);
            Push(bytes, 0, length);
        }

        /// <summary>
        /// 写入字节数组
        /// </summary>
        /// <param name="bytes"></param>
        /// <param name="reversed"></param>
        public void Push(byte[] bytes, bool reversed = false)
        {
            Push(bytes, bytes.Length, reversed);
        }

        /// <summary>
        /// 写入另一个<see cref="ByteBuffer"/>对象
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="reversed"></param>
        public void Push(ByteBuffer buffer, bool reversed = false)
        {
            if (buffer == null) return;
            if (buffer.ReadableBytes() <= 0) return;
            Push(buffer.ToArray(), reversed);
        }

        /// <summary>
        /// 写入一个<see cref="short"/>对象
        /// </summary>
        /// <param name="value"></param>
        /// <param name="reversed"></param>
        public void Push(short value, bool reversed = false)
        {
            Push((ushort)value, reversed);
        }

        /// <summary>
        /// 写入一个<see cref="ushort"/>对象
        /// </summary>
        /// <param name="value"></param>
        /// <param name="reversed"></param>
        public void Push(ushort value, bool reversed = false)
        {
            _bufferCache[0] = (byte)(value >> 8);
            _bufferCache[1] = (byte)value;

            Push(_bufferCache, 2, reversed);
        }

        public void Push(char value, bool reversed = false)
        {
            Push((short)value, reversed);
        }

        /// <summary>
        /// 写入一个<see cref="int"/>对象
        /// </summary>
        /// <param name="value"></param>
        /// <param name="reversed"></param>
        public void Push(int value, bool reversed = false)
        {
            Push((uint)value);
        }

        /// <summary>
        /// 写入一个<see cref="uint"/>对象
        /// </summary>
        /// <param name="value"></param>
        /// <param name="reversed"></param>
        public void Push(uint value, bool reversed = false)
        {
            _bufferCache[0] = (byte)(value >> 0x18);
            _bufferCache[1] = (byte)(value >> 0x10);
            _bufferCache[2] = (byte)(value >> 8);
            _bufferCache[3] = (byte)value;

            Push(_bufferCache, 4, reversed);
        }

        /// <summary>
        /// 写入一个<see cref="long"/>对象
        /// </summary>
        /// <param name="value"></param>
        /// <param name="reversed"></param>
        public void Push(long value, bool reversed = false)
        {
            Push((ulong)value);
        }

        /// <summary>
        /// 写入一个<see cref="ulong"/>对象
        /// </summary>
        /// <param name="value"></param>
        /// <param name="reversed"></param>
        public void Push(ulong value, bool reversed = false)
        {
            _bufferCache[0] = (byte)(value >> 0x38);
            _bufferCache[1] = (byte)(value >> 0x30);
            _bufferCache[2] = (byte)(value >> 0x28);
            _bufferCache[3] = (byte)(value >> 0x20);
            _bufferCache[4] = (byte)(value >> 0x18);
            _bufferCache[5] = (byte)(value >> 0x10);
            _bufferCache[6] = (byte)(value >> 8);
            _bufferCache[7] = (byte)value;

            Push(_bufferCache, 8, reversed);
        }

        /// <summary>
        /// 写入一个<see cref="float"/>对象
        /// </summary>
        /// <param name="value"></param>
        /// <param name="reversed"></param>
        public void Push(float value, bool reversed = false)
        {
            var buf = BitConverter.GetBytes(value);

            Push(buf, reversed);
        }

        /// <summary>
        /// 写入一个<see cref="byte"/>对象
        /// </summary>
        /// <param name="value"></param>
        public void Push(byte value)
        {
            lock (this)
            {
                int afterLen = WriteIndex + 1;
                int len = Buffer.Length;
                FixSizeAndReset(len, afterLen);
                Buffer[WriteIndex] = value;
                WriteIndex = afterLen;
            }
        }

        /// <summary>
        /// 写入一个<see cref="double"/>对象
        /// </summary>
        /// <param name="value"></param>
        /// <param name="reversed"></param>
        public void Push(double value, bool reversed = false)
        {
            var buf = BitConverter.GetBytes(value);

            Push(buf, reversed);
        }

        #endregion 压入对象

        #region pop出一个对象

        /// <summary>
        /// 读取一个<see cref="byte"/>
        /// </summary>
        /// <returns></returns>
        public byte PopByte()
        {
            byte b = Buffer[ReadIndex];
            ReadIndex++;
            return b;
        }

        /// <summary>
        /// 读取指定的<see cref="byte"/>[]
        /// </summary>
        /// <param name="len"></param>
        /// <param name="reversed"></param>
        /// <returns></returns>
        private byte[] Pop(int len, bool reversed = false)
        {
            byte[] bytes = new byte[len];
            Array.Copy(Buffer, ReadIndex, bytes, 0, len);
            if (reversed)
                Array.Reverse(bytes);
            ReadIndex += len;
            return bytes;
        }

        /// <summary>
        /// 读取指定的<see cref="ushort"/>
        /// </summary>
        /// <returns></returns>
        public ushort PopUshort(bool reversed = false)
        {
            var buf = Pop(2, reversed);
            return (ushort)(buf[0] << 8 | buf[1]);
        }

        /// <summary>
        /// 读取指定的<see cref="ushort"/>
        /// </summary>
        /// <returns></returns>
        public char PopChar(bool reversed = false)
        {
            var buf = Pop(2, reversed);
            return (char)(buf[0] << 8 | buf[1]);
        }

        /// <summary>
        /// 读取指定的<see cref="short"/>
        /// </summary>
        /// <param name="reversed"></param>
        /// <returns></returns>
        public short PopShort(bool reversed = false)
        {
            var buf = Pop(2, reversed);
            return (short)(buf[0] << 8 | buf[1]);
        }

        /// <summary>
        /// 读取指定的<see cref="uint"/>
        /// </summary>
        /// <param name="reversed"></param>
        /// <returns></returns>
        public uint PopUint(bool reversed = false)
        {
            var buf = Pop(4, reversed);
            return (uint)(buf[0] << 0x18 | buf[1] << 0x10 | buf[2] << 0x8 | buf[3]);
        }

        /// <summary>
        /// 读取指定的<see cref="int"/>
        /// </summary>
        /// <param name="reversed"></param>
        /// <returns></returns>
        public int PopInt(bool reversed = false)
        {
            var buf = Pop(4, reversed);
            return buf[0] << 0x18 |
                   buf[1] << 0x10 |
                   buf[2] << 0x8 |
                   buf[3];
        }

        /// <summary>
        /// 读取指定的<see cref="ulong"/>
        /// </summary>
        /// <param name="reversed"></param>
        /// <returns></returns>
        public ulong PopUlong(bool reversed = false)
        {
            var buf = Pop(8, reversed);
            return (ulong)(buf[0] << 0x38 |
                           buf[1] << 0x30 |
                           buf[2] << 0x28 |
                           buf[3] << 0x20 |
                           buf[4] << 0x18 |
                           buf[5] << 0x10 |
                           buf[6] << 0x08 |
                           buf[7]);
        }

        /// <summary>
        /// 读取指定的<see cref="long"/>
        /// </summary>
        /// <param name="reversed"></param>
        /// <returns></returns>
        public long PopLong(bool reversed = false)
        {
            var buf = Pop(8, reversed);
            return buf[0] << 0x38 |
                   buf[1] << 0x30 |
                   buf[2] << 0x28 |
                   buf[3] << 0x20 |
                   buf[4] << 0x18 |
                   buf[5] << 0x10 |
                   buf[6] << 0x08 |
                   buf[7];
        }

        /// <summary>
        /// 读取指定的<see cref="float"/>
        /// </summary>
        /// <param name="reversed"></param>
        /// <returns></returns>
        public float PopFloat(bool reversed = false)
        {
            return BitConverter.ToSingle(Pop(4, reversed), 0);
        }

        /// <summary>
        /// 读取指定的<see cref="double"/>
        /// </summary>
        /// <param name="reversed"></param>
        /// <returns></returns>
        public double PopDouble(bool reversed = false)
        {
            return BitConverter.ToDouble(Pop(8, reversed), 0);
        }

        /// <summary>
        /// 读取指定长度的<see cref="byte"/>[]
        /// </summary>
        /// <param name="desBytes"></param>
        /// <param name="desStart"></param>
        /// <param name="len"></param>
        public void PopBytes(byte[] desBytes, int desStart, int len)
        {
            int size = desStart + len;
            for (int i = desStart; i < size; i++)
            {
                desBytes[i] = PopByte();
            }
        }

        public byte[] PopBytes(int len)
        {
            var buf = new byte[len];
            for (int i = 0; i < len; i++)
            {
                buf[i] = PopByte();
            }

            return buf;
        }

        #endregion pop出一个对象

        /// <summary>
        /// 清除已读缓冲 后续队列前移
        /// </summary>
        public void DiscardReadBytes()
        {
            if (ReadIndex <= 0) return;
            int len = Buffer.Length - ReadIndex;
            byte[] newbuf = new byte[Buffer.Length];
            Array.Copy(Buffer, ReadIndex, newbuf, 0, len);
            Buffer = newbuf;
            WriteIndex -= ReadIndex;
            MarkReadIndex -= ReadIndex;
            if (MarkReadIndex < 0)
            {
                MarkReadIndex = ReadIndex;
            }
            MarkWirteIndex -= ReadIndex;
            if (MarkWirteIndex < 0 || MarkWirteIndex < ReadIndex || MarkWirteIndex < MarkReadIndex)
            {
                MarkWirteIndex = WriteIndex;
            }
            ReadIndex = 0;
        }

        /// <summary>
        /// 清空缓存
        /// </summary>
        public void Clear()
        {
            Buffer = new byte[Buffer.Length];
            ReadIndex = 0;
            WriteIndex = 0;
            MarkReadIndex = 0;
            MarkWirteIndex = 0;
        }

        /// <summary>
        /// 设置缓存读取位置
        /// </summary>
        /// <param name="index"></param>
        public void SetReaderIndex(int index)
        {
            if (index < 0) return;
            ReadIndex = index;
        }

        /// <summary>
        /// 标记当前读取的索引位置
        /// </summary>
        public void MarkReaderIndex()
        {
            MarkReadIndex = ReadIndex;
        }

        /// <summary>
        /// 标记当前写入的索引位置
        /// </summary>
        public void MarkWriterIndex()
        {
            MarkWirteIndex = WriteIndex;
        }

        /// <summary>
        /// 将读取的索引位置重置为标记的读取索引位置
        /// </summary>
        public void ResetReaderIndex()
        {
            ReadIndex = MarkReadIndex;
        }

        /// <summary>
        /// 将写入的索引位置重置为标记的写入索引位置
        /// </summary>
        public void ResetWriterIndex()
        {
            WriteIndex = MarkWirteIndex;
        }

        /// <summary>
        /// 剩余可读数量
        /// </summary>
        /// <returns></returns>
        public int ReadableBytes()
        {
            return WriteIndex - ReadIndex;
        }

        /// <summary>
        /// 剩余可读缓存转数组
        /// </summary>
        /// <returns></returns>
        public byte[] ToArray()
        {
            byte[] bytes = new byte[WriteIndex];
            Array.Copy(Buffer, 0, bytes, 0, bytes.Length);
            return bytes;
        }

        public int IndexOf(byte[] buf, int offset = 0, int length = -1)
        {
            if (length <= 0) length = buf.Length - offset;

            // 位置
            int p = -1;
            for (int i = 0; i < length;)
            {
                if (ReadableBytes() < 1) return -1;
                int c = PopByte();
                if (c == -1) return -1;

                p++;
                if (c == buf[offset + i])
                {
                    i++;

                    // 全部匹配，退出
                    if (i >= length) return p - length + 1;
                }
                else
                {
                    int n = i;
                    i = 0;
                    for (int j = 1; j < n; j++)
                    {
                        // 在字节数组前(j,n)里面找自己(0,n-j)
                        if (buf.CompareTo(j, n, buf, 0, n - j) == 0)
                        {
                            // 前面(0,n-j)相等，窗口退回到这里
                            i = n - j;
                            break;
                        }
                    }
                }
            }

            return -1;
        }

        public bool EnsureStartWith(byte[] buf, int offset = 0, int length = -1)
        {
            if (buf.Length < offset) throw new ArgumentOutOfRangeException("offset");
            if (offset < 0) offset = 0;
            if (length < 0 || buf.Length < (offset + length)) length = buf.Length - offset;
            int index = IndexOf(buf, offset, length);
            if (index == -1)
            {
                //重建缓冲清除数据
                //DiscardReadBytes();
                //不能重建缓冲 有可能尾部有数据部分匹配而导致数据丢失
                //重置ReaderIndex即可
                SetReaderIndex(0);

                return false;
            }

            if (index == 0) return true;

            SetReaderIndex(index);
            DiscardReadBytes();

            return true;
        }
    }
}
