using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Skyscraper;
using skyscraper5.Skyscraper.IO;
using skyscraper5.Skyscraper.Plugins;

namespace skyscraper5.T2MI.Packets
{
	[SkyscraperPlugin]
	[T2MiPacketType(0x10)]
    public class _0x10_L1Current : T2MiPacket
    {
        public _0x10_L1Current(T2MIHeader header, byte[] buffer) : base(header, buffer)
        {
            if (buffer.Length < 2)
            {
                Valid = false;
                return;
            }
            FrameIndex = buffer[0];
            FrequencySource = (buffer[1] & 0xc0) >> 6;
            L1CurrentData = new L1CurrentDataFields(buffer);
            Valid = L1CurrentData.Valid;
        }

        public L1CurrentDataFields L1CurrentData { get; }
        public int FrequencySource { get; private set; }

        public byte FrameIndex { get; private set; }

        public class L1CurrentDataFields : Validatable
        {
            public L1CurrentDataFields(byte[] buffer)
            {
                if (buffer.Length < 23)
                {
                    Valid = false;
                    return;
                }

                MemoryStream ms = new MemoryStream(buffer, 2, buffer.Length - 2, false);
                L1PreSignallingBits = ms.ReadBytes(21);
                if (ms.GetAvailableBytes() < 2)
                {
                    Valid = false;
                    return;
                }
                ushort l1conflen = ms.ReadUInt16BE();

                int l1conflenRounded = Align(l1conflen);
                if (l1conflenRounded > ms.GetAvailableBytes())
                {
                    Valid = false;
                    return;
                }

                L1ConfigurablePostSignalling = ms.ReadBytes(l1conflenRounded);
                ushort l1dynCurrLen = ms.ReadUInt16BE();

                int l1dynCurrLenRounded = Align(l1dynCurrLen);
                if (l1dynCurrLenRounded > ms.GetAvailableBytes())
                {
                    Valid = false;
                    return;
                }

                L1DynamicCurrentFrame = ms.ReadBytes(l1dynCurrLenRounded);
                ushort l1extLen = ms.ReadUInt16BE();
                int alignedLen = Align(l1extLen);
                if (alignedLen > ms.GetAvailableBytes())
                {
                    Valid = false;
                    return;
                }
                L1Extension = ms.ReadBytes(alignedLen);
                Valid = true;
            }

            private static int Align(ushort len)
            {
                if (len % 8 == 0)
                    return len / 8;
                else
                {
                    len /= 8;
                    len++;
                    return len;
                }
            }

            public byte[] L1Extension { get; private set; }

            public byte[] L1DynamicCurrentFrame { get; private set; }

            public byte[] L1ConfigurablePostSignalling { get; private set; }

            public byte[] L1PreSignallingBits { get; private set; }
        }
    }
}
