using System;
using System.Collections.Generic;

namespace skyscraper5.Scorcher
{
	public abstract class PsiGenerator : IPacketGenerator
	{
		protected PsiGenerator(TimeSpan timeInbetween, uint pid)
		{
			this.packetQueue = new Queue<byte[]>();
			this.apperanceTimeSpan = timeInbetween;
			this.pid = pid;
		}

		private uint pid;
		private TimeSpan apperanceTimeSpan;
		private DateTime lastBroadcast;
		private bool pusi;
		private int continuity;
		private Queue<byte[]> packetQueue;
		protected int versionNumber;

		public abstract byte[] BuildPsi();

		private void EnqueuePackets()
		{
			byte[] buildPsi = BuildPsi();
			int numPackets = 0;
			for (int i = 0; i < buildPsi.Length; numPackets++)
			{
				byte[] newPacket = new byte[188];
				Array.Fill(newPacket, (byte)0xff);
				byte[] buildHeader = TsPacketHeaderBuilder.BuildHeader(numPackets == 0, pid, continuity++);
				Array.Copy(buildHeader, 0, newPacket, 0, buildHeader.Length);

				byte packetSizeLeft = 188;
				packetSizeLeft -= (byte)buildHeader.Length;
				if (numPackets == 0)
				{
					newPacket[buildHeader.Length] = 0;
					packetSizeLeft--;
				}

				int copySize = Math.Min(packetSizeLeft, buildPsi.Length - i);
				Array.Copy(buildPsi, i, newPacket, 188 - packetSizeLeft, copySize);
				i += copySize;
				packetQueue.Enqueue(newPacket);
			}
		}

		public bool PacketAvailable()
		{
			if (packetQueue.Count > 0)
				return true;

			DateTime whenNeeded = lastBroadcast + apperanceTimeSpan;
			return DateTime.Now >= whenNeeded;
		}

		public byte[] GeneratePacket()
		{
			if (packetQueue.Count == 0)
				EnqueuePackets();

			byte[] result = packetQueue.Dequeue();
			lastBroadcast = DateTime.Now;
			return result;
		}
	}
}
