using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Dvb.Descriptors;
using skyscraper5.Skyscraper.IO;
using skyscraper8.SophtainerIO;

namespace skyscraper8.Skyscraper.Drawing
{
	public class RfSpectrumData
	{

		private RfSpectrumData()
		{
			blocks = new List<RfSpectrumDataBlock>();
		}

		public static RfSpectrumData Create()
		{
			RfSpectrumData child = new RfSpectrumData();
			return child;
		}

		private List<RfSpectrumDataBlock> blocks;

		public RfSpectrumDataBlock CreateBlock(int minFreq, int maxFreq, int step, SatelliteDeliverySystemDescriptor.PolarizationEnum polarization)
		{
			RfSpectrumDataBlock child = new RfSpectrumDataBlock(minFreq,maxFreq,step,polarization);
			blocks.Add(child);
			return child;
		}

		public void SaveTo(Stream outerStream)
		{
			Sophtainer sophtainer = Sophtainer.CreateSophtainer(outerStream, 538986066u, new Version(1, 0, 0, 0));
			OffsetStream stream = sophtainer.GetStream();

			foreach (RfSpectrumDataBlock block in blocks)
			{
				stream.WriteUInt8(0x58);
				stream.WriteInt32LE(block.MinimumFrequency);
				stream.WriteInt32LE(block.MaximumFrequency);
				stream.WriteInt32LE(block.Step);
				stream.WriteUInt8((byte)block.Polarization);

				double[] blockData = block.Data;
				for (int i = 0; i < blockData.Length; i++)
					stream.WriteFloat64LE(blockData[i]);
			}

			stream.WriteUInt8(0x4f);
			
		}

		public byte[] SaveToBytes()
		{
			MemoryStream ms = new MemoryStream();
			SaveTo(ms);
			return ms.GetBuffer();
		}

		public static RfSpectrumData LoadFromStream(Stream fileStream)
		{
			Sophtainer sophtainer = Sophtainer.LoadSophtainer(fileStream);
			if (sophtainer.Application.Value != 538986066u)
				throw new WrongApplicationException(538986066u, sophtainer.Application.Value);

			OffsetStream stream = sophtainer.GetStream();

			RfSpectrumData result = new RfSpectrumData();

			byte currentBlockType;
			while ((currentBlockType = stream.ReadUInt8()) == 0x58)
			{
				int minFreq = stream.ReadInt32LE();
				int maxFreq = stream.ReadInt32LE();
				int step = stream.ReadInt32LE();
				SatelliteDeliverySystemDescriptor.PolarizationEnum polarizazion = (SatelliteDeliverySystemDescriptor.PolarizationEnum)stream.ReadUInt8();
				RfSpectrumDataBlock block = result.CreateBlock(minFreq, maxFreq, step, polarizazion);
				for (int i = 0; i < block.Data.Length; i++)
					block.Data[i] = stream.ReadFloat64LE();
			}

			stream.Close();
			sophtainer.Dispose();

			return result;
		}

		public IEnumerable<RfSpectrumDataBlock> GetBlocks()
		{
			return blocks.AsReadOnly();
		}
	}

	public class RfSpectrumDataBlock
	{

		public RfSpectrumDataBlock(int minFreq, int maxFreq, int step, SatelliteDeliverySystemDescriptor.PolarizationEnum polarization)
		{
			MinimumFrequency = minFreq;
			MaximumFrequency = maxFreq;
			Step = step;
			Polarization = polarization;
			Data = new double[Length + 1];
		}

		public SatelliteDeliverySystemDescriptor.PolarizationEnum Polarization { get; private set; }

		public int Step { get; private set; }

		public int MaximumFrequency { get; private set; }

		public int MinimumFrequency { get; private set; }

		public int Length => (MaximumFrequency - MinimumFrequency) / Step;

		public double[] Data { get; private set; }

		public bool Push(int i, double rf)
		{
			i -= MinimumFrequency;
			i /= Step;
			if (i >= Data.Length)
				return false;
			Data[i] = rf;
			return true;
		}
	}
}
