using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Skyscraper.IO;
using static skyscraper5.Dvb.Descriptors.ServiceListDescriptor;

namespace skyscraper5.Docsis.AnnexC
{
    public class GeneralServiceFlowEncoding
    {
        public GeneralServiceFlowEncoding(byte[] buffer)
        {
            MemoryStream ms = new MemoryStream(buffer, false);
            while (ms.GetAvailableBytes() > 2)
            {
                byte type = ms.ReadUInt8();
                byte len = ms.ReadUInt8();
                byte[] v = ms.ReadBytes(len);
                switch (type)
                {
                    case 1:
                        (v[0], v[1]) = (v[1], v[0]);
                        ServiceFlowReference = BitConverter.ToUInt16(v, 0);
                        break;
                    case 2:
                        (v[0], v[1]) = (v[1], v[0]);
                        ServiceFlowIdentifier = BitConverter.ToUInt16(v, 0);
                        break;
                    case 6:
                        ProvisionedSet = (v[0] & 0x01) != 0;
                        AdmittedSet = (v[0] & 0x02) != 0;
                        ActiveSet = (v[0] & 0x04) != 0;
                        break;
                    case 7:
                        TrafficPriority = v[0];
                        break;
                    case 8:
                        (v[0], v[1], v[2], v[3]) = (v[3], v[2], v[1], v[0]);
                        UpstreamMaximumSustainedTrafficRate = BitConverter.ToUInt32(v, 0);
                        break;
                    case 9:
                        (v[0], v[1], v[2], v[3]) = (v[3], v[2], v[1], v[0]);
                        MaximumTrafficBurst = BitConverter.ToUInt32(v, 0);
                        break;
                    case 10:
                        (v[0], v[1], v[2], v[3]) = (v[3], v[2], v[1], v[0]);
                        MinimumReservedTrafficRate = BitConverter.ToUInt32(v, 0);
                        break;
                    case 11:
                        (v[0], v[1]) = (v[1], v[0]);
                        AssumedMinimumReservedRatePacketSize = BitConverter.ToUInt16(v, 0);
                        break;
                    case 12:
                        (v[0], v[1]) = (v[1], v[0]);
                        TimeoutForActiveQosParameters = BitConverter.ToUInt16(v, 0);
                        break;
                    case 14:
						(v[0], v[1]) = (v[1], v[0]);
                        MaximumConcatenatedBurst = BitConverter.ToUInt16(v, 0);
                        break;
					case 15:
                        ServiceFlowSchedulingType = (ServiceFlowSchedulingTypeEnum)v[0];
                        break;
                    case 16:
                        DoNotUseAllCms = (v[3] & 0x01) != 0;
                        DoNotUsePriorityRequest = (v[3] & 0x02) != 0;
                        DoNotUseRequest2ForRequests = (v[3] & 0x04) != 0;
                        DoNotUseRequest2ForData = (v[3] & 0x08) != 0;
                        DoNotPiggybackRequests = (v[3] & 0x10) != 0;
                        DoNotConcatenateData = (v[3] & 0x20) != 0;
                        DoNotFragmentData = (v[3] & 0x40) != 0;
                        DoNotSupressPayloadHeaders = (v[3] & 0x80) != 0;
                        DropPacketsTooBigForUnsolicitedGrant = (v[2] & 0x01) != 0;
                        DoNotUseSegmentHeaders = (v[2] & 0x02) != 0;
                        DoNotUseContentionRegions = (v[2] & 0x04) != 0;
                        break;
                    case 17:
                        if (len == 4)
                        {
                            (v[0], v[1], v[2], v[3]) = (v[3], v[2], v[1], v[0]);
                            NominalPollingInterval = BitConverter.ToUInt32(v, 0);
                        }
                        else if (len == 1)
                        {
                            DownstreamResequencing = v[0];
                        }
                        break;
                    case 19:
                        (v[0], v[1]) = (v[1], v[0]);
                        UnsolicitedGrantSize = BitConverter.ToUInt16(v, 0);
                        break;
                    case 20:
                        (v[0], v[1], v[2], v[3]) = (v[3], v[2], v[1], v[0]);
                        NominalGrantInterval = BitConverter.ToUInt32(v, 0);
                        break;
                    case 21:
                        (v[0], v[1], v[2], v[3]) = (v[3], v[2], v[1], v[0]);
                        ToleratedGrantJitter = BitConverter.ToUInt32(v, 0);
                        break;
                    case 22:
                        GrantsPerInterval = v[0];
                        break;
                    case 23:
                        IpTypeOfServiceOverwrite = v;
                        break;
                    case 24:
                        (v[0], v[1], v[2], v[3]) = (v[3], v[2], v[1], v[0]);
                        CmtsTimestamp = BitConverter.ToUInt32(v, 0);
                        break;
                    case 26:
                        MultiplierToNumberOfBytesRequested = v[0];
                        break;
                    case 32:
						(v[0], v[1], v[2], v[3]) = (v[3], v[2], v[1], v[0]);
                        ServiceFlowForbiddenAttributeMask = BitConverter.ToUInt32(v);
                        break;

					default:
                        //CM-SP-MULPIv4.0-I01-190815.pdf page 758
                        throw new NotImplementedException(string.Format("General Service Flow Encodings Type {0}", type));
                }
            }
        }

        public byte? DownstreamResequencing { get; set; }

        public uint? NominalPollingInterval { get; set; }

        public ushort? ServiceFlowReference { get; set; }

        public ushort? AssumedMinimumReservedRatePacketSize { get; set; }

        public byte? TrafficPriority { get; set; }

        public uint? MaximumTrafficBurst { get; set; }

        public uint? MinimumReservedTrafficRate { get; set; }

        public uint? UpstreamMaximumSustainedTrafficRate { get; set; }

        public uint? CmtsTimestamp { get; set; }

        public uint? NominalGrantInterval { get; set; }

        public byte? GrantsPerInterval { get; set; }

        public bool? DoNotUseContentionRegions { get; set; }

        public bool? DoNotUseSegmentHeaders { get; set; }

        public bool? DropPacketsTooBigForUnsolicitedGrant { get; set; }

        public bool? DoNotSupressPayloadHeaders { get; set; }

        public bool? DoNotFragmentData { get; set; }

        public bool? DoNotConcatenateData { get; set; }

        public bool? DoNotPiggybackRequests { get; set; }

        public bool? DoNotUseRequest2ForData { get; set; }

        public bool? DoNotUseRequest2ForRequests { get; set; }

        public bool? DoNotUsePriorityRequest { get; set; }

        public bool? DoNotUseAllCms { get; set; }

        public ServiceFlowSchedulingTypeEnum ServiceFlowSchedulingType { get; private set; }
        public enum ServiceFlowSchedulingTypeEnum : byte
        {
            BestEffort = 2,
            NonRealTimePollingService = 3,
            RealTimePollingService = 4,
            UnsolicitedGrantServiceWithActivityDeletion = 5,
            UnsolicitedGrantService = 6,
            ProactiveGrantService = 7
        }

        public uint? ToleratedGrantJitter { get; set; }

        public ushort? UnsolicitedGrantSize { get; set; }

        public ushort? TimeoutForActiveQosParameters { get; set; }

        public ushort? ServiceFlowIdentifier { get; set; }

        public bool? ActiveSet { get; set; }

        public bool? AdmittedSet { get; set; }

        public bool? ProvisionedSet { get; set; }
		public byte[] IpTypeOfServiceOverwrite { get; }
		public ushort MaximumConcatenatedBurst { get; }
		public byte MultiplierToNumberOfBytesRequested { get; }
		public uint ServiceFlowForbiddenAttributeMask { get; }

		public override string ToString()
        {
            return $"{nameof(ServiceFlowIdentifier)}: {ServiceFlowIdentifier}";
        }
    }
}
