using skyscraper5.Dvb.Descriptors;
using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.IO;
using skyscraper5.Skyscraper.Plugins;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace skyscraper5.src.InteractionChannel.Model.Descriptors
{
	[SkyscraperPlugin]
	[TsDescriptor(0xa8,"RMT")]
	public class _0xa8_SatelliteForwardLinkDescriptor : TsDescriptor
	{
		public _0xa8_SatelliteForwardLinkDescriptor(byte[] buffer)
		{
			MemoryStream ms = new MemoryStream(buffer, false);
			SatelliteId = ms.ReadUInt8();
			BeamId = ms.ReadUInt16BE();
			NccId = ms.ReadUInt8();

			byte byteA = ms.ReadUInt8();
			LinkUsage = (ForwardLinkUsageCodes)((byteA & 0xe0) >> 5);
			LocalLinkId = (byteA & 0x1f);

			Frequency = ms.ReadUInt32BE();
			OrbitalPosition = ms.ReadUInt16BE();

			byte byteB = ms.ReadUInt8();
			East = (byteB & 0x80) != 0;
			Polarization = (ForwardLinkPolarization)((byteB & 0x60) >> 5);
			TransmissionStandard = (TransmissionStandardEnum)((byteB & 0x18) >> 3);
			if (TransmissionStandard == TransmissionStandardEnum.DVBS)
			{
				int assertion = ((byteB & 0x07));
				if (assertion != 1)
				{
					Valid = false;
					return;
				}
			}
			else if (TransmissionStandard == TransmissionStandardEnum.DVBS2_CCM || TransmissionStandard == TransmissionStandardEnum.DVBS2_ACM)
			{
				ScramblingSequenceSelector = (byteB & 0x04) != 0;
				int rollOff = (byteB & 0x03);
				switch(rollOff)
				{
					case 0: RollOff = null; break;
					case 1: RollOff = 0.2; break;
					case 2: RollOff = 0.25; break;
					case 3: RollOff = 0.35; break;
				}
			}
			SymbolRate = ms.ReadUInt24BE();
			if (TransmissionStandard == TransmissionStandardEnum.DVBS)
			{
				byte byteC = ms.ReadUInt8();
				FecInner = (InnerFecScheme?)((byteC & 0xf0) >> 4);
				int reserved = (byteC & 0x0f);
			}
			else if (TransmissionStandard == TransmissionStandardEnum.DVBS2_CCM || TransmissionStandard == TransmissionStandardEnum.DVBS2_ACM)
			{
				InputStreamIndentifier = ms.ReadUInt8();
				if (ScramblingSequenceSelector.Value == false)
				{
					byte byteC = ms.ReadUInt8();
					SpreadingCodeSelector = ((byteC & 0xe0) >> 5);
					ScramblingSequenceIndex = (byteC & 0x03);
					ScramblingSequenceIndex <<= 16;
					ScramblingSequenceIndex += ms.ReadUInt16BE();
				}
			}

			PrivateDataBytes = ms.ReadBytes(ms.GetAvailableBytes());
			Valid = true;
		}

		public byte SatelliteId { get; }
		public ushort BeamId { get; }
		public byte NccId { get; }
		public ForwardLinkUsageCodes LinkUsage { get; }
		public int LocalLinkId { get; }
		public uint Frequency { get; }
		public ushort OrbitalPosition { get; }
		public bool East { get; }
		public ForwardLinkPolarization Polarization { get; }
		public TransmissionStandardEnum TransmissionStandard { get; }
		public bool? ScramblingSequenceSelector { get; }
		public double? RollOff { get; }
		public uint SymbolRate { get; }
		public InnerFecScheme? FecInner { get; }
		public byte? InputStreamIndentifier { get; }
		public int? SpreadingCodeSelector { get; }
		public int ScramblingSequenceIndex { get; }
		public byte[] PrivateDataBytes { get; }

		public enum ForwardLinkUsageCodes
		{
			Combined = 0,
			Signalling = 1,
			Data = 2,
			Release = 3
		}

		public enum ForwardLinkPolarization
		{
			Horizontal = 0,
			Vertical = 1,
			Left = 2,
			Right = 3
		}

		public enum TransmissionStandardEnum
		{
			DVBS = 0,
			DVBS2_CCM = 1,
			DVBS2_ACM = 2
		}

		public enum InnerFecScheme
		{
			AHalf = 0,
			TwoThirds = 1,
			ThreeQuarters = 2,
			FiveSixths = 3,
			SevenEights = 4,
			Omitted = 5
		}

		public override string ToString()
		{
			return String.Format("Forward Link: {0} kHz,{1}, {2} sym/s", Frequency, Polarization.ToString()[0], SymbolRate);
		}

		protected bool Equals(_0xa8_SatelliteForwardLinkDescriptor other)
		{
			return SatelliteId == other.SatelliteId && BeamId == other.BeamId && Frequency == other.Frequency && OrbitalPosition == other.OrbitalPosition && East == other.East && Polarization == other.Polarization && SymbolRate == other.SymbolRate;
		}

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

		public override int GetHashCode()
		{
			return HashCode.Combine(SatelliteId, BeamId, Frequency, OrbitalPosition, East, (int)Polarization, SymbolRate);
		}
	}
}
