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

namespace skyscraper8.T2MI.Packets
{
    [SkyscraperPlugin]
    [T2MiPacketType(0xf0)]
    public class _0xF0_FramingTimingInformation : T2MiPacket
    {
        public _0xF0_FramingTimingInformation(T2MIHeader header, byte[] buffer) : base(header, buffer)
        {
            MemoryStream ms = new MemoryStream(buffer, false);

            FrameIndex = ms.ReadUInt8();

            NumberOfPlps = ms.GetAvailableBytes() / 32;

            InBitStream bitStream = new InBitStream(ms);

            Plps = new Plp[NumberOfPlps];
            for (long u = 0; u < NumberOfPlps; u++)
            {
                Plp plp = new Plp();
                plp.PlpId = bitStream.ReadBitsAsByte(8);
                plp.IntlFrameStart = bitStream.ReadBitAsBoolean();
                plp.Rfu = bitStream.ReadBitsAsByte(7);
                plp.Matype1 = bitStream.ReadBitsAsByte(8);
                plp.Matype2 = bitStream.ReadBitsAsByte(8);
                plp.TtoE = bitStream.ReadBitsAsByte(5);
                plp.TtoM = bitStream.ReadBitsAsByte(7);
                plp.TtoL = bitStream.ReadBitsAsByte(8);
                plp.FirstIscr = bitStream.ReadBitsAsUint(22);
                plp.Bufs = bitStream.ReadBitsAsUInt16(12);
                plp.FirstDfl = bitStream.ReadBitsAsUInt16(16);
                plp.FirstSyncd = bitStream.ReadBitsAsUInt16(16);
                plp.NextFirstSyncd = bitStream.ReadBitsAsUInt16(16);
                plp.Mode = bitStream.ReadBitsAsByte(8);
                plp.Pcr = bitStream.ReadBitsAsULong(48);
                plp.FramePktCount = bitStream.ReadBitsAsUint(32);
                plp.Dpcr = bitStream.ReadBitsAsUint(32);
                Plps[u] = plp;
            }
            Valid = NumberOfPlps > 0;
        }

        
        public byte FrameIndex { get; }
        public long NumberOfPlps { get; }
        public Plp[] Plps { get; }

        public override bool Equals(object? obj)
        {
            if (obj == null) 
                return false;
            if (!(obj is _0xF0_FramingTimingInformation))
                return false;

            _0xF0_FramingTimingInformation that = (_0xF0_FramingTimingInformation)obj;
            if (this.FrameIndex != that.FrameIndex) 
                return false;
            if (this.NumberOfPlps != that.NumberOfPlps) 
                return false;
            for (int i = 0; i < Plps.Length; i++)
            {
                if (!this.Plps[i].Equals(that.Plps[i]))
                    return false;
            }
            return true;
        }

        public class Plp
        {
            public byte PlpId { get; internal set; }
            public bool IntlFrameStart { get; internal set; }
            public byte Rfu { get; internal set; }
            public byte Matype1 { get; internal set; }
            public byte Matype2 { get; internal set; }
            public byte TtoE { get; internal set; }
            public byte TtoM { get; internal set; }
            public byte TtoL { get; internal set; }
            public uint FirstIscr { get; internal set; }
            public ushort Bufs { get; internal set; }
            public ushort FirstDfl { get; internal set; }
            public ushort FirstSyncd { get; internal set; }
            public ushort NextFirstSyncd { get; internal set; }
            public byte Mode { get; internal set; }
            public ulong Pcr { get; internal set; }
            public uint FramePktCount { get; internal set; }
            public uint Dpcr { get; internal set; }

            public override bool Equals(object? obj)
            {
                return obj is Plp plp &&
                       PlpId == plp.PlpId &&
                       IntlFrameStart == plp.IntlFrameStart &&
                       Rfu == plp.Rfu &&
                       Matype1 == plp.Matype1 &&
                       Matype2 == plp.Matype2 &&
                       TtoE == plp.TtoE &&
                       TtoM == plp.TtoM &&
                       TtoL == plp.TtoL &&
                       FirstIscr == plp.FirstIscr &&
                       Bufs == plp.Bufs &&
                       FirstDfl == plp.FirstDfl &&
                       FirstSyncd == plp.FirstSyncd &&
                       NextFirstSyncd == plp.NextFirstSyncd &&
                       Mode == plp.Mode &&
                       Pcr == plp.Pcr &&
                       FramePktCount == plp.FramePktCount &&
                       Dpcr == plp.Dpcr;
            }
        }


    }
}
