using Edge.Core.Parser.BinaryParser;
using Edge.Core.Parser.BinaryParser.MessageEntity;
using Edge.Core.Parser.BinaryParser.Util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Wayne_Pump_Dart.MessageEntity;

namespace Wayne_Pump_Dart
{
    public class Parser : ParserBase
    {
        public Parser() : base(new MessageTemplateLookup())
        {
        }

        public override byte[] Serialize(MessageTemplateBase message)
        {
            //ADR   CTRL    NO    LNG     1    2   …   CRC-1   CRC-2   ETX     SF
            var bytesWithoutCrc16 = base.Serialize(message).ToList();
            var wayneDartMsg = message as MessageBase;
            if (wayneDartMsg.ControlCharacter == ControlCharacter.DATA)
            {
                var crc16 = bytesWithoutCrc16.ToArray().ComputeChecksumBytesCrc16().Reverse().ToArray();
                var processedBody = this.ProcessCodeTransparency(bytesWithoutCrc16);
                var processedCrc = this.ProcessCodeTransparency(crc16.ToList());
                var _ = processedBody.Concat(processedCrc).Concat(new byte[] { 0x03, 0xFA });
                return _.ToArray();
            }
            else if (wayneDartMsg.ControlCharacter == ControlCharacter.POLL
                || wayneDartMsg.ControlCharacter == ControlCharacter.ACK)
                return bytesWithoutCrc16.Concat(new byte[] { 0xFA }).ToArray();

            throw new InvalidOperationException("unhandled ControlCharacter of " + wayneDartMsg.ControlCharacter);
            //return bytesWithoutCrc16.Concat(new byte[] { 0x03, 0xFA }).ToArray();
        }

        public override MessageTemplateBase Deserialize(byte[] rawData)
        {
            if (rawData.Length > 4)
            {
                // exclude last 4 byte which are (2 bytes CRC + 1 byte EOT + 1byte 0xFA)
                return base.Deserialize(rawData.Take(rawData.Length - 4).ToArray());
            }
            else
            {
                // exclude last 1 byte of 0xFA
                return base.Deserialize(rawData.Take(rawData.Length - 1).ToArray());
            }
        }

        /// <summary>
        /// Code transparency for 8 bit data is achieved by Data Link escape (DLE) inser-tion. 
        /// DLE insertion is needed when any data byte or CRC has the value SF (stop flag). 
        /// Transmitting device transmit DLE before SF is transmitted in the data field. 
        /// Receiving device checks when receiving SF, if previous received character was DLE. 
        /// If so DLE is over written by the received SF in the line buffer. 
        /// Inserted DLE:s are not included in the CRC-calculation.
        /// </summary>
        /// <param name="original"></param>
        /// <returns></returns>
        private byte[] ProcessCodeTransparency(List<byte> original)
        {
            //====record 0xFA position============
            var indexs = new List<int>();
            for (int i = 0; i < original.Count; i++)
            {
                if (original[i] == 0xFA)
                {
                    indexs.Add(i);
                }
            }
            //=====end=====

            if (!indexs.Any()) return original.ToArray();
            //var originalLen = original.Skip(2).Take(2).GetBCD();
            //var newLen = (originalLen).GetBCDBytes(2);
            //original[2] = newLen[0];
            //original[3] = newLen[1];
            byte[] _ = new byte[original.Count];
            original.CopyTo(_);
            var newList = _.ToList();
            for (int i = 0; i < indexs.Count; i++)
            {
                newList.Insert(indexs[i] + i, 0x10);
            }

            return newList.ToArray();
        }

        //private static byte[] ProcessDoubleHexFAInCRC(byte[] originalCrc)
        //{
        //    var result = new List<byte>();
        //    result.Add(originalCrc[0]);
        //    if (originalCrc[0] == 0xFA)
        //    {
        //        result.Add(0xFA);
        //    }
        //    result.Add(originalCrc[1]);
        //    if (originalCrc[1] == 0xFA)
        //    {
        //        result.Add(0xFA);
        //    }

        //    return result.ToArray();
        //}

        //public override MessageTemplateBase Deserialize(byte[] rawData)
        //{
        //    // skip first 0xFA
        //    return base.Deserialize(rawData.Skip(1).ToArray());
        //}

        //public override MessageTemplateBase Deserialize(byte[] rawData, MessageTemplateBase withTemplate)
        //{
        //    // skip first 0xFA
        //    return base.Deserialize(rawData.Skip(1).ToArray(), withTemplate);
        //}
    }
}