using ReaderB;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Kivii.Client.SamplePackages
{
    public class Reader
    {
        public event EventHandler<ConnectionChangedEventArgs> Connected;
        public event EventHandler<ConnectionChangedEventArgs> ConnectionLost;
        public ApplicationConnectionState State { get; private set; }

        private byte fComAdr = 0xff; //当前操作的ComAdr
        private byte fBaud;
        private double fdminfre;
        private double fdmaxfre;
        private int frmcomportindex;
        private int fOpenComIndex; //打开的串口索引号
        private int fCmdRet = 30; //所有执行指令的返回值
        private bool fIsInventoryScan;
        private int ferrorcode;
        private string fInventory_EPC_List; //存贮询查列表（如果读取的数据没有变化，则不进行刷新）
        private byte Maskadr;
        private byte MaskLen;
        private byte MaskFlag;
        private byte[] fPassWord = new byte[4];

        private bool IsConnected { get; set; } = false;

        public virtual void OnConnected(ConnectionChangedEventArgs args)
        {
            State = args.State;
            if (null != this.Connected)
            {
                this.Connected(this, args);
            }
        }
        public virtual void OnConnectionLost(ConnectionChangedEventArgs args)
        {
            State = args.State;
            if (null != this.ConnectionLost)
            {
                this.ConnectionLost(this, args);
            }
        }

        private string GetErrorCodeDesc(int cmdRet)
        {
            switch (cmdRet)
            {
                case 0x00:
                    return "其它错误";
                case 0x03:
                    return "存储器超限或不被支持的PC值";
                case 0x04:
                    return "存储器锁定";
                case 0x0b:
                    return "电源不足";
                case 0x0f:
                    return "非特定错误";
                default:
                    return "";
            }
        }

        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;
        }

        private string ByteArrayToHexString(byte[] data)
        {
            StringBuilder sb = new StringBuilder(data.Length * 3);
            foreach (byte b in data)
                sb.Append(Convert.ToString(b, 16).PadLeft(2, '0'));
            return sb.ToString().ToUpper();

        }

        public bool AutoOpenComPort()
        {
            if (IsConnected) return IsConnected;
            int port = 0;
            int openresult;
            openresult = 30;
            fBaud = Convert.ToByte(6);
            fComAdr = Convert.ToByte("FF", 16); // $FF;
            openresult = StaticClassReaderB.AutoOpenComPort(ref port, ref fComAdr, fBaud, ref frmcomportindex);
            fOpenComIndex = frmcomportindex;
            if ((fOpenComIndex == -1) && (openresult == 0x30)) throw new Exception("串口通讯错误");
            IsConnected = true;
            var args = new ConnectionChangedEventArgs();
            args.State = ApplicationConnectionState.Connected;
            this.OnConnected(args);
            return IsConnected;
        }
        public bool CloseSpecComPort()
        {
            if (!IsConnected) return IsConnected;
            int port = fOpenComIndex;
            if (port < 0) throw new Exception("要关闭的端口号错误");
            fCmdRet = StaticClassReaderB.CloseSpecComPort(port);
            if (fCmdRet != 0) throw new Exception("串口通讯错误");
            IsConnected = false;
            var args = new ConnectionChangedEventArgs();
            args.State = ApplicationConnectionState.ConnectionLost;
            this.OnConnectionLost(args);
            return IsConnected;
        }

        public string ReadEpc()
        {
            int CardNum = 0;
            int Totallen = 0;
            int EPClen, m;
            byte[] EPC = new byte[5000];
            int CardIndex;
            string temps;
            string s, sEPC = null;
            fIsInventoryScan = true;
            byte AdrTID = 0;
            byte LenTID = 0;
            byte TIDFlag = 0;
            ListViewItem aListItem = new ListViewItem();
            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);
                fInventory_EPC_List = temps;            //存贮记录
                m = 0;

                if (CardNum == 0)
                {
                    fIsInventoryScan = false;
                    return string.Empty;
                }
                EPClen = daw[m];
                sEPC = temps.Substring(m * 2 + 2, EPClen * 2);
                m = m + EPClen + 1;
                if (sEPC.Length != EPClen * 2)
                {
                    fIsInventoryScan = false;
                    return string.Empty;
                }
            }
            fIsInventoryScan = false;
            return sEPC;
        }

        public string ReadTid()
        {
            int CardNum = 0;
            int Totallen = 0;
            int EPClen, m;
            byte[] EPC = new byte[5000];
            int CardIndex;
            string temps;
            string s, sTID = null;
            fIsInventoryScan = true;
            byte AdrTID = Convert.ToByte("00", 16);
            byte LenTID = Convert.ToByte("06", 16);
            byte TIDFlag = 1;
            ListViewItem aListItem = new ListViewItem();
            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);
                fInventory_EPC_List = temps;            //存贮记录
                m = 0;

                if (CardNum == 0)
                {
                    fIsInventoryScan = false;
                    return string.Empty;
                }
                EPClen = daw[m];
                sTID = temps.Substring(m * 2 + 2, EPClen * 2);
                m = m + EPClen + 1;
                if (sTID.Length != EPClen * 2)
                {
                    fIsInventoryScan = false;
                    return string.Empty;
                }

            }
            fIsInventoryScan = false;
            return sTID;
        }

        public bool ProgramEpc(string writeEpc, string accessPassword, out string epc)
        {
            fIsInventoryScan = true;
            byte[] WriteEPC = new byte[100];
            byte WriteEPClen;
            byte ENum;
            if ((writeEpc.Length % 4) != 0)
            {
                epc = "请输入以字为单位的16进制数！'+#13+#10+'例如：1234、12345678!";
                return false;
            }

            WriteEPClen = Convert.ToByte(writeEpc.Length / 2);
            ENum = Convert.ToByte(writeEpc.Length / 4);
            byte[] EPC = new byte[ENum];
            EPC = HexStringToByteArray(writeEpc);
            if (string.IsNullOrEmpty(accessPassword)) { accessPassword = "00000000"; }
            fPassWord = HexStringToByteArray(accessPassword);
            fCmdRet = StaticClassReaderB.WriteEPC_G2(ref fComAdr, fPassWord, EPC, WriteEPClen, ref ferrorcode, frmcomportindex);

            if (fCmdRet != 0)
            {
                epc = GetErrorCodeDesc(ferrorcode);
                return false;
            }
            fIsInventoryScan = false;
            epc = ByteArrayToHexString(EPC);
            return true;
        }
    }

    public class ConnectionChangedEventArgs : EventArgs
    {
        public object ReaderIdentity { get; set; }

        public ApplicationConnectionState State { get; set; }

        public DateTime Timestamp { get; set; }
    }
    public enum ApplicationConnectionState
    {
        NotConnected,
        Connected,
        Disconnected,
        ConnectionLost,
        FailedReaderNotOnNetwork,
        FailedReaderConnectedToAnother,
        FailedReaderOtherReason
    }
}
