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

namespace skyscraper5.Mpeg2.Psi
{
    class CatParser : IPsiProcessor
    {
        public ICatEventHandler EventHandler { get; }

        public CatParser(ICatEventHandler eventHandler)
        {
            EventHandler = eventHandler;
        }

        public void GatherPsi(PsiSection section, int sourcePid)
        {
            MemoryStream ms = new MemoryStream(section.GetDataCopy());
            if (ms.GetAvailableBytes() < 9)
                return;
            byte tableId = ms.ReadUInt8();
            if (tableId != 0x01)
                return;

            ushort readUInt16Be = ms.ReadUInt16BE();
            bool sectionSyntaxSelector = (readUInt16Be & 0x8000) != 0;
            if (!sectionSyntaxSelector)
                return;
            int sectionLength = readUInt16Be & 0x0fff;

            ms.ReadUInt16BE(); //16 of 18 reversed bits
            byte readUInt8 = ms.ReadUInt8();
            int versionNumber = (readUInt8 & 0x3e) >> 1;
            bool currentNextIndicator = (readUInt8 & 0x01) != 0;

            byte sectionNumber = ms.ReadUInt8();

            byte lastSectionNumber = ms.ReadUInt8();

            long availableBytes = ms.GetAvailableBytes() - 4;
            byte[] descriptors = ms.ReadBytes(availableBytes);
            IEnumerable<TsDescriptor> unpackDescriptors = TsDescriptorUnpacker.GetInstance().UnpackDescriptors(descriptors, "CAT");

            uint? privateDataSpecifier = null;
            foreach (TsDescriptor dvbDescriptor in unpackDescriptors)
            {
                string name = dvbDescriptor.GetType().Name;
                switch (name)
                {
                    case nameof(CaDescriptor):
                        CaDescriptor caDescriptor = (CaDescriptor)dvbDescriptor;
                        EventHandler.NotifyOfCaSystem(caDescriptor);
                        break;
                    case nameof(StuffingDescriptor):
                        break;
                    case nameof(UserDefinedDescriptor):
                        UserDefinedDescriptor udd = (UserDefinedDescriptor)dvbDescriptor;
                        if (!privateDataSpecifier.HasValue)
                            continue;
                        TsDescriptor unpackedDescriptor = UserDefinedDescriptorUnpacker.GetInstance().UnpackUserDefinedDescriptor(udd, privateDataSpecifier.Value, "CAT");
                        if (unpackedDescriptor != null)
                            continue;
                        throw new NotImplementedException();
                    default:
                        throw new NotImplementedException(name);
                }
            }

            uint crc32 = ms.ReadUInt32BE();
        }
    }
}
