using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.IO;
using skyscraper5.Skyscraper.Scraper.Utils;
using skyscraper5.src.Id3.Frames;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace skyscraper5.src.Id3
{
	internal class Id3PesProcessor : IPesProcessor
	{
		public Id3PesProcessor(Id3Handler handler)
		{
			this.handler = handler;
		}

		private Id3Handler handler;

		public void ProcessPesPacket(PesPacket packet)
		{
			if (packet.Payload == null)
			{
				handler.OnId3Error(Id3ErrorState.NullPacket);
				return;
			}
			
			MemoryStream ms = new MemoryStream(packet.Payload, false);
			if (ms.ReadUInt8() != 'I')
			{
				handler.OnId3Error(Id3ErrorState.InvalidMagic);
				return;
			}
			if (ms.ReadUInt8() != 'D')
			{
				handler.OnId3Error(Id3ErrorState.InvalidMagic);
				return;
			}
			if (ms.ReadUInt8() != '3')
			{
				handler.OnId3Error(Id3ErrorState.InvalidMagic);
				return;
			}

			byte major = ms.ReadUInt8();
			byte minor = ms.ReadUInt8();
			Version version = new Version(2, major, minor);
			Id3Tag frame = new Id3Tag(version);

			byte flags = ms.ReadUInt8();
			frame.Unsynchronisation = ((flags & 0x80) != 0);
			bool extendedHeaderPresent = ((flags & 0x40) != 0);
			frame.ExperimentalIndicator = ((flags & 0x20) != 0);
			bool footerPresent = ((flags & 0x10) != 0);

			uint size = ms.ReadUInt32BE();
			if (ms.GetAvailableBytes() < size)
			{
				handler.OnId3Error(Id3ErrorState.PacketTooShort);
				return;
			}

			if (extendedHeaderPresent)
			{
				throw new NotImplementedException("ID3 extended header");
			}

			long dataLeft = size;
			while (dataLeft > 0)
			{
				uint entryFourcc = ms.ReadUInt32BE();
				dataLeft -= 4;
				uint entrySize = ms.ReadUInt32BE();
				dataLeft -= 4;
				ushort entryFlags = ms.ReadUInt16BE();
				dataLeft -= 2;
				byte[] entryData = ms.ReadBytes(entrySize);
				dataLeft -= entrySize;

				Id3Frame child = null;
				switch(entryFourcc)
				{
					case 1347570006:    //PRIV
						child = new PrivateFrame(entryData, entryFlags);
						break;
					default:
						string v = Encoding.ASCII.GetString(BitConverter.GetBytes(entryFourcc));
						throw new NotImplementedException(String.Format("ID3 Frame {0}", v));
				}
				frame.Frames.Add(child);
			}
			handler.OnId3Tag(frame);
		}
	}
}
