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;
using skyscraper5.Mpeg2;

namespace skyscraper5.src.InteractionChannel.Model
{
	public class Cmt : Validatable
	{
		public Cmt(MemoryStream ms)
		{
			InBitStream ibs = new InBitStream(ms);
			byte entryLoopCount = ibs.ReadBitsAsByte(8);
			entryLoopCount++;
			Entries = new CmtEntry[entryLoopCount];

			for (int i = 0; i < entryLoopCount; i++)
			{
				Entries[i] = new CmtEntry();
				Entries[i].GroupId = ibs.ReadBitsAsByte(8);
				Entries[i].LoginId = ibs.ReadBitsAsUInt16(16);

				bool timeCorrectionFlag = ibs.ReadBitAsBoolean();
				bool powerCorrectionFlag = ibs.ReadBitAsBoolean();
				bool frequencyCorrectionFlag = ibs.ReadBitAsBoolean();
				Entries[i].SlotType = (CorrectionMessageSlotType)ibs.ReadBitsAsByte(2);
				Entries[i].BurstTimeScaling = ibs.ReadBitsAsByte(3);
				if (timeCorrectionFlag)
					Entries[i].BurstTimeCorrection = ibs.ReadBitsAsByte(8);

				if (powerCorrectionFlag)
				{
					bool powerControlFlag = ibs.ReadBitAsBoolean();
					if (powerControlFlag)
						Entries[i].PowerCorrection = ibs.ReadBitsAsByte(7);
					else
						Entries[i].EsN0 = ibs.ReadBitsAsByte(7);
				}

				if (frequencyCorrectionFlag)
					Entries[i].FrequencyCorrection = ibs.ReadBitsAsUInt16(16);
			}
			uint crc32 = ibs.ReadBitsAsUint(32);
			Valid = true;
		}

		public CmtEntry[] Entries;

		public class CmtEntry
		{
			public byte GroupId { get; internal set; }
			public ushort LoginId { get; internal set; }
			public CorrectionMessageSlotType SlotType { get; internal set; }
			public int BurstTimeScaling { get; internal set; }
			public uint? BurstTimeCorrection { get; internal set; }
			public int? PowerCorrection { get; internal set; }
			public int? EsN0 { get; internal set; }
			public ushort FrequencyCorrection { get; internal set; }

			protected bool Equals(CmtEntry other)
			{
				return GroupId == other.GroupId && LoginId == other.LoginId && SlotType == other.SlotType;
			}

			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((CmtEntry)obj);
			}

			public override int GetHashCode()
			{
				return HashCode.Combine(GroupId, LoginId, (int)SlotType);
			}
		}
	}
}
