using ProjectBase.Data.Logs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SIASUN.Autopilot.Device
{
    public static class MessageCoder
    {
        // can总线数据包长度
        private static  int ByteLength = 8; 
        /// <summary>
        /// 序列化数据对象
        /// </summary>
        /// <param name="dataModel">数据对象</param>
        public static byte[] Serialize(object dataModel)
        {
            System.IO.MemoryStream ms = new System.IO.MemoryStream();
            byte[] data = new byte[8];
            foreach (System.Reflection.PropertyInfo field in dataModel.GetType().GetProperties())
            {
                object[] objs = field.GetCustomAttributes(typeof(DataAttribute), false);

                if (objs.Length > 0)
                {
                    DataAttribute fieldAttr = (DataAttribute)objs[0];
                    if (fieldAttr.DataType == "LIST")
                    {
                        System.Collections.IList fieldValues = field.GetValue(dataModel, null) as System.Collections.IList;
                        foreach (object fieldValue in fieldValues)
                        {
                            byte[] bytefiled = Serialize(fieldValue);
                            ms.Write(bytefiled, 0, bytefiled.Length);
                        }
                    }
                    else if (fieldAttr.DataType == "binary")
                    {          
                        string fieldValue = field.GetValue(dataModel, null) == null ? "" : field.GetValue(dataModel, null).ToString();
                        byte[] bytefiled = serializeField(fieldAttr.BitStart, fieldValue, fieldAttr.BitLength);
                        ms.Write(bytefiled, fieldAttr.BitStart, bytefiled.Length);
                    }
                    else
                    {
                        LogHelper.log.Error("数据类型不是binary");
                    }
                }
            }
            return ms.ToArray();
        }
        /// <summary>
        /// 反序列化数据对象
        /// </summary>
        /// <param name="dataModel">数据对象</param>
        /// <param name="ms">数据流</param>
        public static object DeSerialize(object dataModel, byte[] bytes)
        {
            foreach (System.Reflection.PropertyInfo field in dataModel.GetType().GetProperties())
            {
                object[] objs = field.GetCustomAttributes(typeof(DataAttribute), false);

                if (objs.Length > 0)
                {
                    DataAttribute fieldAttr = (DataAttribute)objs[0];

                    if (fieldAttr.DataType == "binary")
                    {
                        int byteth = fieldAttr.BitStart / ByteLength; // 第几个字节
                        if (bytes.Length <= byteth)
                        {
                            LogHelper.log.Error(string.Format("代表{0}的字段长度出现错误", fieldAttr.Description));
                            return null;
                        }
                        field.SetValue(dataModel, de_serializeField(fieldAttr.BitStart, fieldAttr.BitLength, bytes), null);
                    }
                    else
                    {
                        LogHelper.log.Error("数据类型不是binary");
                    }
                }
            }
            return dataModel;
        }
         /// <summary>
         /// 解析位
         /// </summary>
         /// <param name="startBit"></param>
         /// <param name="lengthBit"></param>
         /// <param name="bytedata"></param>
         /// <returns></returns>
        private static string de_serializeField(int startBit, int lengthBit, byte[] bytedata)
        {
            int byteth = startBit / ByteLength; // 第几个字节
            int bytesLength = (startBit%ByteLength + lengthBit )/ ByteLength + ((startBit % ByteLength + lengthBit) % ByteLength) > 0 ? 1 : 0; 
            byte[] data = new byte[bytesLength];
            byte[] resultByteData = new byte[bytesLength];
            Buffer.BlockCopy(bytedata, byteth, data, 0, bytesLength);
            BitOR(resultByteData, RightShift(data, startBit % ByteLength));
            return  de_serialize_hex(resultByteData);
        }



        private static byte[] serializeField(int startBit, string value, int lengthBit)   
        {
            int byteth = startBit / ByteLength; // 第几个字节
            int bytesLength = (startBit % ByteLength + lengthBit) / ByteLength + ((startBit % ByteLength + lengthBit) % ByteLength) > 0 ? 1 : 0;
            byte[] byteArray = serialize_hex(value, bytesLength);
            byte[] resultByteData = new byte[8] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00};
            if (byteth< 8)
            {
                resultByteData = BitOR(resultByteData, LeftShift (byteArray, startBit % ByteLength));
            }
            else
            {
                LogHelper.log.Error(string.Format("第{0}位赋值不成功", startBit));
            }
            return resultByteData;
        }

        public static byte[] serialize_hex(string value, int length)
        {
            byte[] returnBytes = new byte[length];
            bool ishexstring = false;

            if (string.IsNullOrEmpty(value))
            {
                return returnBytes;
            }

            ishexstring = true;
            value = value.Replace(" ", "");
            if ((value.Length % 2) != 0)
            {
                value = "0" + value;
            }

            for (int i = 0; i < value.Length / 2; i++)
            {
                if (ishexstring)
                {
                    returnBytes[i] = Convert.ToByte(value.Substring(i * 2, 2), 16);
                }
                else
                {
                    returnBytes[i] = Convert.ToByte(value.Substring(i, 1), 16);
                }
            }
            return returnBytes;
        }

        public static string de_serialize_hex(byte[] bsdata)
        {
            string returnStr = "";
            if (bsdata != null)
            {
                for (int i = 0; i < bsdata.Length; i++)
                {
                    returnStr += bsdata[i].ToString("X2");
                }
            }
            return returnStr;
        }


        /// <summary>
        /// byte转化成bit
        /// </summary>
        /// <param name="b"></param> 
        /// <returns></returns>
        private static int byteToBit(byte bytedata, int bitLocation)  
        {
            return (int)((bytedata) >> bitLocation) & 0x1;
        }

        private static byte[] BitAnd(this byte[] ba1, byte[] ba2)
        {
            if (ba1.Length != ba2.Length)
            {
                return new byte[0];
            }
            var ba3 = new byte[ba1.Length];
            for (int i = 0; i < ba3.Length; i++)
            {
                ba3[i] = (byte)((byte)ba1[i] & (byte)ba2[i]);
            }
            return ba3;

        }
        private static byte[] BitOR(this byte[] ba1, byte[] ba2)
        {
            if (ba1.Length != ba2.Length)
            {
                return new byte[0];
            }
            var ba3 = new byte[ba1.Length];
            for (int i = 0; i < ba3.Length; i++)
            {
                ba3[i] = (byte)((byte)ba1[i] | (byte)ba2[i]);
            }
            return ba3;

        }

        private static byte[] RightShift(this byte[] ba, int n)
        {
            if (n < 0)
            {               
                return LeftShift(ba, Math.Abs(n));
            }
            byte[] ba2 = null;
            ba2 = ba.Clone() as byte[];
            int loop = (int)Math.Ceiling(n / 8.0);
            byte tempByte = 0;
            byte tempByte2 = 0;
            byte Header = 0;

            for (int i = 0; i < loop; i++)
            {
                var tempN = i + 1 == loop ? n % 8 : 8;
                if (tempN == 0 && n != 0)
                {
                    tempN = 8;
                }
                for (int j = 0; j < ba.Length; j++)
                {
                    if (j == 0)
                    {
                        Header = (byte)((ba2.First() & ((byte)(Math.Pow(2, tempN) - 1))) << (8 - tempN));
                        tempByte = (byte)((ba2[ba.Length - 1 - j] & ((byte)(Math.Pow(2, tempN) - 1))) << (8 - tempN));
                        ba2[ba.Length - 1 - j] >>= tempN;
                    }
                    else
                    {
                        tempByte2 = (byte)((ba2[ba.Length - 1 - j] & ((byte)(Math.Pow(2, tempN) - 1))) << (8 - tempN));
                        ba2[ba.Length - 1 - j] >>= tempN;
                        ba2[ba.Length - 1 - j] |= tempByte;
                        tempByte = tempByte2;
                        if (j + 1 == ba.Length)
                        {
                            ba2[j] |= Header;
                        }
                    }
                }
            }
            return ba2;
        }

        private static byte[] LeftShift(this byte[] ba, int n)
        {
            if (n < 0)
            {
                return RightShift(ba, Math.Abs(n));
            }
            byte[] ba2 = null;
            ba2 = ba.Clone() as byte[];
            int loop = (int)Math.Ceiling(n / 8.0);
            byte tempByte = 0;
            byte tempByte2 = 0;
            byte Header = 0;

            for (int i = 0; i < loop; i++)
            {
                var tempN = i + 1 == loop ? n % 8 : 8;
                if (tempN == 0 && n != 0)
                {
                    tempN = 8;
                }
                for (int j = 0; j < ba.Length; j++)
                {
                    if (j == 0)
                    {
                        Header = (byte)(ba2.Last() & ((byte)(Math.Pow(2, tempN) - 1) << (8 - tempN)));
                        tempByte = (byte)(ba2[j] & ((byte)(Math.Pow(2, tempN) - 1) << (8 - tempN)));
                        ba2[j] <<= tempN;
                    }
                    else
                    {
                        tempByte2 = (byte)(ba2[j] & ((byte)(Math.Pow(2, tempN) - 1) << (8 - tempN)));
                        ba2[j] <<= tempN;
                        ba2[j] |= (byte)(tempByte >> (8 - tempN));
                        tempByte = tempByte2;
                        if (j + 1 == ba.Length)
                        {
                            ba2[0] |= (byte)(Header >> (8 - tempN));
                        }
                    }
                }
            }
            return ba2;
        }
    }
}
