using System;
using System.Collections.Generic;
using System.IO;
using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.IO;

namespace skyscraper5.Scorcher
{
	internal class PatGenerator : PsiGenerator
	{

		public PatGenerator(ushort transportStreamId) : base(new TimeSpan(0,0,0,2), 0x0000)
		{
			TransportStreamId = transportStreamId;
			content = new Dictionary<ushort, ushort>();
		}

		public ushort TransportStreamId { get; }
		private Dictionary<ushort, ushort> content;

		public void AddProgram(ushort programId, ushort pmtPid)
		{
			content.Add(programId, pmtPid);
			versionNumber++;
		}

		public override byte[] BuildPsi()
		{
			ushort sectionLength = (ushort)((content.Count * 4) + 5 + 4);
			sectionLength &= 0x03ff;
			if (versionNumber > 32)
				versionNumber %= 32;
			
			MemoryStream ms = new MemoryStream();
			ms.WriteUInt8(0);	//Table ID

			byte byte2 = 0;
			byte2 |= 0x80;	//section syntax indicator
			//byte2 &= 0x40;	//'0'
			byte2 |= 0x30;	//reserved
			byte2 += (byte)((sectionLength & 0x0300) >> 8);
			ms.WriteUInt8(byte2);	//section length, part 1

			byte byte3 = (byte)(sectionLength & 0x00ff);
			ms.WriteUInt8(byte3);	//section length, part 2

			ms.WriteUInt16BE(TransportStreamId);	//transport stream id


			byte byte4 = 0;
			byte4 |= 0xc0;	//reserved
			byte4 |= (byte)(versionNumber << 1);	//version number
			byte4 |= 0x01;	//current_next_indicator
			ms.WriteUInt8(byte4);

			ms.WriteUInt8(0);	//section number
			ms.WriteUInt8(0);	//last section number
			foreach (var (program_number, program_map_pid) in content)
			{
				ms.WriteUInt16BE(program_number);
				ms.WriteUInt16BE((ushort)(program_map_pid & 0x1fff));
			}

			uint crc = DvbCrc32.CreateCrc(ms, 0, (int)ms.Position);
			ms.WriteUInt32BE(crc);
															 
			return ms.ToArray();
		}
	}
}
