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

namespace skyscraper5.Scorcher
{
	internal class CatGenerator : PsiGenerator
	{
		public CatGenerator() : base(new TimeSpan(0,0,4), 0x0001)
		{
			caDescriptors = new List<CaDescriptor>();
		}

		private List<CaDescriptor> caDescriptors;
		private byte[] SerializeDescriptors()
		{
			MemoryStream ms = new MemoryStream();
			foreach (CaDescriptor descriptor in caDescriptors)
			{
				ms.WriteUInt8(descriptor.GetDescriptorId());    //descriptor_tag

				byte[] descriptorBytes = descriptor.Serialize();
				ms.WriteUInt8((byte)descriptorBytes.Length);    //descriptor_length
				ms.Write(descriptorBytes, 0, descriptorBytes.Length);
			}
			return ms.ToArray();
		}
		public override byte[] BuildPsi()
		{
			byte[] descriptorBuffer = SerializeDescriptors();
			int sectionLength = 5 + descriptorBuffer.Length + 4;

			//-------------------------------------
			MemoryStream ms = new MemoryStream();
			ms.WriteUInt8(0x01);	//table id

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

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

			ms.WriteUInt16BE(0xffff);	//reserved, part 1

			byte byte3 = 0;
			byte3 |= 0xc0;	//reserved, part 2
			byte3 |= (byte)((versionNumber << 1) & 0xff);
			byte3 |= 0x01;	//current next indicator
			ms.WriteUInt8(byte3);

			ms.WriteUInt8(0x00);	//section number
			ms.WriteUInt8(0x00);	//last_section_number

			ms.Write(descriptorBuffer, 0, descriptorBuffer.Length);

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

			return ms.ToArray();
		}

		public void AddCaSystem(ushort caSystemId, ushort caPid, byte[] privateData)
		{
			CaDescriptor caDescriptor = new CaDescriptor(caSystemId, caPid, privateData);
			caDescriptors.Add(caDescriptor);
			versionNumber++;
		}
	}
}
