using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.Plugins;
using skyscraper5.Skyscraper.Scraper;
using skyscraper5.Skyscraper.Scraper.StreamAutodetection;
using skyscraper5.src.InteractionChannel;
using skyscraper5.src.InteractionChannel.Model;
using skyscraper5.src.InteractionChannel.Model.Descriptors;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.src.InteractionChannel.Model2;
using skyscraper8.InteractionChannel.Model;
using skyscraper8.InteractionChannel.Model2;
using skyscraper8.InteractionChannel.Model2.Descriptors;

namespace skyscraper5.src.Skyscraper.Scraper.StreamAutodetection.Contestants
{
	[SkyscraperPlugin]
    internal class InteractionChannelContestant : Contestant, InteractionChannelHandler, IDisposable
	{
		public InteractionChannelContestant(int pid)
			: base("Interaction channel for satellite distribution systems",pid)
		{
			InteractionChannelPsiGatherer interactionChannelPsiGatherer = new InteractionChannelPsiGatherer();
			interactionChannelPsiGatherer.Handler = this;
			PacketProcessor = new PsiDecoder(pid, interactionChannelPsiGatherer);
		}

		public override void DeclareWinner(SkyscraperContext skyscraperContext, int pid, ProgramContext programContext)
		{
			InteractionChannelPsiGatherer icPsi = new InteractionChannelPsiGatherer();
			icPsi.Handler = skyscraperContext;
			skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid, icPsi));
		}

		public override void Introduce(ProgramContext programContext)
		{
			
		}

		public override void Dispose()
		{

		}

		public int GetRmtTransmissionStandard(ushort networkId)
		{
			throw new NotImplementedException();
		}

		public void OnCorrectionMessage(ushort interactiveNetworkId, Cmt cmt)
		{
			if (cmt.Entries.Length > 0)
			{
				Score++;
			}
		}

		public void OnFrameComposition(ushort interactiveNetworkId, Fct fct)
		{
			if (fct.Frames.Length > 0)
			{
				Score++;
			}
		}

		public void OnInteractionChannelError(InteractionChannelErrorState unexpectedTable)
		{
			Score--;
		}

		public void OnRcsMap(Rmt rmt)
		{
			if (rmt.Linkages != null)
			{
				if (rmt.Linkages.Count > 0)
				{
					Score++;
					return;
				}
			}
			if (rmt.TransportStreams != null)
			{
				if (rmt.TransportStreams.Count > 0)
				{
					Score++;
				}
			}
		}

		public void OnSatellitePosition(ushort interactiveNetworkId, Spt spt)
		{
			if (spt.Satellites.Length > 0)
			{
				Score++;
			}
		}

		public void OnSuperframeComposition(ushort interactiveNetworkId, Sct sct)
		{
			if (sct.Superframes.Length > 0)
			{
				Score++;
			}
		}

		public void OnTerminalBurstTimePlan(ushort interactiveNetworkId, Tbtp tbtp)
		{
			if (tbtp.Frames.Length > 0)
			{
				Score++;
			}
		}

		public void OnTimeslotComposition(ushort interactiveNetworkId, Tct tct)
		{
			if (tct.Timeslots.Length > 0)
			{
				Score++;
			}
		}

		private Dictionary<ushort, int> knownTmsts;
		public void OnTransmissionModeSupport(ushort interactiveNetworkId, Tmst tmst)
		{
			if (!tmst.Valid)
			{
				Score--;
				return;
			}

			if (tmst.Modes.Length > 0)
			{
				if (knownTmsts == null)
					knownTmsts = new Dictionary<ushort, int>();

				if (knownTmsts.ContainsKey(interactiveNetworkId))
				{
					if (knownTmsts[interactiveNetworkId] == tmst.Modes.Length)
					{
						Score++;
					}
					else
					{
						knownTmsts[interactiveNetworkId] = tmst.Modes.Length;
					}
				}
				else
				{
					knownTmsts[interactiveNetworkId] = tmst.Modes.Length;
				}
			}
		}

        public void OnTerminalBurstTimePlan2(ushort interactiveNetworkId, Tbtp2 tbtp2)
        {
	        if (tbtp2.Frames.Length > 0)
	        {
		        Score++;
	        }
        }

        public void OnFrameComposition2(ushort networkId, Fct2 fct2)
        {
	        if (fct2.FrameTypes.Length > 0)
	        {
		        Score++;
	        }
        }

        public void OnBroadcastConfiguration(ushort networkId, Bct bct)
        {
	        if (bct.TxTypes.Length > 0)
	        {
		        Score++;
	        }
        }

        public void OnRcs2Nit(ushort interactiveNetworkId, RcsNit nit)
        {
			//TODO: put validation logic in here, important!
        }

        public void OnRcs2Tdt(ushort interactiveNetworkId, Rcs2Tdt tdt)
        {
			//TODO: put validation logic in here, important!
		}

        public void OnTransmissionModeSupport2(ushort interactiveNetworkId, Tmst2 tmst2)
        {
	        if (tmst2.TransmissionModes.Length > 0)
	        {
		        Score++;
	        }
        }

        public void OnFrameComposition2(ushort? networkId, Fct2 fct2)
        {
	        if (fct2.FrameTypes.Length > 0)
	        {
		        Score++;
	        }
        }

		public void OnTerminalInformationMessage(ushort? interactiveNetworkId, PhysicalAddress physicalAddress, Tim tim)
		{
			foreach(TsDescriptor tsDescriptor in tim.Descriptors)
			{
				bool valid = false;
				try
				{
					valid = tsDescriptor.Valid;
				}
				catch (InvalidOperationException ioe)
				{
					continue;
				}
				if (!valid)
				{
					Score--;
				}
			}
			if (tim.Descriptors.Length > 0)
			{
				Score++;
			}
		}
	}
}
