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

namespace HighWayIot.Common
{
    /// <summary>
    /// 工具类
    /// </summary>
    public sealed class MsgUtil
    {

        private static readonly Lazy<MsgUtil> lazy = new Lazy<MsgUtil>(() => new MsgUtil());

        public static MsgUtil Instance
        {
            get
            {
                return lazy.Value;
            }
        }

        private MsgUtil() { }

        #region 数据解析公共方法
        /// <summary>
        /// 字节数组转换成结构体
        /// </summary>
        /// <param name="buf"></param>
        /// <param name="len"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static object BytesToStruct(byte[] buf, int len, Type type)
        {
            object rtn;
            IntPtr buffer = Marshal.AllocHGlobal(len);
            Marshal.Copy(buf, 0, buffer, len);
            try
            {
                rtn = Marshal.PtrToStructure(buffer, type);
                Marshal.FreeHGlobal(buffer);
            }
            catch (Exception)
            {
                return null;
            }
            return rtn;
        }

        public string StringToHexString(string s, Encoding encode)
        {

            byte[] b = encode.GetBytes(s);          //按照指定编码将string编程字节数组
            string result = string.Empty;
            for (int i = 0; i < b.Length; i++)      //逐字节变为16进制字符，以%隔开
            {
                result += "%" + Convert.ToString(b[i], 16);
            }
            return result;
        }

        //// <summary>
        /// 结构体转byte数组
        /// </summary>
        /// <param name="structObj">要转换的结构体</param>
        /// <returns>转换后的byte数组</returns>
        public static byte[] StructToBytes(object structObj)
        {
            //得到结构体的大小
            int size = Marshal.SizeOf(structObj);
            //创建byte数组
            byte[] bytes = new byte[size];
            //分配结构体大小的内存空间
            IntPtr structPtr = Marshal.AllocHGlobal(size);
            //将结构体拷到分配好的内存空间
            Marshal.StructureToPtr(structObj, structPtr, false);
            //从内存空间拷到byte数组
            Marshal.Copy(structPtr, bytes, 0, size);
            //释放内存空间
            Marshal.FreeHGlobal(structPtr);
            //返回byte数组
            return bytes;
        }


        #endregion
        #region 消息验证方法

        /// <summary>
        /// CS和校验
        /// </summary>
        /// <param name="Abyte"></param>
        /// <returns></returns>
        public byte Check_CS(byte[] Abyte)
        {
            byte result = new byte();
            try
            {
                int num = 0;
                for (int i = 0; i < Abyte.Length; i++)
                {
                    num = (num + Abyte[i]) % 256;
                }
                result = (byte)num;
            }
            catch
            {
                result = 0;
            }
            return result;
        }

        /// <summary>
        /// BCC异或取反校验
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public string getBCC(byte[] data)
        {
            String ret = "";
            byte[] BCC = new byte[1];
            for (int i = 0; i < data.Length; i++)
            {
                BCC[0] = (byte)(BCC[0] ^ data[i]);
            }
            String hex = ((~BCC[0]) & 0xFF).ToString("X");//取反操作
            if (hex.Length == 1)
            {
                hex = '0' + hex;
            }
            ret += hex.ToUpper();
            return ret;
        }

        static int BytesToInt(byte[] b, int length)
        {
            int temp = 0;
            for (int i = 0; i <= length - 1 && i < 4; i++)
            {
                temp += (int)(b[i] << (i * 8));
            }
            return temp;
        }

        public static byte[] CalculateVerify(byte[] pMessage, int iLength)
        {
            UInt16 i;
            int iVerify = 0;

            iVerify = pMessage[0];
            for (i = 0; i < iLength - 1; i++)
            {
                iVerify = iVerify + pMessage[i + 1];
            }
            return BitConverter.GetBytes(Convert.ToUInt16(iVerify));
        }
        #endregion
        public byte[] HexStrTorbytes(string strHex)//e.g. " 01 01" ---> { 0x01, 0x01}
        {
            strHex = strHex.Replace(" ", "");
            if ((strHex.Length % 2) != 0)
                strHex += " ";
            byte[] returnBytes = new byte[strHex.Length / 2];
            for (int i = 0; i < returnBytes.Length; i++)
                returnBytes[i] = Convert.ToByte(strHex.Substring(i * 2, 2), 16);
            return returnBytes;
        }

        /// <summary>
        /// 将字符串强制转换成int，转换失败则返回0
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public int ParseToInt(string str)
        {
            int returnInt = 0;

            if (str == null || str.Trim().Length < 1)
            {
                return returnInt;
            }

            if (int.TryParse(str, out returnInt))
            {
                return returnInt;
            }
            else
            {
                return 0;
            }
        }

        public byte[] HexToString(string Str)
        {
            byte[] str = new byte[Str.Length / 2];
            for (int i = 0; i < str.Length; i++)
            {
                int temp = Convert.ToInt32(Str.Substring(i * 2, 2), 16);
                str[i] = (byte)temp;
            }
            return str;
        }
        public string ConverToString(byte[] data)
        {
            string str;
            StringBuilder stb = new StringBuilder();
            for (int i = 0; i < data.Length; i++)
            {
                if ((int)data[i] > 15)
                {
                    stb.Append(Convert.ToString(data[i], 16).ToUpper()); //添加字符串
                }
                else  //如果是小于0F需要加个零
                {
                    stb.Append("0" + Convert.ToString(data[i], 16).ToUpper());
                }
            }
            str = stb.ToString();
            return str;
        }

        public string bytesToHexStr(byte[] bytes, int iLen)
        {
            StringBuilder sb = new StringBuilder();
            if (bytes != null)
            {
                for (int i = 0; i < iLen; i++)
                {
                    sb.Append(bytes[i].ToString("X2"));
                }
            }
            return sb.ToString();
        }

        /// <summary>
        /// 从十进制转换到十六进制
        /// </summary>
        /// <param name="ten"></param>
        /// <returns></returns>
        public string Ten2Hex(string ten)
        {
            ulong tenValue = Convert.ToUInt64(ten);
            ulong divValue, resValue;
            string hex = "";
            do
            {
                //divValue = (ulong)Math.Floor(tenValue / 16);

                divValue = (ulong)Math.Floor((decimal)(tenValue / 16));

                resValue = tenValue % 16;
                hex = tenValue2Char(resValue) + hex;
                tenValue = divValue;
            }
            while (tenValue >= 16);
            if (tenValue != 0)
                hex = tenValue2Char(tenValue) + hex;
            return hex;
        }

        public static string tenValue2Char(ulong ten)
        {
            switch (ten)
            {
                case 0:
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                case 8:
                case 9:
                    return ten.ToString();
                case 10:
                    return "A";
                case 11:
                    return "B";
                case 12:
                    return "C";
                case 13:
                    return "D";
                case 14:
                    return "E";
                case 15:
                    return "F";
                default:
                    return "";
            }
        }
    }

    #region 消息公用的头尾

    /// <summary>
    /// 能源通讯协议结构体
    /// </summary>

    public enum CallbackSendData
    {
        _LoginIn = 0XA1,
        _SetTime = 0X08,
        _HeartBeat = 0XA4,
        _ERealFlag = 0XB3,
        _SRealFlag = 0XB4,
        _TRealFlag = 0XB5,
        _IRealFlag = 0XB6,

        _EFlag = 0XC3,
        _SFlag = 0XC4,
        _TFlag = 0XC5,
        _IFlag = 0XC6,
    }
    public struct struFrame
    {
        //帧开始
        public byte BeginChar_State;
        //采集器类型
        public byte Collection_Type;
        //采集器地址
        public byte[] Collection_Addr;
        //命令序列号
        public byte[] Command_Id;
        //起始符
        public byte StartChar_State;
        //控制码
        public byte Ctrl_State;
        //数据长度
        public byte[] DataLen_State;
        //数据域
        public byte[] Data_State;
        //校验码
        public byte CSChar_State;
        //结束符
        public byte EndChar_State;
        //终端类型
        public byte flagDTN;
        //逻辑编号
        public byte[] addrDNL;
        //主站地址
        public byte flagMSTA;
        //帧内序号
        public byte flagISEQ;
        //帧序号
        public byte flagFSEQ;
        //控制码
        public byte flagCtrl;
        //传送方向
        public byte flagCtrlD;
        //异常标志
        public byte flagCtrlE;
        //功能标志
        public byte flagCtrlF;
        //数据长度
        public int lenData;
        //数据字符串
        public byte[] strData;

        public object userData;
        public string tName;

        public object userData2;
        //public bool isCtrl;
        //public bool isData;

        public bool isTimeCorrectting;

    };



    /// <summary>
    /// 头文件
    /// </summary>
    [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    public struct Head
    {
        public byte start;                                        //起始
        public short addr;                                       //软件地址
        public byte mstaseq;                                      //主站地址与命令序号
        public byte control;                                      //控制码
        public short length;                                     //数据长度
    }
    /// <summary>
    /// 结尾
    /// </summary>
    [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    public struct Tail
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        public byte[] verifica;                                   //校验码
        public byte end;                                        //结束码
    }
    #endregion
    #region 与MES通讯协议
    //识别一条EPC数据  125+3
    [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    public struct ReadEPC
    {
        public Head head;
        public int num;//合并编号
        public Tail tail;
    }

    /// <summary>
    /// 写入反馈 125+5
    /// </summary>
    [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    public struct RecWrite
    {
        public Head head;
        public int num;//合并编号
        public byte state;//1成功，0失败，2写失败，读成功
        public Tail tail;
    }
    //
    [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]

    public struct RecDataCell
    {
        public byte len;//Data长度
        public byte[] data;//len 长度个字节数据
    }
    /// <summary>
    /// 自报数据 125+6
    /// </summary>
    [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]

    public struct RecAutoData
    {
        public Head head;
        public int num;//合并编号
        public RecDataCell recDatas;//自报数据
        public Tail tail;
    }

    /// <summary>
    ///心跳 101
    /// </summary>
    [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]

    public struct Heart
    {
        public Head head;
        public Tail tail;
    }
    #endregion
    #region 与上层应用层 消息指令
    /// <summary>
    /// 收到的消息指令
    /// </summary>
    enum RecAppMsgType
    {
        _ReadEpc = 125 + 3,
        _ReadData = 125 + 4,
        _WirteData = 125 + 5,
        _AutoSendData,

        _HeartBeat = 101,
        _ReadEquipState = 125 + 102,
        _SendGetSoftState = 125 + 103,

    }

    /// <summary>
    /// 发送的消息指令
    /// </summary>
    enum RetAppMsgType
    {
        _RetEpc = 125 + 3,
        _RetData = 125 + 4,
        _RetDataBack = 125 + 5,
        _RetAutoSendData,

        _RetEquipState = 125 + 102,
        _RetGetSoftState = 125 + 103,
    }
    #endregion


    #region 与设备层 适配层消息指令
    //收到设备层消息
    enum RecEquipMsgType
    {
        _GetEquipInfo = 0X01,             //收到适配软件所需设备信息
        _GetSensor = 0x02,                //收到适配软件传感器信息
        _EPCinfo = 0x03,                  //收到设备返回数据 将数据发送MES  并保存数据库
        _SendData = 0x04,                 //收到读取到的数据 收到数据后，上传给MES，并保存数据库
        _RecGetData = 0x05,             //收到写入的数据是否成功反馈
        _RecAutoData = 0x06,              //收到设备自报数据

        _HeartBeat = 101,               //心跳
        _EquipState,                    //设备状态
    }
    //发送给设备层消息
    enum RetEquipMsgType
    {
        _RetEquipInfo = 0X01,             //获取适配软件所需设备信息
        _RetSensor = 0x02,                //获取适配软件传感器信息
        _GetEPCinfo = 0x03,                 //向设备发送命令，识别EPC数据
        _GetData = 0x04,                    //向设备发送命令，读取数据
        _WirteData = 0x05,                 //向设备发送命令，写入数据
        _RetAutoData = 0x06,              //收到设备自爆数据反馈

    }
    #endregion
}
