using ReaderB;
using System.Text;

namespace UHFHelper
{
    public class UHFCardHelper
    {
        /// <summary>
        /// 单例模式
        /// </summary>
        private static UHFCardHelper? Instance { get; set; }
        private UHFCardHelper()
        {
        }
        public static UHFCardHelper GetInstance()
        {
            if (Instance == null)
            {
                Instance = new UHFCardHelper();
            }
            return Instance;
        }
        //当前操作的ComAdr
        private byte fComAdr  = 0xff;
        //返回串口的索引号
        private int frmcomportindex;
        /// <summary>
        /// 打开的COM口号
        /// </summary>
        public int OpenComNo { get; set; } 
        //所有执行指令的返回值
        private int fCmdRet { get; set; } =  30; 
        /// <summary>
        /// 串口打开标示
        /// </summary>
        public bool ComOpen { get; set; } = false;
        /// <summary>
        /// 密码
        /// </summary>
        private byte[] fPassWord = new byte[4];
        /// <summary>
        /// 错误码
        /// </summary>
        private int ferrorcode;
        //定义Timer类
        private System.Timers.Timer timer;
        //定义委托
        public delegate void SetControlValue(string value);
        private void InitTimer()
        {
            int interval = 1000;
            timer = new System.Timers.Timer(interval);
            timer.AutoReset = true;
            timer.Enabled = true;
            //绑定事件，每隔一秒执行一次此方法
            timer.Elapsed += new System.Timers.ElapsedEventHandler(MyMethod);
        }
        private void MyMethod(object sender, System.Timers.ElapsedEventArgs e)
        {
            //TODO 持续扫码
        }
        /// <summary>
        /// 打开串口
        /// </summary>
        /// <returns></returns>
        public Resultoutput OpenPort()
        {
            int port = 0;
            int openresult;
            fComAdr = Convert.ToByte("FF", 16); // $FF;
            try
            {
                openresult = StaticClassReaderB.AutoOpenComPort(ref port, ref fComAdr, 5, ref frmcomportindex);
                OpenComNo = frmcomportindex;
                if (openresult == 0)
                {
                    ComOpen = true;
                    //自动执行读取写卡器信息
                    byte[] TrType = new byte[2];
                    byte[] VersionInfo = new byte[2];
                    byte ReaderType = 0;
                    byte ScanTime = 0;
                    byte dmaxfre = 0;
                    byte dminfre = 0;
                    byte powerdBm = 0;
                    fCmdRet = StaticClassReaderB.GetReaderInformation(ref fComAdr, VersionInfo, ref ReaderType, TrType, ref dmaxfre, ref dminfre, ref powerdBm, ref ScanTime, frmcomportindex);
                    if ((fCmdRet == 0x35) | (fCmdRet == 0x30))
                    {
                        StaticClassReaderB.CloseSpecComPort(frmcomportindex);
                        ComOpen = false;
                        return new Resultoutput { Res=false,ResMes= "串口通讯错误" };
                    }
                    if ((OpenComNo == -1) && (openresult == 0x30))
                    {
                        return new Resultoutput { Res = false, ResMes = "串口通讯错误" };
                    }
                    
                }

            }
            catch(Exception ex) {
                return new Resultoutput { Res = false, ResMes = ex.ToString() };
            }
            ComOpen = true;
            //var result = WorkMode();
            //if (!result.Res)
            //{
            //    return result;
            //}
            return new Resultoutput { Res = true, ResMes = "串口打开成功" };
        }
        /// <summary>
        /// 关闭串口
        /// </summary>
        /// <returns></returns>
        public Resultoutput ClosePort()
        {
            fCmdRet = StaticClassReaderB.CloseSpecComPort(OpenComNo);
            if (fCmdRet == 0)
            {
                ComOpen = false;
            }
            else
            {
                return new Resultoutput { Res = false, ResMes = "串口关闭失败" };
            }
            return new Resultoutput { Res = true, ResMes = "串口关闭成功" };
        }
        /// <summary>
        /// 设置工作模式
        /// </summary>
        public Resultoutput WorkMode()
        {
            byte[] Parameter = new byte[6];
            //应答模式
            Parameter[0] = Convert.ToByte(0);
            //工作模式 EPCC1   ISO18000-6B 
            int Reader_bit0 = 0;
            //输出模式
            int Reader_bit1 = 0;
            //蜂鸣开关
            int Reader_bit2 = 1;
            //起始地址
            int Reader_bit3 = 0;
            //是否SYRIS485输出
            int Reader_bit4 = 0;
            Parameter[1] = Convert.ToByte(Reader_bit0 * 1 + Reader_bit1 * 2 + Reader_bit2 * 4 + Reader_bit3 * 8 + Reader_bit4 * 16);
            //存储区 EPC区
            Parameter[2] = 1;
            //起始字地址(Hex)
            Parameter[3] = Convert.ToByte("02", 16);
            //读取字数
            Parameter[4] = Convert.ToByte(1);
            //单张标签过滤时间
            Parameter[5] = Convert.ToByte(0);
            //设置工作模式
            fCmdRet = StaticClassReaderB.SetWorkMode(ref fComAdr, Parameter, frmcomportindex);
            if (fCmdRet == 0)
            {
                return new Resultoutput { Res = true, ResMes = "工作模式设置成功" };
            }
            return new Resultoutput { Res = false, ResMes = "读卡失败" };
        }
        /// <summary>
        /// 读卡
        /// </summary>
        /// <returns></returns>
        public string ReadCard()
        {
            int CardNum = 0;
            int Totallen = 0;
            int EPClen, m;
            byte[] EPC = new byte[5000];
            string temps;
            string sEPC;
            //fIsInventoryScan = true;
            byte AdrTID = 0;
            byte LenTID = 0;
            byte TIDFlag = 0;
            AdrTID = 0;
            LenTID = 0;
            TIDFlag = 0;
            fCmdRet = StaticClassReaderB.Inventory_G2(ref fComAdr, AdrTID, LenTID, TIDFlag, EPC, ref Totallen, ref CardNum, frmcomportindex);
            if ((fCmdRet == 1) | (fCmdRet == 2) | (fCmdRet == 3) | (fCmdRet == 4) | (fCmdRet == 0xFB))//代表已查找结束，
            {
                byte[] daw = new byte[Totallen];
                Array.Copy(EPC, daw, Totallen);
                temps = ByteArrayToHexString(daw);
                m = 0;
                if (CardNum == 0)
                {
                    return "";
                }
                for (int CardIndex = 0; CardIndex < CardNum; CardIndex++)
                {
                    EPClen = daw[m];
                    sEPC = temps.Substring(m * 2 + 2, EPClen * 2);
                    m = m + EPClen + 1;
                    if (sEPC.Length != EPClen * 2)
                    {
                        return "";
                    }
                    string cardcode = sEPC.Substring(1, sEPC.Length-1);
                    return cardcode;
                }
            }
            return "";
        }

        /// <summary>
        /// 写卡
        /// </summary>
        /// <returns></returns>
        public Resultoutput WriteCard(string CardCodeStr) 
        {
            byte[] WriteEPC = new byte[100];
            byte WriteEPClen;
            byte ENum;
            string AccessCode = "00000000";
            try
            {
                string CardCode = CardCodeStr;
                if ((CardCode.Length % 4) != 0)
                {
                    CardCode = "0" + CardCodeStr;
                }
                WriteEPClen = Convert.ToByte(CardCode.Length / 2);
                ENum = Convert.ToByte(CardCode.Length / 4);
                byte[] EPC = new byte[ENum];
                EPC = HexStringToByteArray(CardCode);
                fPassWord = HexStringToByteArray(AccessCode);
                fCmdRet = StaticClassReaderB.WriteEPC_G2(ref fComAdr, fPassWord, EPC, WriteEPClen, ref ferrorcode, frmcomportindex);
                if (fCmdRet == 0)
                {
                    return new Resultoutput { Res = true, ResMes = "写卡成功！" };
                }
                else
                {
                    return new Resultoutput { Res = false, ResMes = "写卡失败！错误码:" + ferrorcode };
                }
            }
            catch (Exception ex)
            {

                return new Resultoutput { Res = false, ResMes = "写卡失败"+ ex.Message };
            }
            
        }
        /// <summary>
        /// 解析数据
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        private byte[] HexStringToByteArray(string s)
        {
            s = s.Replace(" ", "");
            byte[] buffer = new byte[s.Length / 2];
            for (int i = 0; i < s.Length; i += 2)
                buffer[i / 2] = (byte)Convert.ToByte(s.Substring(i, 2), 16);
            return buffer;
        }
        /// <summary>
        /// 解析数据
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private string ByteArrayToHexString(byte[] data)
        {
            StringBuilder sb = new(data.Length * 3);
            foreach (byte b in data)
                sb.Append(Convert.ToString(b, 16).PadLeft(2, '0'));
            return sb.ToString().ToUpper();

        }
        /// <summary>
        /// 字符串转16进制
        /// </summary>
        /// <param name="strEncode"></param>
        /// <returns></returns>

        public string ToEncode16(string strEncode)
        {
            byte[] b = Encoding.UTF8.GetBytes(strEncode);//按照指定编码将string编程字节数组
            string result = string.Empty;
            for (int i = 0; i < b.Length; i++)//逐字节变为16进制字符
            {
                result += Convert.ToString(b[i], 16);
            }
            return result;
        }
        /// <summary>
        /// 16进制转字符串
        /// </summary>
        /// <param name="strEncode"></param>
        /// <returns></returns>

        public string ToEncodeString(string strDecode)
        {
            string strTemp = "";
            byte[] b = new byte[strDecode.Length / 2];
            for (int i = 0; i < strDecode.Length / 2; i++)
            {
                strTemp = strDecode.Substring(i * 2, 2);
                b[i] = Convert.ToByte(strTemp, 16);
            }
            //按照指定编码将字节数组变为字符串
            return Encoding.UTF8.GetString(b);
        }
    }
}