using System.IO;
using System.Net.NetworkInformation;
using skyscraper5.Skyscraper.IO;
using skyscraper5.Skyscraper.Plugins;
using skyscraper5.Skyscraper.Scraper;

namespace skyscraper5.Docsis.MacManagement
{
	[SkyscraperPlugin]
	[MacManagementMessageType(5, 3)]
    internal class UpstreamBandwidthAllocationV5 : MacManagementMessage
    {
        public UpstreamBandwidthAllocationV5(PhysicalAddress source, PhysicalAddress destination, byte[] buffer) : base(source, destination, buffer)
        {
            MemoryStream ms = new MemoryStream(buffer, false);
            UpstreamChannelId = ms.ReadUInt8();
            UcdCount = ms.ReadUInt8();

            ushort readUInt16Be = ms.ReadUInt16BE();
            int numberOfElements = (readUInt16Be & 0xff80) >> 7;
            int rsvd = (readUInt16Be & 0x0070) >> 4;
            CAT = (readUInt16Be & 0x000f);

            AllocStartTime = ms.ReadUInt32BE();
            ProbeInformationElements = new ProbeInformationElement[numberOfElements];

            for (int i = 0; i < numberOfElements; i++)
            {
                ProbeInformationElements[i] = new ProbeInformationElement(ms.ReadUInt32BE());
            }
            Valid = true;
        }

        internal struct ProbeInformationElement
        {
            public ProbeInformationElement(uint value)
            {
                this.RawValue = value;
            }

            public uint RawValue { get; private set; }

            public uint SID => (RawValue & 0xfffc0000) >> 18;

            public bool MER => (RawValue & 0x00020000) != 0;

            public bool Power => (RawValue & 0x00010000) != 0;

            public bool TxEqualization => (RawValue & 0x00008000) != 0;

            public bool Stagger => (RawValue & 0x00004000) != 0;

            public uint ProbeFrame => (RawValue & 0x00003000) >> 12;

            public uint SymbolInFrame =>   (RawValue & 0x00000fc0) >> 6;

            public uint StartSubcarrier => (RawValue & 0x00000038) >> 3;

            public uint SubcarrierSkipping => (RawValue & 0x00000007);

            public override string ToString()
            {
                return $"{nameof(SID)}: {SID}, {nameof(ProbeFrame)}: {ProbeFrame}, {nameof(SymbolInFrame)}: {SymbolInFrame}, {nameof(StartSubcarrier)}: {StartSubcarrier}, {nameof(SubcarrierSkipping)}: {SubcarrierSkipping}";
            }
        }

        public ProbeInformationElement[] ProbeInformationElements { get; private set; }

        public uint AllocStartTime { get; private set; }

        public int CAT { get; private set; }

        public byte UcdCount { get; private set; }

        public byte UpstreamChannelId { get; private set; }
    }
}
