using skyscraper5.Docsis.MacManagement;
using skyscraper5.Skyscraper;
using skyscraper5.Skyscraper.IO;
using skyscraper8.Docsis.AnnexC;
using skyscraper8.Docsis.DQoS;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Intrinsics;
using System.Text;
using System.Threading.Tasks;

namespace skyscraper5.Docsis.AnnexC
{
    public class CommonTlvEncodingObject
    {
        public CommonTlvEncodingObject(MemoryStream ms)
        {
            while (ms.GetAvailableBytes() > 2)
            {
                byte type = ms.ReadUInt8();
                byte len = ms.ReadUInt8();
                byte[] v = ms.ReadBytes(len);
                switch (type)
                {
                    case 5:
                        ModemCapabilitiesEncoding = new ModemCapabilitiesEncoding(v);
                        break;
                    case 22:
                        if (UpstreamDropPacketClassificationEncoding == null)
                            UpstreamDropPacketClassificationEncoding = new List<GeneralPacketClassifierEncoding>();
						UpstreamDropPacketClassificationEncoding.Add(new GeneralPacketClassifierEncoding(v));
                        break;
                    case 23:
                        if (DownstreamPacketClassificationEncoding == null)
                            DownstreamPacketClassificationEncoding = new List<GeneralPacketClassifierEncoding>();
                        DownstreamPacketClassificationEncoding.Add(new GeneralPacketClassifierEncoding(v));
                        break;
                    case 24:
                        if (UpstreamServiceFlows == null)
                            UpstreamServiceFlows = new List<GeneralServiceFlowEncoding>();
                        UpstreamServiceFlows.Add(new GeneralServiceFlowEncoding(v));
                        break;
                    case 25:
                        if (DownstreamServiceFlows == null)
                            DownstreamServiceFlows = new List<GeneralServiceFlowEncoding>();
                        DownstreamServiceFlows.Add(new GeneralServiceFlowEncoding(v));
                        break;
                    case 27:
                        HmacDigest = v;
                        break;
                    case 30:
                        AuthorizationHint = new AuthorizationBlock(v);
                        break;
                    case 31:
                        KeySequenceNumber = v[0];
                        break;
                    case 46:
                        if (TransmitChannelConfiguration == null)
                            TransmitChannelConfiguration = new List<TransmitChannelConfigurationObject>();
                        TransmitChannelConfiguration.Add(new TransmitChannelConfigurationObject(v));
                        break;
                    case 47:
                        ServiceFlowSidClusterAssignment = new ServiceFlowSidClusterAssignmentObject(v);
                        break;
                    case 49:
                        RcpId = new RcpIdEncoding(v);
                        break;
                    case 50:
                        if (DsidEncodings == null)
                            DsidEncodings = new List<DsidEncoding>();
                        DsidEncodings.Add(new DsidEncoding(v));
                        break;
                    case 52:
                        (v[0], v[1]) = (v[1], v[0]);
                        InitializingChannelTimeout = new TimeSpan(0, 0, BitConverter.ToUInt16(v));
                        break;
                    default:
                        //CM-SP-MULPIv4.0-I01-190815.pdf page 652
                        throw new NotImplementedException(string.Format("Common TLV Encodings Type {0}", type));
                }
            }
        }

        public ModemCapabilitiesEncoding ModemCapabilitiesEncoding { get; private set; }
        public ServiceFlowSidClusterAssignmentObject ServiceFlowSidClusterAssignment { get; private set; }
        public List<GeneralPacketClassifierEncoding> DownstreamPacketClassificationEncoding { get; set; }

        public List<GeneralPacketClassifierEncoding> UpstreamDropPacketClassificationEncoding { get; set; }

        public List<TransmitChannelConfigurationObject> TransmitChannelConfiguration { get; set; }
        public class TransmitChannelConfigurationObject : Validatable
        {
            public TransmitChannelConfigurationObject(byte[] buffer)
            {
                MemoryStream ms = new MemoryStream(buffer, false);
                while (ms.GetAvailableBytes() > 2)
                {
                    byte type = ms.ReadUInt8();
                    byte length = ms.ReadUInt8();
                    byte[] v = ms.ReadBytes(length);
                    switch (type)
                    {
                        case 1:
                            TccReferenceId = v[0];
                            break;
                        case 2:
                            UpstreamChannelAction = (UpstreamChannelActionEnum)v[0];
                            break;
                        case 3:
                            UpstreamChannelId = v[0];
                            break;
                        case 5:
                            this.UpstreamChannelDescriptor = new UpstreamChannelDescriptor(null, null, v);
                            break;
                        case 6:
                            (v[0], v[1]) = (v[1], v[0]);
                            RangingSid = BitConverter.ToUInt16(v, 0);
                            break;
                        case 7:
                            InitializationTechnique = (InitalizationTechniqueEnum?)v[0];
                            break;
                        case 9:
                            DynamicRangeWindow = v[0];
                            break;
                        case 10:
                            P16Hi = v[0];
                            break;
                        case 11:
                            ListOfIucs = v;
                            break;
                        default:
                            //see CM-SP-MULPIv4.0-I01-190815.pdf page 713
                            throw new NotImplementedException(string.Format("TCC TLV Type {0}", type));
                    }
                }
                Valid = true;
            }

            public byte[] ListOfIucs { get; set; }

            public ushort? RangingSid { get; set; }

            public byte? UpstreamChannelId { get; set; }

            public UpstreamChannelActionEnum? UpstreamChannelAction { get; private set; }
            public enum UpstreamChannelActionEnum : byte
            {
                NoAction = 0,
                Add = 1,
                Change = 2,
                Delete = 3,
                Replace = 4,
                Rerange = 5
            }

            public byte? TccReferenceId { get; set; }
			public InitalizationTechniqueEnum? InitializationTechnique { get; }
			public UpstreamChannelDescriptor UpstreamChannelDescriptor { get; }
			public byte DynamicRangeWindow { get; }
			public byte P16Hi { get; }
		}

        public byte KeySequenceNumber { get; set; }

        public byte[] HmacDigest { get; set; }

        public List<GeneralServiceFlowEncoding> DownstreamServiceFlows { get; set; }

        public List<GeneralServiceFlowEncoding> UpstreamServiceFlows { get; }
		public RcpIdEncoding RcpId { get; private set; }
		public AuthorizationBlock AuthorizationHint { get; }
		public List<DsidEncoding> DsidEncodings { get; private set; }
		public TimeSpan InitializingChannelTimeout { get; }
	}
}
