using skyscraper5.Docsis.MacManagement;
using skyscraper5.DsmCc.Descriptors;
using skyscraper5.Dvb.DataBroadcasting.IntModel;
using skyscraper5.Dvb.DataBroadcasting.SkyscraperVfs;
using skyscraper5.Dvb.Descriptors;
using skyscraper5.Dvb.Psi.Model;
using skyscraper5.Dvb.SystemSoftwareUpdate.Model;
using skyscraper5.Dvb.TvAnytime;
using skyscraper5.Mhp.Si;
using skyscraper5.Mhp.Si.Model;
using skyscraper5.Mpeg2.Descriptors;
using skyscraper5.Mpeg2.Psi.Model;
using skyscraper5.Rds.Messages;
using skyscraper5.Scte35;
using skyscraper5.Skyscraper.Gps;
using skyscraper5.Skyscraper.Headless;
using skyscraper5.Skyscraper.IO;
using skyscraper5.Skyscraper.IO.CrazycatStreamReader;
using skyscraper5.Skyscraper.Scraper.Storage.InMemory.Model;
using skyscraper5.Skyscraper.Scraper.Storage.Utilities;
using skyscraper5.src.InteractionChannel.Model;
using skyscraper5.src.InteractionChannel.Model.Descriptors;
using skyscraper5.src.Skyscraper.FrequencyListGenerator;
using skyscraper5.src.Skyscraper.Scraper.Dns;
using skyscraper5.src.Skyscraper.Scraper.Storage.InMemory;
using skyscraper5.Teletext;
using skyscraper8.DvbI;
using skyscraper8.DvbNip;
using skyscraper8.Ses;
using skyscraper8.Ses.Descriptors;
using skyscraper8.Skyscraper.Scraper.Storage.InMemory.Model;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using skyscraper5.src.InteractionChannel.Model2;
using skyscraper8.Ietf.FLUTE;
using skyscraper8.InteractionChannel.Model;
using skyscraper8.InteractionChannel.Model2;
using skyscraper8.InteractionChannel.Model2.Descriptors;
using skyscraper8.Skyscraper.Scraper.Storage;
using skyscraper8.Skyscraper.Scraper.Storage.Utilities;
using Platform = skyscraper5.Dvb.SystemSoftwareUpdate.Model.Platform;

namespace skyscraper5.Skyscraper.Scraper.Storage.InMemory
{
	internal class InMemoryScraperStorage : DataStorage
	{
		public InMemoryScraperStorage()
		{
			nitNetworks = new NitNetwork[ushort.MaxValue + 1];
			nitTransportStreams = new NitTransportStream[ushort.MaxValue + 1][];
			patEntries = new HashSet<InMemoryPatEntry>();
			pmtEntries = new ProgramMapping[ushort.MaxValue + 1][][];
			teletextPageCache = new Dictionary<TeletextCoordinate, HashSet<TeletextMagazine>>();
			sdtServices = new SdtService[ushort.MaxValue + 1][][];
			batBouquets = new BatBouquet[ushort.MaxValue];
			batTransportStreams = new BatTransportStream[ushort.MaxValue + 1][];
			timeOffsets = new Tuple<DateTime, LocalTimeOffsetDescriptor>[ushort.MaxValue + 1][];
			tdtTimes = new DateTime[ushort.MaxValue + 1][];
			eitEvents = new HashSet<EitEvent>();
			doItNowEvents = new List<InMemoryDoItNowEvent>();
			caSystems = new List<InMemoryCaSystem>();
			updateHashes = new HashSet<int>();
			updates = new List<Tuple<int, Compatibility, Platform>>();
			rdsTexts = new HashSet<InMemoryRdsText>();
			ptyCodes = new PTY.ProgrammeTypeCodes[ushort.MaxValue][][];
			scte35SpliceCoordinates = new HashSet<Scte35SpliceCoordinate>();
			compliances = new HashSet<ComplianceCoordiante>();
			stationIdentification = new string[ushort.MaxValue + 1][];
			aitApplicationCoordinates = new HashSet<AitApplicationCoordinate>();
			rstCoordinates = new HashSet<RstCoordinates>();
			ipMacNotificationCoordinates = new List<IpMacNotification>();
			pluginToken = new InMemoryPluginToken();
		}

		private NitNetwork[] nitNetworks;
		private NitTransportStream[][] nitTransportStreams;
		private HashSet<InMemoryPatEntry> patEntries;
		private ProgramMapping[][][] pmtEntries;
		private Dictionary<TeletextCoordinate, HashSet<TeletextMagazine>> teletextPageCache;
		private SdtService[][][] sdtServices;
		private BatBouquet[] batBouquets;
		private BatTransportStream[][] batTransportStreams;
		private Tuple<DateTime, LocalTimeOffsetDescriptor>[][] timeOffsets;
		private DateTime[][] tdtTimes;
		private HashSet<EitEvent> eitEvents;
		private List<InMemoryDoItNowEvent> doItNowEvents;
		private List<InMemoryCaSystem> caSystems;
		private HashSet<int> updateHashes;
		private List<Tuple<int, Compatibility, Platform>> updates;
		private bool[][][] rdsDataPresent;
		private string[][][] rdsProgrammeService;
		private HashSet<InMemoryRdsText> rdsTexts;
		private PTY.ProgrammeTypeCodes[][][] ptyCodes;
		private bool[][][] rdsTrafficInformationPreset;
		private HashSet<Scte35SpliceCoordinate> scte35SpliceCoordinates;
		private HashSet<ComplianceCoordiante> compliances;
		private string[][] stationIdentification;
		private HashSet<AitApplicationCoordinate> aitApplicationCoordinates;
		private HashSet<RstCoordinates> rstCoordinates;
		private List<IpMacNotification> ipMacNotificationCoordinates;
		private DateTime[][][] t2MiTimestamps;
		private InMemoryPluginToken pluginToken;

		public bool TestForNitNetwork(NitNetwork nitNetwork)
		{
			return nitNetworks[nitNetwork.NetworkId] != null;
		}

		public void StoreNitNetwork(NitNetwork nitNetwork)
		{
			nitNetworks[nitNetwork.NetworkId] = nitNetwork;
		}

		public bool UpdateNitNetwork(NitNetwork l)
		{
			bool result = false;
			NitNetwork r = nitNetworks[l.NetworkId];
			if (r == null)
			{
				StoreNitNetwork(l);
				return true;
			}

			if (string.IsNullOrEmpty(r.Name) && !string.IsNullOrEmpty(l.Name))
			{
				r.Name = l.Name;
				result = true;
			}

			foreach (LinkageDescriptor lLinkage in l.Linkages)
			{
				if (!r.Linkages.Contains(lLinkage))
				{
					r.Linkages.Add(lLinkage);
					result = true;
				}
			}

			if (!r.PrivateDataSpecifierId.HasValue && l.PrivateDataSpecifierId.HasValue)
			{
				r.PrivateDataSpecifierId = l.PrivateDataSpecifierId;
				result = true;
			}

			return result;
		}

		public bool TestForNitTransportStream(ushort networkId, NitTransportStream transportStream)
		{
			if (nitTransportStreams[transportStream.OriginalNetworkId] == null)
				return false;

			return nitTransportStreams[transportStream.OriginalNetworkId][transportStream.TransportStreamId] != null;
		}

		public void StoreNitTransportStream(ushort networkId, NitTransportStream transportStream)
		{
			if (nitTransportStreams[transportStream.OriginalNetworkId] == null)
				nitTransportStreams[transportStream.OriginalNetworkId] = new NitTransportStream[ushort.MaxValue];

			nitTransportStreams[transportStream.OriginalNetworkId][transportStream.TransportStreamId] = transportStream;
		}

		public bool UpdateNitTransportStream(ushort nid, NitTransportStream l)
		{
			NitTransportStream r = nitTransportStreams[l.OriginalNetworkId][l.TransportStreamId];

			if (!r.Frequency.HasValue && l.Frequency.HasValue)
			{
				r.RollOff = l.RollOff;
				r.S2 = l.S2;
				r.Frequency = l.Frequency;
				r.Polarization = l.Polarization;
				r.SymbolRate = l.SymbolRate;
				r.East = l.East;
				r.FecInner = l.FecInner;
				r.ModulationType = l.ModulationType;
				r.OrbitalPosition = l.OrbitalPosition;
				return true;
			}

			return false;
		}

		public bool StorePatEntry(int currentNetworkId, int currentTransportStreamId, int pmtPid, ushort programId)
		{
			InMemoryPatEntry inMemoryPatEntry =
				new InMemoryPatEntry(currentNetworkId, currentTransportStreamId, pmtPid, programId);
			return patEntries.Add(inMemoryPatEntry);
		}

		public bool TestForPmtEvent(int currentNetworkId, int currentTransportStreamId, ProgramMapping result)
		{
			if (pmtEntries[currentNetworkId] == null)
				return false;

			if (pmtEntries[currentNetworkId][currentTransportStreamId] == null)
				return false;

			return pmtEntries[currentNetworkId][currentTransportStreamId][result.ProgramNumber] != null;
		}

		public bool StorePmtEvent(int currentNetworkId, int currentTransportStreamId, ProgramMapping mapping)
		{
			if (pmtEntries[currentNetworkId] == null)
				pmtEntries[currentNetworkId] = new ProgramMapping[ushort.MaxValue][];

			if (pmtEntries[currentNetworkId][currentTransportStreamId] == null)
				pmtEntries[currentNetworkId][currentTransportStreamId] = new ProgramMapping[ushort.MaxValue];

			bool result = pmtEntries[currentNetworkId][currentTransportStreamId][mapping.ProgramNumber] == null;
			pmtEntries[currentNetworkId][currentTransportStreamId][mapping.ProgramNumber] = mapping;
			return result;
		}

		public bool StoreTeletextPage(int networkId, int transportStreamId, ushort programNumber,
			TeletextMagazine magazine, DateTime timestamp)
		{
			return false;
		}

		public bool TestForSdtService(ushort transportStreamId, ushort originalNetworkId, SdtService sdtService)
		{
			if (sdtServices[transportStreamId] == null)
				return false;

			if (sdtServices[transportStreamId][originalNetworkId] == null)
				return false;

			return sdtServices[transportStreamId][originalNetworkId][sdtService.ServiceId] != null;
		}

		public bool TestForTeletextPage(int networkId, int transportStreamId, ushort programNumber,
			TeletextMagazine magazine, DateTime timestamp)
		{
			//No need to keep teletext pages in memory
			return true;
		}

		public void MarkTeletextPageAsKnown(int networkId, int transportStreamId, ushort programNumber,
			TeletextMagazine magazine, DateTime timestamp)
		{
			//No need to keep teletext pages in memory
		}

		public bool UpdateSdtService(ushort transportStreamId, ushort originalNetworkId, SdtService l)
		{
			bool result = false;
			SdtService r = sdtServices[transportStreamId][originalNetworkId][l.ServiceId];
			if (!string.IsNullOrEmpty(l.ServiceName) && string.IsNullOrEmpty(r.ServiceName))
			{
				r.ServiceName = l.ServiceName;
				r.ServiceProviderName = l.ServiceProviderName;
				r.ServiceType = l.ServiceType;
				result = true;
			}

			if (l.PrivateDataSpecifier.HasValue && !r.PrivateDataSpecifier.HasValue)
			{
				r.PrivateDataSpecifier = l.PrivateDataSpecifier;
				result = true;
			}

			return false;
		}

		public void StoreSdtService(ushort transportStreamId, ushort originalNetworkId, SdtService sdtService)
		{
			if (sdtServices[transportStreamId] == null)
				sdtServices[transportStreamId] = new SdtService[ushort.MaxValue + 1][];

			if (sdtServices[transportStreamId][originalNetworkId] == null)
				sdtServices[transportStreamId][originalNetworkId] = new SdtService[ushort.MaxValue + 1];

			sdtServices[transportStreamId][originalNetworkId][sdtService.ServiceId] = sdtService;
		}

		public bool TestForBatBouquet(BatBouquet batBouquet)
		{
			return batBouquets[batBouquet.BouquetId] != null;
		}

		public bool UpdateBatBouquet(BatBouquet l)
		{
			bool result = false;
			BatBouquet r = batBouquets[l.BouquetId];
			if (!string.IsNullOrEmpty(l.BouquetName) && string.IsNullOrEmpty(r.BouquetName))
			{
				r.BouquetName = l.BouquetName;
				result = true;
			}

			foreach (LinkageDescriptor linkageDescriptor in l.Linkages)
			{
				if (!r.Linkages.Contains(linkageDescriptor))
				{
					r.Linkages.Add(linkageDescriptor);
					result = true;
				}
			}

			foreach (KeyValuePair<string, bool> country in l.CountryAvailabilityDictionary)
			{
				if (r.CountryAvailabilityDictionary.ContainsKey(country.Key))
				{
					if (country.Value != r.CountryAvailabilityDictionary[country.Key])
					{
						r.CountryAvailabilityDictionary[country.Key] = country.Value;
						result = true;
						continue;
					}
				}
				else
				{
					r.CountryAvailabilityDictionary[country.Key] = country.Value;
					result = true;
				}
			}

			return result;
		}

		public void StoreBatBouquet(BatBouquet batBouquet)
		{
			batBouquets[batBouquet.BouquetId] = batBouquet;
		}

		public bool TestForBatTransportStream(ushort batBouquetBouquetId, BatTransportStream child)
		{
			if (batTransportStreams[batBouquetBouquetId] == null)
				return false;

			return batTransportStreams[batBouquetBouquetId][child.TransportStreamId] != null;
		}

		public bool UpdateBatTransportStream(ushort batBouquetBouquetId, BatTransportStream l)
		{
			if (l.ServiceList == null)
				return false;

			bool result = false;
			BatTransportStream r = batTransportStreams[batBouquetBouquetId][l.TransportStreamId];
			foreach (ServiceListDescriptor.Service service in l.ServiceList)
			{
				if (r.ServiceList == null)
					r.ServiceList = new List<ServiceListDescriptor.Service>();
				if (!r.ServiceList.Contains(service))
				{
					r.ServiceList.Add(service);
					result = true;
				}
			}

			return result;
		}

		public void StoreBatTransportStream(ushort batBouquetBouquetId, BatTransportStream child)
		{
			if (batTransportStreams[batBouquetBouquetId] == null)
				batTransportStreams[batBouquetBouquetId] = new BatTransportStream[ushort.MaxValue];

			batTransportStreams[batBouquetBouquetId][child.TransportStreamId] = child;
		}

		public bool UpdateTimeOffsetTable(int currentNetworkId, int currentTransportStreamId, DateTime newTime,
			LocalTimeOffsetDescriptor ltod)
		{
			if (timeOffsets[currentNetworkId] == null)
				timeOffsets[currentNetworkId] = new Tuple<DateTime, LocalTimeOffsetDescriptor>[ushort.MaxValue];

			if (timeOffsets[currentNetworkId][currentTransportStreamId] != null)
			{
				DateTime oldTime = timeOffsets[currentNetworkId][currentTransportStreamId].Item1;
				if ((newTime - oldTime).TotalSeconds < 10)
					return false;
			}

			timeOffsets[currentNetworkId][currentTransportStreamId] =
				new Tuple<DateTime, LocalTimeOffsetDescriptor>(newTime, ltod);
			return true;
		}

		public bool UpdateTimeAndDate(int currentNetworkId, int currentTransportStreamId, DateTime newTime)
		{
			if (tdtTimes[currentNetworkId] == null)
				tdtTimes[currentNetworkId] = new DateTime[ushort.MaxValue];

			if (tdtTimes[currentNetworkId][currentTransportStreamId] != DateTime.MinValue)
			{
				DateTime oldTime = tdtTimes[currentNetworkId][currentTransportStreamId];
				if ((newTime - oldTime).TotalSeconds < 10)
					return false;
			}

			tdtTimes[currentNetworkId][currentTransportStreamId] = newTime;
			return true;
		}

		public bool StoreEitEvent(EitEvent eitEvent)
		{
			return eitEvents.Add(eitEvent);
		}

		public bool TestForAitApplication(ApplicationIdentifier aitApplicationApplicationIdentifier)
		{
			AitApplicationCoordinate aitCoordinate = new AitApplicationCoordinate(
				aitApplicationApplicationIdentifier.OrganisationId, aitApplicationApplicationIdentifier.ApplicationId);
			return aitApplicationCoordinates.Contains(aitCoordinate);
		}

		public void StoreAitApplication(AitApplication aitApplication)
		{
			AitApplicationCoordinate aitApplicationCoordinate = new AitApplicationCoordinate(
				aitApplication.ApplicationIdentifier.OrganisationId,
				aitApplication.ApplicationIdentifier.ApplicationId);

			aitApplicationCoordinate.PointingTo = aitApplication;
			aitApplicationCoordinates.Add(aitApplicationCoordinate);
		}

		public bool TestForCaSystem(int currentNetworkId, int currentTransportStreamId, int caDescriptorCaPid)
		{
			InMemoryCaSystem find = caSystems.Find(x =>
				x.CurrentNetworkId == currentNetworkId && x.CurrentTransportStreamId == currentTransportStreamId &&
				x.CaPid == caDescriptorCaPid);
			return find != null;
		}

		public void StoreCaSystem(int currentNetworkId, int currentTransportStreamId, CaDescriptor caDescriptor)
		{
			InMemoryCaSystem caSystem = new InMemoryCaSystem(currentNetworkId, currentTransportStreamId, caDescriptor);
			caSystems.Add(caSystem);
		}

		public bool TestForUpdateNotification(int hashCode, UpdateNotificationGroup common)
		{
			return updateHashes.Contains(hashCode);
		}

		public void StoreUpdateNotification(int hashCode, UpdateNotificationGroup common, Compatibility compatibility,
			Platform platform)
		{
			updateHashes.Add(hashCode);
			updates.Add(new Tuple<int, Compatibility, Platform>(hashCode, compatibility, platform));
		}
		
		public bool TestForKnownRdsData(int currentNetworkId, int currentTransportStreamId, int programNumber)
		{
			if (rdsDataPresent == null)
				return false;

			if (rdsDataPresent[currentNetworkId] == null)
				return false;

			if (rdsDataPresent[currentNetworkId][currentTransportStreamId] == null)
				return false;

			return rdsDataPresent[currentNetworkId][currentTransportStreamId][programNumber];
		}

		public void EnableRdsCollection(int currentNetworkId, int currentTransportStreamId, int programNumber)
		{
			if (rdsDataPresent == null)
				rdsDataPresent = new bool[ushort.MaxValue][][];

			if (rdsDataPresent[currentNetworkId] == null)
				rdsDataPresent[currentNetworkId] = new bool[ushort.MaxValue][];

			if (rdsDataPresent[currentNetworkId][currentTransportStreamId] == null)
				rdsDataPresent[currentNetworkId][currentTransportStreamId] = new bool[ushort.MaxValue];

			rdsDataPresent[currentNetworkId][currentTransportStreamId][programNumber] = true;
		}

		public bool UpdateRdsProgrammeServiceName(int currentNetworkId, int currentTransportStreamId, int programNumber,
			string programmeService2)
		{
			if (rdsProgrammeService == null)
				rdsProgrammeService = new string[ushort.MaxValue][][];

			if (rdsProgrammeService[currentNetworkId] == null)
				rdsProgrammeService[currentNetworkId] = new string[ushort.MaxValue][];

			if (rdsProgrammeService[currentNetworkId][currentTransportStreamId] == null)
				rdsProgrammeService[currentNetworkId][currentTransportStreamId] = new string[ushort.MaxValue];

			bool result = !string.Equals(programmeService2,
				rdsProgrammeService[currentNetworkId][currentTransportStreamId][programNumber]);
			rdsProgrammeService[currentNetworkId][currentTransportStreamId][programNumber] = programmeService2;
			return result;
		}

		public bool UpdateRdsRadioText(int currentNetworkId, int currentTransportStreamId, int programNumber,
			string text)
		{
			InMemoryRdsText child =
				new InMemoryRdsText(currentNetworkId, currentTransportStreamId, programNumber, text);
			bool add = rdsTexts.Add(child);
			return add;
		}

		public bool UpdateRdsPty(int currentNetworkId, int currentTransportStreamId, int programNumber,
			PTY.ProgrammeTypeCodes pty)
		{
			if (ptyCodes[currentNetworkId] == null)
				ptyCodes[currentNetworkId] = new PTY.ProgrammeTypeCodes[ushort.MaxValue][];

			if (ptyCodes[currentNetworkId][currentTransportStreamId] == null)
				ptyCodes[currentNetworkId][currentTransportStreamId] = new PTY.ProgrammeTypeCodes[ushort.MaxValue];

			if (ptyCodes[currentNetworkId][currentTransportStreamId][programNumber] != pty)
			{
				ptyCodes[currentNetworkId][currentTransportStreamId][programNumber] = pty;
				return true;
			}

			return false;
		}

		public bool MarkAsRdsTrafficInformationProgramme(int currentNetworkId, int currentTransportStreamId,
			int programNumber)
		{
			if (rdsTrafficInformationPreset == null)
				rdsTrafficInformationPreset = new bool[ushort.MaxValue][][];

			if (rdsTrafficInformationPreset[currentNetworkId] == null)
				rdsTrafficInformationPreset[currentNetworkId] = new bool[ushort.MaxValue][];

			if (rdsTrafficInformationPreset[currentNetworkId][currentTransportStreamId] == null)
				rdsTrafficInformationPreset[currentNetworkId][currentTransportStreamId] = new bool[ushort.MaxValue];

			if (!rdsTrafficInformationPreset[currentNetworkId][currentTransportStreamId][programNumber])
			{
				rdsTrafficInformationPreset[currentNetworkId][currentTransportStreamId][programNumber] = true;
				return true;
			}

			return false;
		}

		public bool TestForScte35SpliceInsert(int currentNetworkId, int currentTransportStreamId, ushort programNumber,
			SpliceInsert spliceInsert)
		{
			Scte35SpliceCoordinate scte35sc = new Scte35SpliceCoordinate(currentNetworkId, currentTransportStreamId,
				programNumber, spliceInsert.SpliceEventId);
			return scte35SpliceCoordinates.Contains(scte35sc);
		}

		public void StoreScte35SpliceInsert(int currentNetworkId, int currentTransportStreamId, ushort programNumber,
			SpliceInsert spliceInsert)
		{
			Scte35SpliceCoordinate scte35sc = new Scte35SpliceCoordinate(currentNetworkId, currentTransportStreamId,
				programNumber, spliceInsert.SpliceEventId);
			scte35SpliceCoordinates.Add(scte35sc);
		}

		public bool IsCompliant(int currentNetworkId, int currentTransportStreamId, string compliance)
		{
			ComplianceCoordiante cc = new ComplianceCoordiante(currentNetworkId, currentTransportStreamId, compliance);
			return compliances.Contains(cc);
		}

		public void MarkAsCompliant(int currentNetworkId, int currentTransportStreamId, string compliance)
		{
			ComplianceCoordiante cc = new ComplianceCoordiante(currentNetworkId, currentTransportStreamId, compliance);
			compliances.Add(cc);
		}

		public bool SetStationIdentification(int currentNetworkId, int currentTransportStreamId, string newSi)
		{
			if (stationIdentification[currentNetworkId] == null)
				stationIdentification[currentNetworkId] = new string[ushort.MaxValue];

			bool result = !newSi.Equals(stationIdentification[currentNetworkId][currentTransportStreamId]);
			stationIdentification[currentNetworkId][currentTransportStreamId] = newSi;
			return result;
		}
		
		public void StoreDsmCcDoItNowEvent(DateTime timestamp, int currentNetworkId, int currentTransportStreamId,
			int programNumber, StreamEventDescriptor descriptorListStreamEventDescriptor, int pid)
		{

		}

		public bool StoreRunningStatus(uint transportStreamId, uint originalNetworkId, uint serviceId, uint eventId,
			RunningStatus runningStatus, DateTime currentTime)
		{
			RstCoordinates rstCoordinates = new RstCoordinates(originalNetworkId, transportStreamId, serviceId, eventId,
				runningStatus, currentTime);
			return this.rstCoordinates.Add(rstCoordinates);
		}

		public void SetScte35TimeSignal(int currentNetworkId, int currentTransportStreamId, DateTime currentTime,
			ushort programNumber, TimeSignal timeSignal)
		{

		}
		

		private HashSet<DocsisUpstreamChannelCoordinate> _docsisUpstreamChannelCoordinates;

		public bool TestForDocsisUpstreamChannel(PhysicalAddress mmmSource, uint mmmFrequency, int locationId)
		{
			if (_docsisUpstreamChannelCoordinates == null)
				return false;

			DocsisUpstreamChannelCoordinate coord = new DocsisUpstreamChannelCoordinate(mmmSource, mmmFrequency);
			return _docsisUpstreamChannelCoordinates.Contains(coord);
		}

		public void StoreDocsisUpstreamChannel(UpstreamChannelDescriptor mmm, int locationId)
		{
			if (!mmm.Frequency.HasValue)
				return;

			if (_docsisUpstreamChannelCoordinates == null)
				_docsisUpstreamChannelCoordinates = new HashSet<DocsisUpstreamChannelCoordinate>();

			DocsisUpstreamChannelCoordinate
				coord = new DocsisUpstreamChannelCoordinate(mmm.Source, mmm.Frequency.Value);
			_docsisUpstreamChannelCoordinates.Add(coord);
		}

		private HashSet<DocsisUpstreamChannelCoordinate> _docsisDownstreamChannelCoordinates;

		public bool TestForDocsisDownstreamChannel(PhysicalAddress physicalAddress,
			MacDomainDescriptor.DownstreamActiveChannel downstreamActiveChannel, int locationId)
		{
			if (_docsisDownstreamChannelCoordinates == null)
				return false;

			DocsisUpstreamChannelCoordinate coord =
				new DocsisUpstreamChannelCoordinate(physicalAddress, downstreamActiveChannel.Frequency.Value);
			return _docsisDownstreamChannelCoordinates.Contains(coord);
		}

		public void StoreDocsisDownstreamChannel(PhysicalAddress physicalAddress,
			MacDomainDescriptor.DownstreamActiveChannel downstreamActiveChannel, int locationId)
		{
			if (_docsisDownstreamChannelCoordinates == null)
				_docsisDownstreamChannelCoordinates = new HashSet<DocsisUpstreamChannelCoordinate>();

			DocsisUpstreamChannelCoordinate coord =
				new DocsisUpstreamChannelCoordinate(physicalAddress, downstreamActiveChannel.Frequency.Value);
			_docsisDownstreamChannelCoordinates.Add(coord);
		}

		private Dictionary<PhysicalAddress, IPAddress> cmtsIpAddresses;

		public bool SetCmtsIp(PhysicalAddress arpHeaderSenderHardwareAddress, IPAddress arpHeaderSenderProtocolAddress)
		{
			if (cmtsIpAddresses == null)
				cmtsIpAddresses = new Dictionary<PhysicalAddress, IPAddress>();

			if (cmtsIpAddresses.ContainsKey(arpHeaderSenderHardwareAddress))
			{
				bool result = cmtsIpAddresses[arpHeaderSenderHardwareAddress].Equals(arpHeaderSenderProtocolAddress);
				cmtsIpAddresses[arpHeaderSenderHardwareAddress] = arpHeaderSenderProtocolAddress;
				return !result;
			}
			else
			{
				cmtsIpAddresses[arpHeaderSenderHardwareAddress] = arpHeaderSenderProtocolAddress;
				return true;
			}
		}

		private DsmCcModuleBlacklist dsmCcBlacklist;

		public bool IsDsmCcModuleBlacklisted(int currentNetworkId, int currentTransportStreamId, int elementaryPid,
			ushort moduleId,
			byte moduleVersion)
		{
			if (dsmCcBlacklist == null)
			{
				FileInfo fi = new FileInfo("dsmcc_fail_history.csv");
				dsmCcBlacklist = new DsmCcModuleBlacklist(fi);
			}

			return dsmCcBlacklist.IsBlacklisted(currentNetworkId, currentTransportStreamId, elementaryPid, moduleId,
				moduleVersion);
		}

		public int? GetCurrentLocationId()
		{
			if (!File.Exists("docsis_location.txt"))
				return 0;
			else
			{
				string readAllText = File.ReadAllText("docsis_location.txt");
				return Int32.Parse(readAllText);
			}
		}

		private Dictionary<PhysicalAddress, int> docsisParticipants;

		public void StoreDocsisParticipant(PhysicalAddress pa, int currentLocation)
		{
			if (docsisParticipants == null)
				docsisParticipants = new Dictionary<PhysicalAddress, int>();
			if (!docsisParticipants.ContainsKey(pa))
				docsisParticipants.Add(pa, currentLocation);
		}

		public bool TestForIpMacNotification(IpMacNotification notification)
		{
			IpMacNotification ipMacNotification = ipMacNotificationCoordinates.Find(x => x.Equals(notification));
			return ipMacNotification != null;
		}

		public void StoreIpMacNotification(IpMacNotification notification)
		{
			ipMacNotificationCoordinates.Add(notification);
		}

		#region Ts File Collection Importer

		private KnownTsMemory knownTss;

		public void ImportMarkFileAsKnown(FileInfo fi, TimeSpan ts, int tstype)
		{
			if (knownTss == null)
				knownTss = new KnownTsMemory("known_ts_filenames.json");
			knownTss.ImportMarkFileAsKnown(fi, ts, tstype);
		}

		public bool ImportFileKnown(FileInfo fi)
		{
			if (knownTss == null)
				knownTss = new KnownTsMemory("known_ts_filenames.json");
			return knownTss.ImportFileKnown(fi);
		}

		#endregion

		public DateTime T2MiGetTimestamp(int currentNetworkId, int currentTransportStreamId, int pid)
		{
			if (t2MiTimestamps == null)
				return DateTime.MinValue;

			if (t2MiTimestamps[currentNetworkId] == null)
				return DateTime.MinValue;

			if (t2MiTimestamps[currentNetworkId][currentTransportStreamId] == null)
				return DateTime.MinValue;

			return t2MiTimestamps[currentNetworkId][currentTransportStreamId][pid];
		}

		public void T2MiSetTimestamp(int currentNetworkId, int currentTransportStreamId, int pid, DateTime resolveTime)
		{
			if (t2MiTimestamps == null)
				t2MiTimestamps = new DateTime[ushort.MaxValue][][];

			if (t2MiTimestamps[currentNetworkId] == null)
				t2MiTimestamps[currentNetworkId] = new DateTime[ushort.MaxValue][];

			if (t2MiTimestamps[currentNetworkId][currentTransportStreamId] == null)
				t2MiTimestamps[currentNetworkId][currentTransportStreamId] = new DateTime[0x1fff];

			t2MiTimestamps[currentNetworkId][currentTransportStreamId][pid] = resolveTime;
		}

		public bool TestForRelatedContent(EitEvent lEvent, RctLinkInfo rctLinkInfo)
		{
			throw new NotImplementedException();
		}

		public void SetRelatedContent(EitEvent lEvent, RctLinkInfo rctLinkInfo)
		{
			throw new NotImplementedException();
		}

		private List<TunerMetadata> uiTuners;

		public bool UiTunerTestFor(TunerMetadata tuner)
		{
			if (uiTuners == null)
				return false;

			return uiTuners.Exists(x => x.MacAddress.Equals(tuner.MacAddress));
		}

		public void UiTunerUpdate(TunerMetadata tuner)
		{
			TunerMetadata copy = uiTuners.Find(x => x.MacAddress.Equals(tuner.MacAddress));
			copy.DiseqcType = tuner.DiseqcType;
			copy.Satellites[0] = tuner.Satellites[0];
			copy.Satellites[1] = tuner.Satellites[1];
			copy.Satellites[2] = tuner.Satellites[2];
			copy.Satellites[3] = tuner.Satellites[3];
		}

		public void UiTunerInsert(TunerMetadata tuner)
		{
			TunerMetadata copy = new TunerMetadata(tuner.Index, tuner.Name, tuner.Type);
			copy.DiseqcType = tuner.DiseqcType;
			copy.MacAddress = new PhysicalAddress(tuner.MacAddress.GetAddressBytes());
			copy.Satellites = new int[4];
			copy.Satellites[0] = tuner.Satellites[0];
			copy.Satellites[1] = tuner.Satellites[1];
			copy.Satellites[2] = tuner.Satellites[2];
			copy.Satellites[3] = tuner.Satellites[3];
			copy.Caps = tuner.Caps;
			uiTuners.Add(copy);
		}

		public void UiTunerGetConfiguration(TunerMetadata foundTuner)
		{
			TunerMetadata copy = uiTuners.Find(x => x.MacAddress.Equals(foundTuner.MacAddress));
			foundTuner.DiseqcType = copy.DiseqcType;
			foundTuner.Satellites = new int[4];
			foundTuner.Satellites[0] = copy.Satellites[0];
			foundTuner.Satellites[1] = copy.Satellites[1];
			foundTuner.Satellites[2] = copy.Satellites[2];
			foundTuner.Satellites[3] = copy.Satellites[3];
		}

		private void EnsureDirectoryExists(DirectoryInfo di)
		{
			if (di.Exists)
				return;
			EnsureDirectoryExists(di.Parent);
			di.Create();
		}

		public HeadlessJob GetQueuedJob()
		{
			throw new NotImplementedException();
		}

		public void SetQueuedJobComplete(HeadlessJob headlessJob)
		{
			throw new NotImplementedException();
		}

		public void WaitForCompletion()
		{
			//We're doing in-memory operations, so we'll won't have to wait for anything.
		}

		public void UiSetVersion(int version)
		{
			//Since we're working solely in memory, we won't need to remember this.
		}

		class T2MiTransmitterData
		{
			public ushort TimeOffset { get; set; }
		}

		private Dictionary<Tuple<int?, int?, int, ushort>,T2MiTransmitterData> t2miTransmitters;
		public bool T2MiTestForTransmitter(int? currentNetworkId, int? currentTransportStreamId, int relatedPid,
			ushort txIdentifier)
		{
			if (t2miTransmitters == null)
				return false;

			Tuple<int?, int?, int, ushort> t2miTransmitterId = new Tuple<int?, int?, int, ushort>(currentNetworkId, currentTransportStreamId, relatedPid, txIdentifier);
			return t2miTransmitters.ContainsKey(t2miTransmitterId);
		}

		public void T2MiRememberTransmitter(int? currentNetworkId, int? currentTransportStreamId, int relatedPid,
			ushort txIdentifier)
		{
			Tuple<int?, int?, int, ushort> t2miTransmitterId =
				new Tuple<int?, int?, int, ushort>(currentNetworkId, currentTransportStreamId, relatedPid,
					txIdentifier);

			if (t2miTransmitters == null)
				t2miTransmitters = new Dictionary<Tuple<int?, int?, int, ushort>, T2MiTransmitterData>();

			if (t2miTransmitters.ContainsKey(t2miTransmitterId))
				return;

			t2miTransmitters.Add(t2miTransmitterId, new T2MiTransmitterData());
		}

		public void T2MiSetTransmitterTimeOffset(int? currentNetworkId, int? currentTransportStreamId, int relatedPid,
			ushort txIdentifier, ushort timeOffset)
		{
			T2MiRememberTransmitter(currentNetworkId, currentTransportStreamId, relatedPid, txIdentifier);
			Tuple<int?, int?, int, ushort> t2miTransmitterId = new Tuple<int?, int?, int, ushort>(currentNetworkId, currentTransportStreamId, relatedPid, txIdentifier);
			t2miTransmitters[t2miTransmitterId].TimeOffset = timeOffset;
		}


		public object[] GetPluginConnector()
		{
			return new object[] { pluginToken };
		}

		public void Ping()
		{

		}

		public IEnumerable<Tuple<int, SatelliteDeliverySystemDescriptor.PolarizationEnum>> GetBlindscanResultFrequencies(Guid selectedGuid)
		{
			throw new NotImplementedException();
		}

		public void InsertUiBlindscanSettingHistory(int settingsWindowBlScanTunerSelection,
			int multitunerMode, int settingsWindowSetFilterTunerSelection,
			int settingsWindowDiseqc, bool settingsWindowCollectIqGraphs, bool settingsWindowCollectRfSpectrum,
			bool settingsWindowCaptureFile, int settingsWindowSatellite, int settingsWindowLnb, int dish,
			bool settingsWindowScanHorizontalLow, bool settingsWindowScanHorizontalHigh, bool settingsWindowScanVerticalLow,
			bool settingsWindowScanVerticalHigh)
		{
			throw new NotImplementedException();
		}

		public object[] GetLastUiBlindscanSettings()
		{
			throw new NotImplementedException();
		}

		private Dictionary<Tuple<ushort, byte, byte>, Tbtp2.Frame> _tbtp2;
		public bool TestForTerminalBurstTimePlan2(ushort interactiveNetworkId, byte tbtp2GroupId, byte frameFrameNumber)
		{
			if (_tbtp2 == null)
				return false;

			Tuple<ushort, byte, byte> key = new Tuple<ushort, byte, byte>(interactiveNetworkId, tbtp2GroupId, frameFrameNumber);
			return _tbtp2.ContainsKey(key);
		}

		public void StoreTerminalBurstTimePlan2(ushort interactiveNetworkId, byte tbtp2GroupId, Tbtp2.Frame frame)
		{
			if (_tbtp2 == null)
				_tbtp2 = new Dictionary<Tuple<ushort, byte, byte>, Tbtp2.Frame>();

			Tuple<ushort, byte, byte> key = new Tuple<ushort, byte, byte>(interactiveNetworkId, tbtp2GroupId, frame.FrameNumber);
			_tbtp2.Add(key, frame);
		}

		private Dictionary<Tuple<ushort, byte>, Fct2.Frame> _fct2Frames;
		public bool TestForFrameComposition2(ushort networkId, Fct2.Frame fct2)
		{
			if (_fct2Frames == null)
				return false;

			Tuple<ushort, byte> key = new Tuple<ushort, byte>(networkId, fct2.FrameType);
			return _fct2Frames.ContainsKey(key);
		}

		public void InsertFct2Frame(ushort networkId, Fct2.Frame frame)
		{
			if (_fct2Frames == null)
				_fct2Frames = new Dictionary<Tuple<ushort, byte>, Fct2.Frame>();

			Tuple<ushort, byte> key = new Tuple<ushort, byte>(networkId, frame.FrameType);
			_fct2Frames.Add(key, frame);
		}

		private Dictionary<Tuple<ushort, byte>, Bct.BroadcastConfiguration> broadcastConfigurations;
		public bool TestForBroadcastConfiguration(ushort networkId, byte txTypeTxType)
		{
			if (broadcastConfigurations == null)
				return false;

			Tuple<ushort, byte> key = new Tuple<ushort, byte>(networkId, txTypeTxType);
			return broadcastConfigurations.ContainsKey(key);
		}

		public void InsertBroadcastConfiguration(ushort networkId, Bct.BroadcastConfiguration txType)
		{
			if (broadcastConfigurations == null)
				broadcastConfigurations = new Dictionary<Tuple<ushort, byte>, Bct.BroadcastConfiguration>();

			Tuple<ushort, byte> key = new Tuple<ushort, byte>(networkId, txType.TxType);
			broadcastConfigurations.Add(key, txType);
		}

		private HashSet<RcsNit> _rcs2Nits;
		public bool TestForRcs2Nit(RcsNit nit)
		{
			if (_rcs2Nits == null)
				return false;

			return _rcs2Nits.Contains(nit);
		}

		public void InsertRcs2Nit(RcsNit nit)
		{
			if (_rcs2Nits == null)
				_rcs2Nits = new HashSet<RcsNit>();

			_rcs2Nits.Add(nit);
		}

		private DateTime[] _rcs2Timestamps;
		public bool UpdateRcs2Tdt(ushort interactiveNetworkId, DateTime tdtTimestamp)
		{
			if (_rcs2Timestamps == null)
				_rcs2Timestamps = new DateTime[ushort.MaxValue + 1];

			if (_rcs2Timestamps[interactiveNetworkId] < tdtTimestamp)
			{
				_rcs2Timestamps[interactiveNetworkId] = tdtTimestamp;
				return true;
			}

			return false;
		}

		private Dictionary<Tuple<ushort, int>, Tmst2.TransmissionMode> _tmst2;
		public bool TestForTmst2(ushort interactiveNetworkId, Tmst2.TransmissionMode mode)
		{
			if (_tmst2 == null)
				return false;

			Tuple<ushort, int> key = new Tuple<ushort, int>(interactiveNetworkId, mode.Modcod);
			return _tmst2.ContainsKey(key);
		}

		public void InsertTmst2(ushort interactiveNetworkId, Tmst2.TransmissionMode mode)
		{
			if (_tmst2 == null)
				_tmst2 = new Dictionary<Tuple<ushort, int>, Tmst2.TransmissionMode>();

			Tuple<ushort, int> key = new Tuple<ushort, int>(interactiveNetworkId, mode.Modcod);
			_tmst2.Add(key, mode);
		}

		public IEnumerable<Tuple<int, int, ProgramMapping>> SelectAllPmt()
		{
			for (int x = 0; x < pmtEntries.Length; x++)
			{
				if (pmtEntries[x] == null)
					continue;

				for (int y = 0; y < pmtEntries[x].Length; y++)
				{
					if (pmtEntries[x][y] == null)
						continue;

					for (int z = 0; z < pmtEntries[x][y].Length; z++)
					{
						if (pmtEntries[x][y][z] == null)
							continue;

						yield return new Tuple<int, int, ProgramMapping>(y, x, pmtEntries[x][y][z]);
					}
				}
			}

			yield break;
		}

		public SdtService SelectSdtById(int x, int y, ushort programMappingProgramNumber)
		{
			if (sdtServices[y] == null)
				return null;

			if (sdtServices[y][x] == null)
				return null;

			return sdtServices[y][x][programMappingProgramNumber];
		}

		public IEnumerable<Tuple<int, int, SdtService>> SelectAllSdt()
		{
			for (int x = 0; x < sdtServices.Length; x++)
			{
				if (sdtServices[x] == null)
					continue;

				for (int y = 0; y < sdtServices[x].Length; y++)
				{
					if (sdtServices[x][y] == null)
						continue;

					for (int z = 0; z < sdtServices[x][y].Length; z++)
					{
						if (sdtServices[x][y][z] != null)
						{
							yield return new Tuple<int, int, SdtService>(x, y, sdtServices[x][y][z]);
						}
					}
				}
			}

			yield break;
		}

		public void BeamsDisableAll()
		{
			throw new NotImplementedException();
		}

		public void BeamsEnable(int id, float satpos, string name, DateTime processTimestamp)
		{
			throw new NotImplementedException();
		}

		public void BeamFootprintStore(int databasePointerId, DateTime databasePointerBeamsProcessTimestamp,
			string name,
			string getPolygonString, string id)
		{
			throw new NotImplementedException();
		}

		public bool TestForBeamFootprint(int databasePointerId, DateTime databasePointerBeamsProcessTimestamp,
			string name, string id)
		{
			throw new NotImplementedException();
		}

		public void BeamsDisableSpecific(int databasePointerId, float databasePointerSatpos, string databasePointerName,
			DateTime databasePointerBeamsProcessTimestamp)
		{
			throw new NotImplementedException();
		}

		public IEnumerable<SatelliteBeam> BeamsSelectEnabled()
		{
			throw new NotImplementedException();
		}

		public List<SatelliteBeamFootprint> BeamsSelectFootprints(int satelliteBeamId,
			DateTime satelliteBeamProcessTimestamp)
		{
			throw new NotImplementedException();
		}

		private HashSet<DbBlindscanJobContainer> jobs;

		public void InsertBlindscanJob(DbBlindscanJob jobInDb)
		{
			if (jobs == null)
				jobs = new HashSet<DbBlindscanJobContainer>();

			DbBlindscanJobContainer jobContainer = new DbBlindscanJobContainer(jobInDb);
			jobs.Add(jobContainer);
		}

		public void UpdateJobState(DbBlindscanJob jobInDb)
		{

		}


		public void InsertSearchResult(DbBlindscanJob jobInDb, bool satellite, SearchResult searchResult,
			int polarityIndex,
			SearchResult2 searchResult2)
		{
			DbBlindscanJobContainer dbBlindscanJobContainer = jobs.First(x => x.JobGuid.Equals(jobInDb.JobGuid));
			if (dbBlindscanJobContainer == null)
				throw new Exception("Failed to find the job.");

			dbBlindscanJobContainer.AddSearchResult(satellite, searchResult, polarityIndex, searchResult2);
		}

		public void UpdateTransponderState(DbBlindscanJob jobInDb, bool satellite, SearchResult searchResult,
			BlindscanResultState blindscanResultState, SearchResult2 searchResult2)
		{

		}

		public void InsertTransponderService(DbBlindscanJob jobInDb, bool resultSatellite, SearchResult resultSr1,
			SearchResult2 resultSr2, HumanReadableService humanReadableService)
		{
			DbBlindscanJobContainer jobContainer = jobs.First(x => x.JobGuid.Equals(jobInDb.JobGuid));
			if (jobContainer == null)
				throw new Exception("Failed to find the job.");

			DbBlindscanJobContainer.SearchResultContainer searchResultContainer =
				jobContainer.GetSearchResult(resultSatellite, resultSr1, resultSr2);
			if (searchResultContainer == null)
				throw new Exception("Failed to find the search result.");
			searchResultContainer.AddService(humanReadableService);
		}

		public bool TestForIncompleteJob()
		{
			return false;
		}

		public DbBlindscanJob GetPastBlindscanJob(long offset)
		{
			throw new NotImplementedException();
		}

		public void DeleteBlindscanJob(Guid guid)
		{
			throw new NotImplementedException();
		}

		public void DeleteBlindscanResults(Guid jobGuid, int i)
		{
			throw new NotImplementedException();
		}

		public void MoveBlScanResultsToAnotherJob(Guid jobGuid1, Guid jobGuid2, int j)
		{
			throw new NotImplementedException();
		}

		public void FailDsmCcDownload(DatabaseKeyDsmCcModule key, double value)
		{
			if (dsmCcBlacklist == null)
			{
				FileInfo fi = new FileInfo("dsmcc_fail_history.csv");
				dsmCcBlacklist = new DsmCcModuleBlacklist(fi);
			}

			dsmCcBlacklist.AddFailedModule(key.CurrentNetworkId, key.CurrentTransportStreamId, key.ElementaryPid, key.ModuleId, key.ModuleVersion, value);
		}

		public bool TestForTerminalBurstTimePlan(ushort interactiveNetworkId, uint groupId)
		{
			throw new NotImplementedException();
		}

		public void StoreTerminalBurstTimePlan(ushort interactiveNetworkId, Tbtp tbtp)
		{
			throw new NotImplementedException();
		}

		private Dictionary<Tuple<ushort, uint, uint>, Tbtp.TbtpFrame.BtpEntity> _tbtpEntities;
		public bool TestForTerminalBurstTimePlan(ushort interactiveNetworkId, uint groupId, uint logonId)
		{
			if (_tbtpEntities == null)
				return false;

			Tuple<ushort, uint, uint> tuple = new Tuple<ushort, uint, uint>(interactiveNetworkId, groupId, logonId);

			return _tbtpEntities.ContainsKey(tuple);
		}

		public void StoreTerminalBurstTimePlan(ushort interactiveNetworkId, uint gtoupId, uint superframeCount,
			uint frameNumber, Tbtp.TbtpFrame.BtpEntity btp)
		{
			throw new NotImplementedException();
		}

		private HashSet<Cmt.CmtEntry>[] cmtEntries; 
		public bool TestForCmtEntry(ushort interactiveNetworkId, Cmt.CmtEntry entry)
		{
			if (cmtEntries == null)
				return false;
			if (cmtEntries[interactiveNetworkId] == null)
				return false;

			return cmtEntries[interactiveNetworkId].Contains(entry);
		}

		public void InsertCmtEntry(ushort interactiveNetworkId, Cmt.CmtEntry entry)
		{
			if (cmtEntries == null)
				cmtEntries = new HashSet<Cmt.CmtEntry>[ushort.MaxValue];
			if (cmtEntries[interactiveNetworkId] == null)
				cmtEntries[interactiveNetworkId] = new HashSet<Cmt.CmtEntry>();
			cmtEntries[interactiveNetworkId].Add(entry);
		}

		public int GetRmtTransmissionStandard(ushort networkId)
		{
			if (rmts == null)
				return 0;

			if (rmts[networkId] == null)
				return 0;

			if (rmts[networkId].TransportStreams == null)
				return 0;

			foreach(Rmt.TransportStream ts in rmts[networkId].TransportStreams)
			{
				if (ts.SatelliteForwardLink != null)
					return (int)ts.SatelliteForwardLink.TransmissionStandard;
			}

			return 0;
		}

		private byte[][] _tmst;
		public byte[] GetTmst(ushort interactiveNetworkId)
		{
			if (_tmst == null)
				return null;
			if (_tmst[interactiveNetworkId] == null)
				return null;
			return _tmst[interactiveNetworkId];
		}

		public void InsertTmst(ushort interactiveNetworkId, byte[] modes)
		{
			if (_tmst == null)
				_tmst = new byte[ushort.MaxValue][];
			_tmst[interactiveNetworkId] = modes;
		}

		public void UpdateTmst(ushort interactiveNetworkId, byte[] modes)
		{
			throw new NotImplementedException();
		}

		private HashSet<Sct.Superframe>[] _sctSuperframes;
		public bool TestForSuperframeComposition(ushort interactiveNetworkId, Sct.Superframe superframe)
		{
			if (_sctSuperframes == null)
				return false;

			if (_sctSuperframes[interactiveNetworkId] == null)
				return false;

			return _sctSuperframes[interactiveNetworkId].Contains(superframe);
		}

		public void StoreSuperframeComposition(ushort interactiveNetworkId, Sct.Superframe superframe)
		{
			if (_sctSuperframes == null)
				_sctSuperframes = new HashSet<Sct.Superframe>[ushort.MaxValue];

			if (_sctSuperframes[interactiveNetworkId] == null)
				_sctSuperframes[interactiveNetworkId] = new HashSet<Sct.Superframe>();

			_sctSuperframes[interactiveNetworkId].Add(superframe);
		}

		private HashSet<Fct.Frame>[] _fctFrames;
		public bool TestForFrameComposition(ushort interactiveNetworkId, Fct.Frame frame)
		{
			if (_fctFrames == null)
				return false;
			if (_fctFrames[interactiveNetworkId] == null)
				return false;

			return _fctFrames[interactiveNetworkId].Contains(frame);
		}

		public void InsertFctFrame(ushort interactiveNetworkId, Fct.Frame frame)
		{
			if (_fctFrames == null)
				_fctFrames = new HashSet<Fct.Frame>[ushort.MaxValue];
			if (_fctFrames[interactiveNetworkId] == null)
				_fctFrames[interactiveNetworkId] = new HashSet<Fct.Frame>();

			_fctFrames[interactiveNetworkId].Add(frame);
		}

		private HashSet<Spt.Satellite>[] _sptSatellites;
		public bool TestForSatellitePosition(ushort interactiveNetworkId, Spt.Satellite satellite)
		{
			if (_sptSatellites == null)
				return false;
			if (_sptSatellites[interactiveNetworkId] == null)
				return false;

			return _sptSatellites[interactiveNetworkId].Contains(satellite);
		}

		public void StoreSatellitePosition(ushort interactiveNetworkId, Spt.Satellite satellite)
		{
			if (_sptSatellites == null)
				_sptSatellites = new HashSet<Spt.Satellite>[ushort.MaxValue];
			if (_sptSatellites[interactiveNetworkId] == null)
				_sptSatellites[interactiveNetworkId] = new HashSet<Spt.Satellite>();

			_sptSatellites[interactiveNetworkId].Add(satellite);
		}

		public IEnumerable<DbBlindscanJob> GetDbBlindscanJobs()
		{
			throw new NotImplementedException();
		}

		public IReadOnlyList<string> ListImportFileByTag1(int tag1)
		{
			throw new NotImplementedException();
		}

		public long DnsCountA()
		{
			if (dnsRecords == null)
				return 0;

			return dnsRecords.Count(x => x.RecordType.Item1 == 1);
		}

		private Dictionary<IPAddress, string> _ipStringToName;
		public string DnsIpToName(IPAddress source)
		{
			if (_ipStringToName == null)
				return null;

			throw new NotImplementedException();
		}

		public bool TestForIp(IPAddress iP)
		{
			if (dnsRecords == null)
				return false;

			foreach (DnsRecord dnsRecord in dnsRecords)
			{
				if (dnsRecord.RecordType.Item1 != 1 && dnsRecord.RecordType.Item1 != 28)
					continue;

				if (dnsRecord.IP.Equals(iP))
					return true;
			}

			return false;
		}

		private HashSet<DnsRecord> dnsRecords;

		public void RememberDnsRecord(DnsRecord record)
		{
			if (dnsRecords == null)
				dnsRecords = new HashSet<DnsRecord>();

			dnsRecords.Add(record);
		}

		private SgtList[] sgtLists;

		public bool TestForSgtList(SgtList list)
		{
			if (sgtLists == null)
				return false;

			return sgtLists[list.ServiceListId] != null;
		}

		public void InsertSgtList(SgtList list)
		{
			if (sgtLists == null)
				sgtLists = new SgtList[ushort.MaxValue];

			sgtLists[list.ServiceListId] = list;
		}

		private HashSet<SgtService> sgtServices;

		public bool TestForSgtService(SgtService child)
		{
			if (sgtServices == null)
				return false;

			return sgtServices.Contains(child);
		}

		public void InsertSgtService(SgtService child)
		{
			if (sgtServices == null)
				sgtServices = new HashSet<SgtService>();

			sgtServices.Add(child);
		}
		
		private class NipPds
		{
			public class NipSubPds
			{
				public DateTime VersionUpdate { get; set; }
				public List<string> PrivateDataSessions { get; set; }

				public NipSubPds(DateTime versionUpdate, List<string> privateDataSessions)
				{
					VersionUpdate = versionUpdate;
					PrivateDataSessions = privateDataSessions;
				}
			}

			public Dictionary<uint, NipSubPds> subs;
		}

		private Dictionary<NipActualCarrierInformation, NipPds> _nipPrivateDataSpecifiers;

		public bool DvbNipPrivateDataSpecifier(NipActualCarrierInformation currentCarrierInformation,
			DateTime versionUpdate, uint privateDataSpecifier, List<string> privateDataSessions)
		{
			if (_nipPrivateDataSpecifiers == null)
				_nipPrivateDataSpecifiers = new Dictionary<NipActualCarrierInformation, NipPds>();

			if (_nipPrivateDataSpecifiers.ContainsKey(currentCarrierInformation))
			{
				NipPds oldPds = _nipPrivateDataSpecifiers[currentCarrierInformation];
				if (oldPds.subs.ContainsKey(privateDataSpecifier))
				{
					NipPds.NipSubPds oldPdsSub = oldPds.subs[privateDataSpecifier];
					if (oldPdsSub.VersionUpdate < versionUpdate)
					{
						oldPdsSub.VersionUpdate = versionUpdate;
						oldPdsSub.PrivateDataSessions = privateDataSessions;
						return true;
					}
					else
					{
						return false;
					}
				}
				else
				{
					oldPds.subs.Add(privateDataSpecifier, new NipPds.NipSubPds(versionUpdate, privateDataSessions));
					return true;
				}

			}
			else
			{
				NipPds newPds = new NipPds();
				newPds.subs = new Dictionary<uint, NipPds.NipSubPds>();
				newPds.subs.Add(privateDataSpecifier, new NipPds.NipSubPds(versionUpdate, privateDataSessions));
				return true;
			}
		}

		private BroadcastNetworkType[] nipBroadcastNetworkTypes;

		public bool DvbNipTestForNetwork(BroadcastNetworkType network)
		{
			if (nipBroadcastNetworkTypes == null)
				return false;

			return nipBroadcastNetworkTypes[network.NIPNetworkID] != null;
		}

		public void DvbNipInsertNetwork(BroadcastNetworkType network)
		{
			if (nipBroadcastNetworkTypes == null)
				nipBroadcastNetworkTypes = new BroadcastNetworkType[ushort.MaxValue];

			nipBroadcastNetworkTypes[network.NIPNetworkID] = network;
		}

		private class NipServiceCoordinate
		{
			public NipServiceCoordinate(BroadcastMediaStreamType bmst)
			{
				this.NetworkId = bmst.NIPNetworkID;
				this.CarrierId = Convert.ToInt32(bmst.NIPCarrierID);
				this.LinkId = Convert.ToInt32(bmst.NIPLinkID);
				this.ServiceId = bmst.NIPServiceID;
			}

			public ushort ServiceId { get; set; }

			public int LinkId { get; set; }

			public int CarrierId { get; set; }

			public ushort NetworkId { get; set; }

			protected bool Equals(NipServiceCoordinate other)
			{
				return ServiceId == other.ServiceId && LinkId == other.LinkId && CarrierId == other.CarrierId &&
				       NetworkId == other.NetworkId;
			}

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

			public override int GetHashCode()
			{
				return HashCode.Combine(ServiceId, LinkId, CarrierId, NetworkId);
			}
		}

		private Dictionary<NipServiceCoordinate, BroadcastMediaStreamType> _dvbNipServices;

		public bool DvbNipTestForService(BroadcastMediaStreamType broadcastMediaStreamType)
		{
			if (_dvbNipServices == null)
				return false;

			NipServiceCoordinate coords = new NipServiceCoordinate(broadcastMediaStreamType);
			return _dvbNipServices.ContainsKey(coords);
		}

		public void DvbNipInsertService(BroadcastMediaStreamType broadcastMediaStreamType)
		{
			if (_dvbNipServices == null)
				_dvbNipServices = new Dictionary<NipServiceCoordinate, BroadcastMediaStreamType>();

			NipServiceCoordinate coords = new NipServiceCoordinate(broadcastMediaStreamType);
			_dvbNipServices.Add(coords, broadcastMediaStreamType);
		}

		private Dictionary<string, MulticastSessionType> _dvbNipMulticastSessions;

		public bool DvbNipTestForMulticastSession(MulticastSessionType multicastSession)
		{
			if (_dvbNipMulticastSessions == null)
				return false;

			return _dvbNipMulticastSessions.ContainsKey(multicastSession.serviceIdentifier);
		}

		public void DvbNipInsertMulticastSession(MulticastSessionType multicastSession)
		{
			if (_dvbNipMulticastSessions == null)
				_dvbNipMulticastSessions = new Dictionary<string, MulticastSessionType>();

			_dvbNipMulticastSessions[multicastSession.serviceIdentifier] = multicastSession;
		}

		private Dictionary<DatabaseKeyNipMulticastGatewayConfigurationTransportSession,
			MulticastEndpointAddressType> _nipMulticastGatewayConfigurationTransportSessions;

		public bool DvbNipTestForMulticastGatewayConfigurationTransportSession(NipActualCarrierInformation carrier,
			MulticastEndpointAddressType multicastEndpointAddressType)
		{
			if (_nipMulticastGatewayConfigurationTransportSessions == null)
				return false;

			DatabaseKeyNipMulticastGatewayConfigurationTransportSession key =
				new DatabaseKeyNipMulticastGatewayConfigurationTransportSession(carrier, multicastEndpointAddressType);
			return _nipMulticastGatewayConfigurationTransportSessions.ContainsKey(key);
		}

		public void DvbNipInsertMulticastGatewayConfigurationTransportSession(NipActualCarrierInformation carrier,
			MulticastEndpointAddressType multicastGatewayConfigurationTransportSession)
		{
			if (_nipMulticastGatewayConfigurationTransportSessions == null)
				_nipMulticastGatewayConfigurationTransportSessions =
					new Dictionary<DatabaseKeyNipMulticastGatewayConfigurationTransportSession,
						MulticastEndpointAddressType>();

			DatabaseKeyNipMulticastGatewayConfigurationTransportSession key =
				new DatabaseKeyNipMulticastGatewayConfigurationTransportSession(carrier,
					multicastGatewayConfigurationTransportSession);
			_nipMulticastGatewayConfigurationTransportSessions.Add(key, multicastGatewayConfigurationTransportSession);
		}

		private HashSet<NipActualCarrierInformation> _nipActualCarriers;
		public bool DvbNipTestForCarrier(NipActualCarrierInformation currentCarrierInformation)
		{
			if (_nipActualCarriers == null)
				return false;

			return _nipActualCarriers.Contains(currentCarrierInformation);
		}

		public void DvbNipInsertCarrier(NipActualCarrierInformation currentCarrierInformation)
		{
			if (_nipActualCarriers == null)
				_nipActualCarriers = new HashSet<NipActualCarrierInformation>();

			_nipActualCarriers.Add(currentCarrierInformation);
		}

		public void InsertDvbiServiceListEntryPoint(long sourceHash)
		{
			if (_dvbiServiceListEntryPointsCoordinates == null)
				_dvbiServiceListEntryPointsCoordinates = new HashSet<DvbiServiceListEntryPointsCoordinate>();

			DvbiServiceListEntryPointsCoordinate coordinate = new DvbiServiceListEntryPointsCoordinate();
			coordinate.Hash = sourceHash;
			_dvbiServiceListEntryPointsCoordinates.Add(coordinate);
		}

		public bool TestForServiceListEntryPoints(long sourceHash)
		{
			throw new NotImplementedException();
		}

		public void InsertDvbiServiceList(DvbiServiceList serviceList)
		{
			if (_dvbiServiceLists == null)
				_dvbiServiceLists = new Dictionary<string, DvbiServiceList>();
			if (string.IsNullOrEmpty(serviceList.Id))
				return;

			_dvbiServiceLists.Add(serviceList.Id, serviceList);
		}

		public bool TestForDvbiServiceList(string id)
		{
			if (_dvbiServiceLists == null)
				return false;

			return _dvbiServiceLists.ContainsKey(id);
		}

		private Dictionary<string, DvbiServiceList> _dvbiServiceLists;

		private class DvbiServiceListEntryPointsCoordinate
		{
			public long Hash { get; internal set; }
			public DateTime LastUpdate { get; internal set; }

			public override bool Equals(object? obj)
			{
				return obj is DvbiServiceListEntryPointsCoordinate coordinate &&
				       Hash == coordinate.Hash;
			}

			public override int GetHashCode()
			{
				return HashCode.Combine(Hash);
			}
		}

		private HashSet<DvbiServiceListEntryPointsCoordinate> _dvbiServiceListEntryPointsCoordinates;


		public void UpdateDvbiServiceListEntryPointUpdateDate(long v, DateTime currentTime)
		{
			foreach (DvbiServiceListEntryPointsCoordinate coord in _dvbiServiceListEntryPointsCoordinates)
			{
				if (coord.Hash == v)
				{
					coord.LastUpdate = currentTime;
					return;
				}
			}
		}

		public bool TestForDvbiServiceListEntryPoints(long sourceHash)
		{
			if (_dvbiServiceListEntryPointsCoordinates == null)
				return false;

			foreach (DvbiServiceListEntryPointsCoordinate coord in _dvbiServiceListEntryPointsCoordinates)
			{
				if (coord.Hash == sourceHash)
				{
					return true;
				}
			}

			return false;
		}

		private Dictionary<string, DateTime> _dvbiServiceListLastChecked;

		public void UpdateDvbiServiceListLastCheckedDate(string id, DateTime currentTime)
		{
			if (_dvbiServiceListLastChecked == null)
				_dvbiServiceListLastChecked = new Dictionary<string, DateTime>();

			_dvbiServiceListLastChecked[id] = currentTime;
		}

		public DateTime GetLastDvbiServiceListEntryPointUpdateDate(long sourceHash)
		{
			foreach (DvbiServiceListEntryPointsCoordinate coord in _dvbiServiceListEntryPointsCoordinates)
			{
				if (coord.Hash == sourceHash)
				{
					return coord.LastUpdate;
				}
			}

			return DateTime.MinValue;
		}

		public DateTime GetDvbiServiceListLastUpdateDate(string id)
		{
			throw new NotImplementedException();
		}

		private Dictionary<long, List<string>> _dvbiServiceListEntryPointToServiceListMapping;

		public void AddDvbiServiceListToServiceListEntryPoint(DvbiServiceList serviceList, long sourceHash)
		{
			if (_dvbiServiceListEntryPointToServiceListMapping == null)
				_dvbiServiceListEntryPointToServiceListMapping = new Dictionary<long, List<string>>();

			if (!_dvbiServiceListEntryPointToServiceListMapping.ContainsKey(sourceHash))
				_dvbiServiceListEntryPointToServiceListMapping.Add(sourceHash, new List<string>());

			if (!_dvbiServiceListEntryPointToServiceListMapping[sourceHash].Contains(serviceList.Id))
				_dvbiServiceListEntryPointToServiceListMapping[sourceHash].Add(serviceList.Id);
		}

		private Dictionary<string, List<string>> _dvbiServiceToServiceListMapping;

		public void AddDvbiServiceToServiceList(string id, string serviceListId)
		{
			if (_dvbiServiceToServiceListMapping == null)
				_dvbiServiceToServiceListMapping = new Dictionary<string, List<string>>();

			if (!_dvbiServiceToServiceListMapping.ContainsKey(serviceListId))
				_dvbiServiceToServiceListMapping.Add(serviceListId, new List<string>());

			if (!_dvbiServiceToServiceListMapping[serviceListId].Contains(id))
				_dvbiServiceToServiceListMapping[serviceListId].Add(id);
		}

		public int GetDvbiServiceVersion(string id)
		{
			foreach (DvbIService service in _dvbiServices)
			{
				if (service.Id.Equals(id))
				{
					return service.Version;
				}
			}

			return -1;
		}

		private HashSet<DvbIService> _dvbiServices;

		public bool TestForDvbiService(string id)
		{
			if (_dvbiServices == null)
				return false;

			return _dvbiServices.Any(x => x.Id.Equals(id));
		}

		public void InsertDvbiService(DvbIService service)
		{
			if (_dvbiServices == null)
				_dvbiServices = new HashSet<DvbIService>();

			_dvbiServices.Add(service);
		}

		public void UpdateDvbiService(DvbIService service)
		{
			if (_dvbiServices == null)
				return;
			
			foreach (DvbIService oldService in _dvbiServices)
			{
				if (oldService.Id == service.Id)
				{
					_dvbiServices.Remove(oldService);
					break;
				}
			}

			_dvbiServices.Add(service);
		}

		private Rmt[] rmts;
		public bool TestForRmt(Rmt rmt)
		{
			if (rmts == null)
				return false;
			return rmts[rmt.NetworkId] != null;
		}

		public void InsertRmt(Rmt rmt)
		{
			if (rmts == null)
				rmts = new Rmt[ushort.MaxValue];
			rmts[ushort.MaxValue] = rmt;
		}

		private Dictionary<Tuple<ushort, PhysicalAddress>, Tim> tims;
		public Tim GetLastTim(ushort interactiveNetworkId, PhysicalAddress physicalAddress)
		{
			if (tims == null)
				return null;

			Tuple<ushort, PhysicalAddress> key = new Tuple<ushort, PhysicalAddress>(interactiveNetworkId, physicalAddress);
			if (!tims.ContainsKey(key))
				return null;

			return tims[key];
		}

		public void UpsertTim(ushort interactiveNetworkId, PhysicalAddress physicalAddress, Tim currentTim)
		{
			if (tims == null)
				tims = new Dictionary<Tuple<ushort, PhysicalAddress>, Tim>();

			Tuple<ushort, PhysicalAddress> key = new Tuple<ushort, PhysicalAddress>(interactiveNetworkId, physicalAddress);
			tims[key] = currentTim;
		}

		private Dictionary<string, Tuple<UpdateNotificationGroup, UpdateNotificationTarget>> knownUnts;
		public void StoreUpdateNotification2(UpdateNotificationGroup common, UpdateNotificationTarget target)
		{
			if (knownUnts == null)
				knownUnts = new Dictionary<string, Tuple<UpdateNotificationGroup, UpdateNotificationTarget>>();

			if (knownUnts.ContainsKey(common.Oui))
				return;

			knownUnts[common.Oui] = new Tuple<UpdateNotificationGroup, UpdateNotificationTarget>(common, target);
		}
	}
}
