using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.IO;
using skyscraper5.Skyscraper.Plugins;

namespace skyscraper8.InteractionChannel.Model2.Descriptors
{
	[SkyscraperPlugin]
	[TsDescriptor(0xbb,"TIM")]
	public class _0xbb_LowerLayerServiceDescriptor : TsDescriptor
	{
		public _0xbb_LowerLayerServiceDescriptor(byte[] buffer)
		{
			MemoryStream ms = new MemoryStream(buffer, false);
			DefaultControlRandomizationInterval = ms.ReadUInt8();
			DynamicRatePersistence = ms.ReadUInt8();
			VolumeBacklogPersistence = ms.ReadUInt8();
			int lowerLayerServiceCount = (ms.ReadUInt8() & 0x0f);
			LowerLayerServices = new LowerLayerService[lowerLayerServiceCount];
			for (int a = 0; a < lowerLayerServiceCount; a++)
			{
				LowerLayerService child = new LowerLayerService();
				LowerLayerServices[a] = child;

				byte byteA = ms.ReadUInt8();
				child.LowerLayerServiceIndex = (byteA & 0x3c) >> 2;
				bool randomAccess = (byteA & 0x02) != 0;
				bool dedicatedAccess = (byteA & 0x01) != 0;

				if (dedicatedAccess)
				{
					child.DedicatedAccess = new DedicatedAccessClass();
					byteA = ms.ReadUInt8();
					child.DedicatedAccess.NominalRcIndex = (byteA & 0xf0) >> 4;
					child.DedicatedAccess.NominalDaAcIndex = (byteA & 0x0f);
					child.DedicatedAccess.ConditionalDemandRcMap = ms.ReadUInt16BE();
					child.DedicatedAccess.ConditionalSchedulerDaAcMap = ms.ReadUInt16BE();
				}

				if (randomAccess)
				{
					child.RandomAccess = new RandomAccessClass();
					child.RandomAccess.NominalRaAcIndex = (byteA & 0x0f);
					child.RandomAccess.ConditionalSchedulerRaAcMap = ms.ReadUInt8();
				}
			}

			int rcCount = (ms.ReadUInt8() & 0x0f);
			Rcs = new RcClass[rcCount];
			for (int c = 0; c < rcCount; c++)
			{
				RcClass child = new RcClass();
				Rcs[c] = child;
				byte byteB = ms.ReadUInt8();
				child.RcIndex = (byteB & 0xf0) >> 4;
				bool constantAssignmentProvided = (byteB & 0x04) != 0;
				bool volumeAllowed = (byteB & 0x02) != 0;
				child.RbdcAllowed = (byteB & 0x01) != 0;
				child.MaximumServiceRate = ms.ReadUInt16BE();
				child.MinimumServiceRate = ms.ReadUInt16BE();
				if (constantAssignmentProvided)
				{
					child.ConstantServiceRate = ms.ReadUInt16BE();
				}

				if (volumeAllowed)
				{
					child.MaximumBacklog = ms.ReadUInt8();
				}
			}

			int raAcCount = (ms.ReadUInt8() & 0x0f);
			RaRcs = new RaAcClass[raAcCount];
			for (int b = 0; b < raAcCount; b++)
			{
				RaAcClass child = new RaAcClass();
				RaRcs[b] = child;
				child.RaAcIndex = (ms.ReadUInt8() & 0x0f);
				child.MaxUniquePayloadPerBlock = ms.ReadUInt8();
				child.MaxConsecutiveBlockAccessed = ms.ReadUInt8();
				child.MinIdleBlock = ms.ReadUInt8();
				byte defaultsFieldSize = ms.ReadUInt8();
				child.DefaultsForRaLoadControl = ms.ReadBytes(defaultsFieldSize);
			}

			Valid = true;
		}

		public RaAcClass[] RaRcs { get; private set; }
		public RcClass[] Rcs { get; private set; }
		public LowerLayerService[] LowerLayerServices { get; set; }

		public byte VolumeBacklogPersistence { get; set; }

		public byte DynamicRatePersistence { get; set; }

		public byte DefaultControlRandomizationInterval { get; set; }

		public class LowerLayerService
		{
			public int LowerLayerServiceIndex { get; set; }
			public DedicatedAccessClass DedicatedAccess { get; set; }
			public RandomAccessClass RandomAccess { get; set; }
		}

		public class DedicatedAccessClass
		{
			public int NominalRcIndex { get; set; }
			public int NominalDaAcIndex { get; set; }
			public ushort ConditionalDemandRcMap { get; set; }
			public ushort ConditionalSchedulerDaAcMap { get; set; }
		}

		public class RandomAccessClass
		{
			public int NominalRaAcIndex { get; set; }
			public byte ConditionalSchedulerRaAcMap { get; set; }
		}

		public class RcClass
		{
			public int RcIndex { get; set; }
			public bool RbdcAllowed { get; set; }
			public ushort MaximumServiceRate { get; set; }
			public ushort MinimumServiceRate { get; set; }
			public ushort? ConstantServiceRate { get; set; }
			public byte? MaximumBacklog { get; set; }
		}

		public class RaAcClass
		{
			public int RaAcIndex { get; set; }
			public byte MaxUniquePayloadPerBlock { get; set; }
			public byte MaxConsecutiveBlockAccessed { get; set; }
			public byte MinIdleBlock { get; set; }
			public byte[] DefaultsForRaLoadControl { get; set; }
		}

		public override string ToString()
		{
			return String.Format("{0} Lower Layer Services", LowerLayerServices.Length);
		}
	}
}
