using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

#region << 版 本 注 释 >>
/*--------------------------------------------------------------------
* 版权所有 (c) 2024 WenJY 保留所有权利。
* CLR版本：4.0.30319.42000
* 机器名称：T14-GEN3-7895
* 命名空间：ConsoleApp
* 唯一标识：988d1fd9-7907-40bb-9147-51a2c953d9f8
*
* 创建者：WenJY
* 电子邮箱：
* 创建时间：2024-05-22 11:19:23
* 版本：V1.0.0
* 描述：
*
*--------------------------------------------------------------------
* 修改人：
* 时间：
* 修改说明：
*
* 版本：V1.0.0
*--------------------------------------------------------------------*/
#endregion << 版 本 注 释 >>
namespace ConsoleApp
{
    public class HidUtils
    {
        #region parameter Define
        HIDInterface hid = new HIDInterface();


        struct connectStatusStruct
        {
            public bool preStatus;
            public bool curStatus;
        }

        connectStatusStruct connectStatus = new connectStatusStruct();

        /// <summary>
        /// 推送连接状态信息
        /// </summary>
        /// <param name="isConnected"></param>
        public delegate void PushConnectedDelegate(bool isConnected);
        public PushConnectedDelegate pushConnectedDelegateEvent;


        /// <summary>
        /// 推送接收数据信息
        /// </summary>
        /// <param name="datas"></param>
        /// <param name="str"></param>
        public delegate void PushReceiveDataDele(byte[] datas,string str);
        public PushReceiveDataDele pushReceiveDataEvent;

        /// <summary>
        /// 推送设备状态修改
        /// </summary>
        /// <param name="isFlag"></param>
        public delegate void PushDeviceStatusDelegate(bool isFlag);
        public PushDeviceStatusDelegate pushDeviceStatusDelegateEvent;

        /// <summary>
        /// ReadBlock
        /// </summary>
        /// <param name="isConnected"></param>
        public delegate void PushReadBlockDelegate(TagBlock tagBlock);
        public PushReadBlockDelegate pushReadBlockDelegateEvent;

        #endregion

        public void Initial()
        {

            hid.StatusConnected = StatusConnected;
            hid.DataReceived = DataReceived;

            HIDInterface.HidDevice hidDevice = new HIDInterface.HidDevice();
            hidDevice.vID = (ushort)1285;
            hidDevice.pID = (ushort)20560;
            hidDevice.serial = "";
            hid.AutoConnect(hidDevice);

        }

        public void Close()
        {
            hid.StopAutoConnect();
        }

        public bool SendBytes(byte[] data)
        {

            return hid.Send(data);

        }

        public void StartScan()
        {
            byte[] array = new byte[12]
            {
            12, 87, 89, 8, 0, 0, 255, 255, 1, 0,
            210, 15
            };
            ushort value = CalculateCRC(array);
            byte[] bytes = BitConverter.GetBytes(value);
            array[array.Length - 2] = bytes[0];
            array[array.Length - 1] = bytes[1];
            SendBytes(array);
        }

        public void StopScan()
        {
            byte[] array = new byte[12]
            {
            12, 87, 89, 8, 0, 0, 255, 255, 0, 0,
            210, 15
            };
            ushort value = CalculateCRC(array);
            byte[] bytes = BitConverter.GetBytes(value);
            array[array.Length - 2] = bytes[0];
            array[array.Length - 1] = bytes[1];
            SendBytes(array);
            

        }

        public void ReadBlockData(string BlockAddr, string BlockNum)
        {
            byte[] data = Get_Order(0, 0, 16, 0, 36, new byte[10]
                {
                112,
                105,
                180,
                242,
                80,
                1,
                4,
                224,
                Convert.ToByte(BlockAddr, 16),
                Convert.ToByte(BlockNum, 16)
                });
            
            SendBytes(data);

        }

        public void WriteBlock(string BlockAddr, string BlockNum, List<string> BlockList)
        {
            int num = int.Parse(BlockNum);
            if (num / 2 > BlockList.Count)
            {
                Console.WriteLine( "输入数据有误！");
                return;
            }

            int num2 = 10 + num * 2;
            byte[] array = new byte[num2];
            int num3 = 0;
            array[num3++] = 138;
            array[num3++] = 138;
            array[num3++] = 186;
            array[num3++] = 242;
            array[num3++] = 80;
            array[num3++] = 1;
            array[num3++] = 4;
            array[num3++] = 224;
            array[num3++] = Convert.ToByte(BlockAddr, 16);
            array[num3++] = Convert.ToByte(BlockNum, 16);
            if (num % 2 != 0)
            {
                num++;
            }

            for (int i = 0; i < num / 2; i++)
            {
                string text = BlockList[i];
                if (text.Length != 8 && text.Length != 4)
                {
                    Console.WriteLine("长度不符合！");
                    return;
                }

                foreach (char c in text)
                {
                    if ((c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F'))
                    {
                        Console.WriteLine("数据含有不合法字符！");
                        return;
                    }
                }

                for (int k = 0; k < text.Length / 2; k++)
                {
                    array[num3++] = Convert.ToByte(text.Substring(k * 2, 2), 16);
                }
            }

            byte[] data = Get_Order(0, 0, 1, 0, 37, array);
            SendBytes(data);
        }

        public void DataReceived(object sender, byte[] bytes)
        {
            if (bytes[7] == 31 && (bytes[8] == 0 || bytes[8] == 1)) //修改设备返回信息
            {
                bool isFlag = false;
                if (bytes[10] == 1 && bytes[11] == 1)
                {
                    isFlag = false;
                }
                else
                {
                    isFlag = true;
                }
                
                if (pushDeviceStatusDelegateEvent != null)
                    pushDeviceStatusDelegateEvent(isFlag);
            }

            if (bytes[7] == 31 && bytes[8] == 36)
            {
                TagBlock tagBlock = new TagBlock();
                tagBlock.Block = new List<string>();
                int num = 0;
                int num2 = 0;
                string text = "";
                if (bytes[bytes.Length - 3] == 1 && bytes[bytes.Length - 4] == 1)
                {
                    tagBlock.State = false;
                    return;
                }

                for (int i = 10; i < bytes.Length - 4; i++)
                {
                    text += bytes[i].ToString("X2");
                    num2++;
                    if (num2 == 4)
                    {
                        tagBlock.Block.Add(text);
                        num++;
                        num2 = 0;
                        text = "";
                    }
                }

                if (text.Length > 0)
                {
                    tagBlock.Block.Add(text);
                    num++;
                    num2 = 0;
                    text = "";
                }

                if (pushReadBlockDelegateEvent != null)
                    pushReadBlockDelegateEvent(tagBlock);
            }

            if (bytes[7] == 31 && bytes[8] == 37)   //写入结果
            {

                bool isFlag = false;
                if (bytes[10] == 1 && bytes[11] == 1)
                {
                    isFlag = false;
                }
                else
                {
                    isFlag = true;
                }
            }

            if (bytes[7] == 31 && bytes[8] == 17)
            {
                string str = "";
                for (int index = 10; index <= bytes.Length - 6; ++index)
                {
                    str += bytes[index].ToString("X2");
                    if (index != bytes.Length - 6)
                        str += " ";
                }
                if (pushReceiveDataEvent != null)
                    pushReceiveDataEvent(bytes, str);
            }
        }


        public void StatusConnected(object sender, bool isConnect)
        {
            connectStatus.curStatus = isConnect;
            if (connectStatus.curStatus == connectStatus.preStatus)  //connect
                return;
            connectStatus.preStatus = connectStatus.curStatus;

            if (connectStatus.curStatus)
            {
                Console.WriteLine("连接成功");
            }
            else
            {
                Console.WriteLine("无法连接");
            }

            if (pushConnectedDelegateEvent != null)
                pushConnectedDelegateEvent(connectStatus.curStatus);
        }

        private byte[] Get_Order(byte Source_Address_0, byte Source_Address_1, byte Destination_Address_0, byte Destination_Address_1, byte Type, byte[] data)
        {
            int num = 12 + data.Length;
            byte[] array = new byte[num];
            int num2 = 0;
            array[num2++] = (byte)num;
            array[num2++] = 87;
            array[num2++] = 89;
            array[num2++] = (byte)(num - 4);
            array[num2++] = Source_Address_0;
            array[num2++] = Source_Address_1;
            array[num2++] = Destination_Address_0;
            array[num2++] = Destination_Address_1;
            array[num2++] = Type;
            array[num2++] = 0;
            for (int i = 0; i < data.Length; i++)
            {
                array[num2++] = data[i];
            }

            ushort value = CalculateCRC(array);
            byte[] bytes = BitConverter.GetBytes(value);
            array[num2++] = bytes[0];
            array[num2++] = bytes[1];
            return array;
        }

        private ushort CalculateCRC(byte[] data)
        {
            ushort num1 = ushort.MaxValue;
            foreach (byte num2 in data)
            {
                num1 ^= (ushort)num2;
                for (int index = 0; index < 8; ++index)
                {
                    if (((int)num1 & 1) == 1)
                        num1 = (ushort)((int)num1 >> 1 ^ 33800);
                    else
                        num1 >>= 1;
                }
            }
            return num1;
        }
    }
}