using System;
using System.Collections.Generic;
using System.Text;
namespace IceCoffee.HJ212.Models
{
    /// 
    /// 通讯包
    /// 
    public class NetPackage
    {
        /// 
        /// 默认头
        /// 
        public const string FixedHead = "##";
        /// 
        /// 默认尾
        /// 
        public const string FixedTail = "\r\n";
        /// 
        /// 包头
        /// 
        public string Head { get; set; }
        /// 
        /// 数据段长度
        /// 
        public int DataSegmentLength { get; set; }
        /// 
        /// 数据段
        /// 
        public DataSegment DataSegment { get; set; }
        /// 
        /// CRC校验码
        /// 
        public string CrcCode { get; set; }
        /// 
        /// 包尾
        /// 
        public string Tail { get; set; }
        /// 
        /// CRC16校验
        /// 
        /// 需要校验的字符串
        /// CRC16 校验码
        private static string CRC16(string arg)
        {
            char[] puchMsg = arg.ToCharArray();
            uint i, j, crc_reg, check;
            crc_reg = 0xFFFF;
            for (i = 0; i < puchMsg.Length; i++)
            {
                crc_reg = (crc_reg >> 8) ^ puchMsg[i];
                for (j = 0; j < 8; j++)
                {
                    check = crc_reg & 0x0001;
                    crc_reg >>= 1;
                    if (check == 0x0001)
                    {
                        crc_reg ^= 0xA001;
                    }
                }
            }
            return crc_reg.ToString("X2").PadLeft(4, '0');
        }
        /// 
        /// 解析
        /// 
        /// 
        /// 
        /// 
        public static NetPackage Parse(string line, Func unpackCacheFunc = null)
        {
            try
            {
                NetPackage netPackage = new NetPackage();
                netPackage.Head = line.Substring(0, 2);
                netPackage.DataSegmentLength = int.Parse(line.Substring(2, 4));
                string dataSegment = line.Substring(6, netPackage.DataSegmentLength);
                string crcCode = line.Substring(6 + netPackage.DataSegmentLength, 4);
                string calcCrcCode = CRC16(dataSegment);
                if (crcCode != calcCrcCode)
                {
                    throw new Exception("CRC校验失败 " + line);
                }
                netPackage.DataSegment = DataSegment.Parse(dataSegment, unpackCacheFunc);
                netPackage.CrcCode = crcCode;
                netPackage.Tail = line.Substring(10 + netPackage.DataSegmentLength);
                return netPackage;
            }
            catch (Exception ex)
            {
                throw new Exception("Error in NetPackage.Parse", ex);
            }
        }
        /// 
        /// 序列化
        /// 
        /// 
        public string Serialize()
        {
            string dataSegment = DataSegment.Serialize();
            DataSegmentLength = dataSegment.Length;
            CrcCode = CRC16(dataSegment);
            return $"{Head}{DataSegmentLength.ToString().PadLeft(4, '0')}{dataSegment}{CrcCode}{Tail}";
        }
    }
}