using skyscraper5.Skyscraper.IO;
using skyscraper8.DvbNip;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Skyscraper;

namespace skyscraper8.Ietf.FLUTE
{
	internal class LctHeader : Validatable
	{
		/// <summary>
		/// 
		/// </summary>
		/// <param name="headerBuffer">A buffer that contains an LCT Header starting from the first byte of the Congestion Control Information</param>
		/// <param name="c">Congestion control flag</param>
		/// <param name="s">Transport Session Identifier flag</param>
		/// <param name="o">Transport Object Identifier flag</param>
		/// <param name="h">Half-word flag</param>
		/// <exception cref="NotSupportedException"></exception>
		public LctHeader(byte[] headerBuffer, int c, bool sFlag, int o, bool hFlag)
		{
			int s = sFlag ? 1 : 0;
			int h = hFlag ? 1 : 0;
			
			MemoryStream ms = new MemoryStream(headerBuffer, false);
			int cciLength = 32 * (c + 1);
			int tsiLength = 32 * s + 16 * h;
			int toiLength = 32 * o + 16 * h;

			CongestionControlInformation = ReadField(ms, cciLength);
			TransportSessionIdentifier = ReadField(ms, tsiLength);
			TransportObjectIdentifier = ReadField(ms, toiLength);
			if (CongestionControlInformation == UInt64.MaxValue || TransportSessionIdentifier == UInt64.MaxValue || TransportObjectIdentifier == UInt64.MaxValue)
			{
				Valid = false;
				return;
			}

			while (ms.GetAvailableBytes() >= 1)
			{
				byte extensionId = ms.ReadUInt8();
				if (extensionId >= 128)
				{
					ms.Position--;
					uint fixedHeaderExtension = ms.ReadUInt32BE();
					switch (extensionId)
					{
						case 192:
							this.FdtInstanceId = new FdtInstanceHeader(fixedHeaderExtension);
							break;
						case 193:
							this.ContentEncoding = new ContentEncodingOfFdtInstance(fixedHeaderExtension);
							break;
						default:
							Debug.WriteLine(String.Format("LCT Header Extension {0}", extensionId));
							Valid = false;
							return;
					}
				}
				else
				{
					uint headerExtensionLength = ms.ReadUInt8();
					headerExtensionLength *= 4;
					if (headerExtensionLength >= 2)
						headerExtensionLength -= 2;
					if (headerExtensionLength > ms.GetAvailableBytes())
					{
						Valid = false;
						return;
					}
					byte[] extensionBuffer = ms.ReadBytes(headerExtensionLength);
					switch(extensionId)
					{
						case 0:
							break;
						case 2:
							this.TimeExtenstion = new TimeHeaderExtension(extensionBuffer);
							break;
						case 64:
							this.FecObjectTransmissionInformation = new FecObjectTransmissionInformation(extensionBuffer);
							break;
						case 68:
							this.NipActualCarrierInformation = new NipActualCarrierInformation(extensionBuffer);
							break;
						default:
							Debug.WriteLine(String.Format("LCT Header Extension {0}", extensionId));
							Valid = false;
							return;
					}
				}
				
			}

			Valid = true;
		}

		private ulong ReadField(Stream stream, int bits)
		{
			switch(bits)
			{
				case 16:
					return stream.ReadUInt16BE();
				case 32:
					return stream.ReadUInt32BE();
				case 48:
					return stream.ReadUInt48BE();
				case 64:
					return stream.ReadUInt64BE();
				default:
					return UInt64.MaxValue;
			}
		}
		public ulong CongestionControlInformation { get; private set; }
		public ulong TransportSessionIdentifier { get; }
		public ulong TransportObjectIdentifier { get; }
		public FdtInstanceHeader FdtInstanceId { get; }
		public NipActualCarrierInformation NipActualCarrierInformation { get; }
		public FecObjectTransmissionInformation FecObjectTransmissionInformation { get; }
		public TimeHeaderExtension TimeExtenstion { get; }
		public ContentEncodingOfFdtInstance ContentEncoding { get; }
	}
}
