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

namespace skyscraper5.src.InteractionChannel.Model
{
	public class Tct : Validatable
	{
		public Tct(MemoryStream ms)
		{
			byte timeslotLoopCount = ms.ReadUInt8(); timeslotLoopCount++;
			Timeslots = new Timeslot[timeslotLoopCount];
			for (int i = 0; i < timeslotLoopCount; i++)
			{
				if (ms.GetAvailableBytes() < 9)
				{
					Valid = false;
					return;
				}
				Timeslots[i] = new Timeslot();
				Timeslots[i].TimeslotId = ms.ReadUInt8();
				Timeslots[i].SymbolRate = ms.ReadUInt24BE();
				Timeslots[i].TimeslotDuration = ms.ReadUInt24BE();
				Timeslots[i].BurstStartOffset = ms.ReadUInt16BE();

				byte byteA = ms.ReadUInt8();
				Timeslots[i].InnerCodeType = (byteA & 0x80) != 0;
				Timeslots[i].InnerTypeOrdering = (byteA & 0x40) != 0;
				Timeslots[i].OuterCoding = (byteA & 0x30) >> 4;
				Timeslots[i].InnerCodePuncturing = (Timeslot.InnerCodingEnum)(byteA & 0x0f);

				byte byteB = ms.ReadUInt8();
				Timeslots[i].Modulation = (byteB & 0xf8) >> 3;
				Timeslots[i].BasebandShaping = (Timeslot.ReturnLinkBasebandShaping)(byteB & 0x07);

				Timeslots[i].TimeslotPayloadType = (Timeslot.TimeslotType)ms.ReadUInt8();
				byte byteC = ms.ReadUInt8();
				Timeslots[i].RouteIdFlag = (byteA & 0x80) != 0;
				Timeslots[i].AcmFlag = (byteA & 0x40) != 0;
				Timeslots[i].MobFlag = (byteA & 0x20) != 0;
				Timeslots[i].SacLength = (byteA & 0x1f);

				byte byteD = ms.ReadUInt8();
				Timeslots[i].RequestFlag = (byteD & 0x80) != 0;
				Timeslots[i].MandCFlag = (byteD & 0x40) != 0;
				Timeslots[i].GroupIdFlag = (byteD & 0x20) != 0;
				Timeslots[i].LogonIdFlag = (byteD & 0x10) != 0;
				Timeslots[i].CapacityRequestsNumber = (byteD & 0x0e);
				Timeslots[i].NewPermutation = (byteD & 0x01) != 0;
				if (Timeslots[i].InnerCodeType && Timeslots[i].NewPermutation)
				{
					Timeslots[i].P0 = ms.ReadUInt8();
					Timeslots[i].P1 = ms.ReadUInt16BE();
					Timeslots[i].P2 = ms.ReadUInt16BE();
					Timeslots[i].P3 = ms.ReadUInt16BE();
				}

				int preambleLength = ms.ReadUInt8();
				InBitStream ibs = new InBitStream(ms);
				long neededBits = preambleLength * 2;
				if (neededBits > ibs.GetBitsAvailable())
				{
					Valid = false;
					return;
				}
				for (int j =  0; j < preambleLength; j++)
				{
					Timeslots[i].PreambleSymbol <<= 2;
					Timeslots[i].PreambleSymbol += ibs.ReadBitsAsByte(2);
				}
				
			}
			uint crc32 = ms.ReadUInt32BE();
			Valid = true;
		}

		public Timeslot[] Timeslots { get;  }

		public class Timeslot
		{
			public byte TimeslotId { get; internal set; }
			public uint SymbolRate { get; internal set; }
			public uint TimeslotDuration { get; internal set; }
			public ushort BurstStartOffset { get; internal set; }
			public bool InnerCodeType { get; internal set; }
			public bool InnerTypeOrdering { get; internal set; }
			public int OuterCoding { get; internal set; }
			public InnerCodingEnum InnerCodePuncturing { get; internal set; }
			public int Modulation { get; internal set; }
			public ReturnLinkBasebandShaping BasebandShaping { get; internal set; }
			public TimeslotType TimeslotPayloadType { get; internal set; }
			public bool RouteIdFlag { get; internal set; }
			public bool AcmFlag { get; internal set; }
			public bool MobFlag { get; internal set; }
			public int SacLength { get; internal set; }
			public bool RequestFlag { get; internal set; }
			public bool MandCFlag { get; internal set; }
			public bool GroupIdFlag { get; internal set; }
			public bool LogonIdFlag { get; internal set; }
			public int CapacityRequestsNumber { get; internal set; }
			public bool NewPermutation { get; internal set; }
			public byte P0 { get; internal set; }
			public ushort P1 { get; internal set; }
			public ushort P2 { get; internal set; }
			public ushort P3 { get; internal set; }
			public long PreambleSymbol { get; internal set; }

			public enum InnerCodingEnum
			{
				Half = 0,
				TwoThirds = 1,
				ThreeFourths = 2,
				FiveSixths = 3,
				SevenEights = 4,
				OneThirds = 5,
				TwoFifths = 6,
				FourFifths = 7,
				SixSevenths = 8,
				OneFourths = 9,
				ThreeFifths = 10,
				EightNinths = 11,
				NineTenths = 12,
				Omitted = 15
			}

			public enum ReturnLinkBasebandShaping
			{
				_0_35 = 0,
				_0_25 = 1,
				_0_20 = 2
			}

			public enum TimeslotType
			{
				TRF_One_ATM = 0x01,
				TRF_Two_ATM = 0x02,
				TRF_Four_ATM = 0x04,
				TRF_MPEG2 = 0x05,
				CSC = 0x06,
				ACQ = 0x07,
				SYNC = 0x08,
				DVBS2_Normal_Pilots = 0x09,
				DVBS2_Normal = 0x0a,
				DVBS2_Short_Pilots = 0x0b,
				DVBS2_Short = 0x0c,
				DVBS2_Extension = 0x0d
			}

			public override string ToString()
			{
				return String.Format("ID = {0}, SymbolRate = {1}, PayloadType = {2}, Acm = {3},", this.TimeslotId, SymbolRate, TimeslotPayloadType, AcmFlag);
			}
		}
	}
}
