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 Sct : Validatable
	{
		public Sct(MemoryStream ms)
		{
			InBitStream ibs = new InBitStream(ms);
			uint superframeLoopCount = ibs.ReadBitsAsUint(8); superframeLoopCount++;
			Superframes = new Superframe[superframeLoopCount];
			for (int i = 0; i < superframeLoopCount; i++)
			{
				Superframes[i] = new Superframe();
				Superframes[i].SuperframeId = ibs.ReadBitsAsUint(8);
				Superframes[i].LargeTimingUncertainityFlag = ibs.ReadBitAsBoolean();
				uint reserved = ibs.ReadBitsAsUint(5);
				Superframes[i].UplinkPolarization = (Superframe.PolarizationDefinition)ibs.ReadBitsAsUint(2);
				Superframes[i].SuperframeStartTimeBase = ibs.ReadBitsAsULong(33);
				uint reserved2 = ibs.ReadBitsAsUint(6);
				Superframes[i].SuperframeStartTimeExt = ibs.ReadBitsAsUint(9);
				Superframes[i].SuperframeDuration = ibs.ReadBitsAsUint(32);
				Superframes[i].SuperframeCentreFrequency = ibs.ReadBitsAsUint(32);
				Superframes[i].SuperframeCounter = ibs.ReadBitsAsUint(16);
				uint reserved3 = ibs.ReadBitsAsUint(3);
				uint frameLoopCount = ibs.ReadBitsAsUint(5); frameLoopCount++;
				Superframes[i].Frames = new Superframe.Frame[frameLoopCount];
				for (uint j = 0; j < frameLoopCount; j++)
				{
					Superframes[i].Frames[j] = new Superframe.Frame();
					Superframes[i].Frames[j].FrameId = ibs.ReadBitsAsUint(8);
					Superframes[i].Frames[j].FrameStartTime = ibs.ReadBitsAsUint(32);
					Superframes[i].Frames[j].FrameCentreFrequencyOffset = ibs.ReadBitsAsUint(24);
				}
			}
			uint crc32 = ibs.ReadBitsAsUint(32);
			Valid = true;
		}

		public Superframe[] Superframes { get; }

		public class Superframe
		{
			public uint SuperframeId { get; internal set; }
			public bool LargeTimingUncertainityFlag { get; internal set; }
			public PolarizationDefinition UplinkPolarization { get; internal set; }
			public ulong SuperframeStartTimeBase { get; internal set; }
			public uint SuperframeStartTimeExt { get; internal set; }
			public uint SuperframeDuration { get; internal set; }
			public uint SuperframeCentreFrequency { get; internal set; }
			public uint SuperframeCounter { get; internal set; }
			public Frame[] Frames { get; internal set; }

			public enum PolarizationDefinition : uint
			{
				Horizontal = 0,
				Vertical = 1,
				Left = 2,
				Right = 3,
			}

			public class Frame
			{
				public uint FrameId { get; internal set; }
				public uint FrameStartTime { get; internal set; }
				public uint FrameCentreFrequencyOffset { get; internal set; }
			}

			protected bool Equals(Superframe other)
			{
				return SuperframeId == other.SuperframeId && UplinkPolarization == other.UplinkPolarization && SuperframeCentreFrequency == other.SuperframeCentreFrequency;
			}

			public override bool Equals(object? obj)
			{
				if (ReferenceEquals(null, obj)) 
					return false;
				if (ReferenceEquals(this, obj)) 
					return true;
				if (obj.GetType() != this.GetType()) 
					return false;
				return Equals((Superframe)obj);
			}

			public override int GetHashCode()
			{
				return HashCode.Combine(SuperframeId, (int)UplinkPolarization, SuperframeCentreFrequency);
			}
		}
	}
}
