using skyscraper5.Mpeg2;
using skyscraper5.Mpeg2.Descriptors;
using skyscraper5.Skyscraper.IO;
using skyscraper5.src.InteractionChannel.Model;
using skyscraper5.src.InteractionChannel.Model2;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper8.InteractionChannel.Model2;

namespace skyscraper5.src.InteractionChannel
{
	internal class InteractionChannelPsiGatherer : IPsiProcessor
	{
		private UserDefinedDescriptor _expectedTable;
		public UserDefinedDescriptor ExpectedTables
		{
			get => _expectedTable;
			set
			{
				if (value.DescriptorTag != 0xa7)
				{
					throw new ArgumentException(String.Format("Expected a {0} descriptor.", 0xa7));
				}
				_expectedTable = value;
			}
		}

		private InteractionChannelHandler _handler;
		public InteractionChannelHandler Handler
		{
			get => _handler;
			set => _handler = value;
		}

		public ushort? NetworkId { get; private set; }


		//Maybe also check ETSI EN 301 545-2 V1.4.0 (2023-10) ?

		//en_301790v010501p_RCS_Map.pdf
		//page 78
		public void GatherPsi(PsiSection section, int sourcePid)
		{
			if (_handler == null)
			{
				throw new NoInteractionChannelHandlerException();
			}
			byte[] buffer = section.GetDataCopy();
			if (_expectedTable != null)
			{
				if (!_expectedTable.Data.Contains(buffer[0]))
				{
					_handler.OnInteractionChannelError(InteractionChannelErrorState.UnexpectedTable);
					return;
				}
			}
			MemoryStream ms = new MemoryStream(buffer, false);
			switch (buffer[0])
			{
				case 0x40:  //NIT
					InteractionChannelSiSectionHeader nitHeader = new InteractionChannelSiSectionHeader(ms);
					if (!nitHeader.Valid)
					{
						_handler.OnInteractionChannelError(InteractionChannelErrorState.HeaderInvalid);
						return;
					}
					throw new NotImplementedException("NIT");
				case 0x41:  //RMT
					Rmt rmt = new Rmt(ms);
					if (!rmt.Valid)
					{
						_handler.OnInteractionChannelError(InteractionChannelErrorState.RmtInvalid);
						return;
					}
					_handler.OnRcsMap(rmt);
					return;
				case 0x4D:  //SAT
					throw new NotImplementedException("SAT");
				case 0x70:  //TDT
					throw new NotImplementedException("TDT");
				case 0xA0:  //SCT
					InteractionChannelSiSectionHeader sctHeader = new InteractionChannelSiSectionHeader(ms);
					if (!sctHeader.Valid)
					{
						_handler.OnInteractionChannelError(InteractionChannelErrorState.HeaderInvalid);
						return;
					}
					NetworkId = sctHeader.InteractiveNetworkId;
					Sct sct = new Sct(ms);
					if (!sct.Valid)
					{
						_handler.OnInteractionChannelError(InteractionChannelErrorState.SctInvalid);
						return;
					}
					Handler.OnSuperframeComposition(sctHeader.InteractiveNetworkId, sct);
					return;
				case 0xA1:  //FCT
					InteractionChannelSiSectionHeader fctHeader = new InteractionChannelSiSectionHeader(ms);
					if (!fctHeader.Valid)
					{
						_handler.OnInteractionChannelError(InteractionChannelErrorState.HeaderInvalid);
						return;
					}
					NetworkId = fctHeader.InteractiveNetworkId;
					Fct fct = new Fct(ms);
					if (!fct.Valid)
					{
						_handler.OnInteractionChannelError(InteractionChannelErrorState.FctInvalid);
						return;
					}
					Handler.OnFrameComposition(fctHeader.InteractiveNetworkId, fct);
					return;
				case 0xA2:  //TCT
					InteractionChannelSiSectionHeader tctHeader = new InteractionChannelSiSectionHeader(ms);
					if (!tctHeader.Valid)
					{
						_handler.OnInteractionChannelError(InteractionChannelErrorState.HeaderInvalid);
						return;
					}
					NetworkId = tctHeader.InteractiveNetworkId;
					Tct tct = new Tct(ms);
					if (!tct.Valid)
					{
						_handler.OnInteractionChannelError(InteractionChannelErrorState.TctInvalid);
						return;
					}
					Handler.OnTimeslotComposition(tctHeader.InteractiveNetworkId, tct);
					return;
				case 0xA3:  //SPT
					InteractionChannelSiSectionHeader sptHeader = new InteractionChannelSiSectionHeader(ms);
					if (!sptHeader.Valid)
					{
						_handler.OnInteractionChannelError (InteractionChannelErrorState.HeaderInvalid);
						return;
					}
					NetworkId = sptHeader.InteractiveNetworkId;
					Spt spt = new Spt(ms);
					if (!spt.Valid)
					{
						_handler.OnInteractionChannelError(InteractionChannelErrorState.SptInvalid);
						return;
					}
					Handler.OnSatellitePosition(sptHeader.InteractiveNetworkId, spt);
					return;
				case 0xA4:  //CMT
					InteractionChannelSiSectionHeader cmtHeader = new InteractionChannelSiSectionHeader(ms);
					if (!cmtHeader.Valid)
					{
						_handler.OnInteractionChannelError(InteractionChannelErrorState.HeaderInvalid);
						return;
					}
					NetworkId = cmtHeader.InteractiveNetworkId;
					Cmt cmt = new Cmt(ms);
					if (!cmt.Valid)
					{
						_handler.OnInteractionChannelError(InteractionChannelErrorState.CmtInvalid);
						return;
					}
					Handler.OnCorrectionMessage(cmtHeader.InteractiveNetworkId, cmt);
					return;
				case 0xA5:  //TBTP
					InteractionChannelSiSectionHeader tbtpHeader = new InteractionChannelSiSectionHeader(ms);
					if (!tbtpHeader.Valid)
					{
						_handler.OnInteractionChannelError(InteractionChannelErrorState.HeaderInvalid);
						return;
					}
					NetworkId = tbtpHeader.InteractiveNetworkId;
					Tbtp tbtp = new Tbtp(ms);
					if (!tbtp.Valid)
					{
						_handler.OnInteractionChannelError(InteractionChannelErrorState.TbtpInvalid);
						return;
					}
					Handler.OnTerminalBurstTimePlan(tbtpHeader.InteractiveNetworkId, tbtp);
					return;
				case 0xA6:  //PCR packet payload
					throw new NotImplementedException("PCR packet payload");
				case 0xAA:  //Transmission Mode Support Table
					InteractionChannelSiSectionHeader tmstHeader = new InteractionChannelSiSectionHeader(ms);
					if (!tmstHeader.Valid)
					{
						_handler.OnInteractionChannelError(InteractionChannelErrorState.HeaderInvalid);
						return;
					}
					NetworkId = tmstHeader.InteractiveNetworkId;
					Tmst tmst = new Tmst(ms);
					if (!tmst.Valid)
					{
						_handler.OnInteractionChannelError(InteractionChannelErrorState.TmstInvalid);
						return;
					}
					Handler.OnTransmissionModeSupport(tmstHeader.InteractiveNetworkId, tmst);
					return;
				case 0xAB:  //FCT2
					InteractionChannelSiSectionHeader fct2Header = new InteractionChannelSiSectionHeader(ms);
					if (!fct2Header.Valid)
					{
						_handler.OnInteractionChannelError(InteractionChannelErrorState.HeaderInvalid);
						return;
					}
					NetworkId = fct2Header.InteractiveNetworkId;
					Fct2 fct2 = new Fct2(ms);
					if (!fct2.Valid)
					{
						_handler.OnInteractionChannelError(InteractionChannelErrorState.Fct2Invalid);
						return;
					}

					Handler.OnFrameComposition2(NetworkId.Value, fct2);
					return;
				case 0xAC:  //BCT
					InteractionChannelSiSectionHeader bctHeader = new InteractionChannelSiSectionHeader(ms);
					if (!bctHeader.Valid)
					{
						_handler.OnInteractionChannelError(InteractionChannelErrorState.HeaderInvalid);
						return;
					}
					NetworkId = bctHeader.InteractiveNetworkId;
					Bct bct = new Bct(ms);
					if (!bct.Valid)
					{
						_handler.OnInteractionChannelError(InteractionChannelErrorState.BctInvalid);
						return;
					}
					Handler.OnBroadcastConfiguration(NetworkId.Value, bct);
					return;
				case 0xAD:  //TBTP2
					InteractionChannelSiSectionHeader tbtp2Header = new InteractionChannelSiSectionHeader(ms);
					if (!tbtp2Header.Valid)
					{
						_handler.OnInteractionChannelError(InteractionChannelErrorState.HeaderInvalid);
						return;
					}
					NetworkId = tbtp2Header.InteractiveNetworkId;
					Tbtp2 tbtp2 = new Tbtp2(ms);
					if (!tbtp2.Valid)
					{
						_handler.OnInteractionChannelError(InteractionChannelErrorState.Tbtp2Invalid);
						return;
					}

					_handler.OnTerminalBurstTimePlan2(tbtp2Header.InteractiveNetworkId, tbtp2);
					break;
				case 0xAE:  //TMST2
					InteractionChannelSiSectionHeader tmst2Header = new InteractionChannelSiSectionHeader(ms);
					if (!tmst2Header.Valid)
					{
						_handler.OnInteractionChannelError(InteractionChannelErrorState.HeaderInvalid);
						return;
					}
					NetworkId = tmst2Header.InteractiveNetworkId;
					int transmissionStandard = _handler.GetRmtTransmissionStandard(NetworkId.Value);
					Tmst2 tmst2 = new Tmst2(ms,transmissionStandard);
					if (!tmst2.Valid)
					{
						_handler.OnInteractionChannelError(InteractionChannelErrorState.Tmst2Invalid);
						return;
					}
					if (tmst2.TransmissionModes.Length == 0)
						return;
					throw new NotImplementedException("TMST2");
				case 0xAF:  //FAT
							//see en_30154502v010401p.pdf, page 49
					throw new NotImplementedException("TMST2");
				case 0xB0:  //TIM
					InteractionChannelDsmCcPrivateSectionHeader timHeader = new InteractionChannelDsmCcPrivateSectionHeader(ms);
					if (!timHeader.Valid)
					{
						_handler.OnInteractionChannelError(InteractionChannelErrorState.HeaderInvalid);
						return;
					}
					Tim tim = new Tim(ms, timHeader.IsBroadcast);
					if (!tim.Valid)
					{
						_handler.OnInteractionChannelError(InteractionChannelErrorState.TimInvalid);
						return;
					}

					_handler.OnTerminalInformationMessage(NetworkId, timHeader.MacAddress, tim);
					return;
				case 0xB1:  //LL_FEC_parity_data_table
					throw new NotImplementedException("LL_FEC_parity_data_table");
				case 0xB2:  //MMT2
							//see en_30154502v010401p.pdf, page 49
					throw new NotImplementedException("MMT2");
				default:
					if (buffer[0] == 0xa7 || buffer[0] == 0xa8 || buffer[0] == 0xa9)
					{
						//reserved
						break;
					}
					if (buffer[0] >= 0xb2 || buffer[0] <= 0xbf)
					{
						//reserved for future use
						break;
					}
					if (buffer[0] >= 0xc0 || buffer[0] <= 0xfe)
					{
						//user defined
						break;
					}
					throw new NotImplementedException(String.Format("ETSI EN 301 790 V1.5.1 0x{0:X2}", buffer[0]));
			}
		}
	}
}
