using log4net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace VIZ.Framework.Core
{
    /// <summary>
    /// USB设备信息
    /// </summary>
    public class USBDeviceInfo
    {
        /// <summary>
        /// 日志
        /// </summary>
        private static readonly ILog log = LogManager.GetLogger(typeof(USBDeviceInfo));

        /// <summary>
        /// 句柄
        /// </summary>
        public int Handle { get; set; }

        /// <summary>
        /// 设备信息结构体
        /// </summary>
        public USBDeviceStruct Struct { get; set; }

        // ====================================================================
        // 基本信息

        /// <summary>
        /// 固件名称
        /// </summary>
        public string FirmwareName { get; set; }

        /// <summary>
        /// 固件编译时间
        /// </summary>
        public string BuildDate { get; set; }

        /// <summary>
        /// 硬件版本号
        /// </summary>
        public string HardwareVersion { get; set; }

        /// <summary>
        /// 固件版本号
        /// </summary>
        public string FirmwareVersion { get; set; }

        /// <summary>
        /// 适配器序列号
        /// </summary>
        public string SerialNumber { get; set; }

        /// <summary>
        /// 适配器当前具备的功能
        /// </summary>
        public string Functions { get; set; }

        /// <summary>
        /// 触发类型
        /// </summary>
        public GPIOPuPd PuPd { get; set; }

        // ====================================================================
        // 状态信息

        /// <summary>
        /// 状态
        /// </summary>
        public bool State { get; set; }

        /// <summary>
        /// 打开设备
        /// </summary>
        public bool Open()
        {
            if (this.Handle <= 0)
                return false;

            if (!USBDevice.USB_OpenDevice(this.Handle))
            {
                return false;
            }

            USBDeviceStruct data = new USBDeviceStruct();
            StringBuilder funcStr = new StringBuilder(256);
            if (!USBDevice.DEV_GetDeviceInfo(this.Handle, ref data, funcStr))
            {
                log.Error($"获取USB设备信息失败，编号： {this.Handle}");

                return false;
            }

            this.FirmwareName = Encoding.Default.GetString(data.FirmwareName).Trim();
            this.BuildDate = Encoding.Default.GetString(data.BuildDate).Trim();
            this.FirmwareVersion = string.Format("{0}.{1}.{2}", (data.FirmwareVersion >> 24) & 0xFF, (data.FirmwareVersion >> 16) & 0xFF, data.FirmwareVersion & 0xFFFF);
            this.HardwareVersion = string.Format("{0}.{1}.{2}", (data.HardwareVersion >> 24) & 0xFF, (data.HardwareVersion >> 16) & 0xFF, data.HardwareVersion & 0xFFFF);
            this.Functions = funcStr.ToString().Trim();
            this.SerialNumber = data.SerialNumber[0].ToString("X8") + data.SerialNumber[1].ToString("X8") + data.SerialNumber[2].ToString("X8");

            this.State = true;

            return true;
        }

        /// <summary>
        /// 设置输入模式
        /// </summary>
        /// <param name="pinMask">引脚掩码</param>
        /// <param name="pupd">输入输出模式</param>
        /// <returns>是否设置成功</returns>
        public bool SetInput(uint pinMask, GPIOPuPd pupd)
        {
            this.PuPd = pupd;

            GPIOResult result = GPIOResult.GPIO_SUCCESS;

            // 尝试5次设置
            for (int i = 0; i < 5; i++)
            {
                result = (GPIOResult)USB2GPIO.GPIO_SetInput(this.Handle, pinMask, (byte)pupd);

                if (result != GPIOResult.GPIO_SUCCESS)
                {
                    continue;
                }

                break;
            }

            if (result != GPIOResult.GPIO_SUCCESS)
            {
                log.Error($"设置USB输入模式失败, handle: {this.Handle} result : {result.GetDescription()}");

                this.State = false;

                return false;
            }

            this.State = true;

            return true;
        }

        /// <summary>
        /// 读取
        /// </summary>
        /// <param name="pinMask">引脚掩码</param>
        /// <param name="pinValue">引脚值</param>
        /// <returns>是否成功读取</returns>
        public bool Read(uint pinMask, out uint pinValue)
        {
            if (!this.State)
            {
                pinValue = 0;
                return false;
            }

            uint value = 0;
            GPIOResult result = (GPIOResult)USB2GPIO.GPIO_Read(this.Handle, pinMask, ref value);
            pinValue = value;

            if (result != GPIOResult.GPIO_SUCCESS)
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// 关闭设备
        /// </summary>
        /// <returns>是否成功关闭</returns>
        public bool Close()
        {
            if (this.Handle <= 0 || this.State == false)
                return false;

            if (!USBDevice.USB_CloseDevice(this.Handle))
            {
                log.Error($"关闭USB设备失败, handle: {this.Handle}");

                return false;
            }

            this.State = false;

            return true;
        }
    }
}
