using System.IO;
using skyscraper5.Skyscraper.IO;

namespace skyscraper5.Mpeg2.Psi
{
    class PatParser : IPsiProcessor
    {
        public IPatEventHandler PatEventHandler { get; }

        public PatParser(IPatEventHandler patEventHandler)
        {
            PatEventHandler = patEventHandler;
        }

        public void GatherPsi(PsiSection section, int sourcePid)
        {
            MemoryStream ms = new MemoryStream(section.GetDataCopy(), false);
            if (ms.GetAvailableBytes() < 8)
                return;
            byte tableId = ms.ReadUInt8();
            if (tableId != 0 || sourcePid != 0)
                return; //Discard if PAT from weird PID

            ushort readUInt16Be = ms.ReadUInt16BE();
            bool sectionSyntaxIndicator = (readUInt16Be & 0x8000) != 0;
            bool zero = (readUInt16Be & 0x4000) != 0;
            bool reserved = (readUInt16Be & 0x3000) != 0;
            int sectionLength = (readUInt16Be & 0x0fff);

            ushort transportStreamId = ms.ReadUInt16BE();
            if (sourcePid == 0)
                PatEventHandler.SetTransportStreamId(transportStreamId);

            byte readUInt8 = ms.ReadUInt8();
            int reserved2 = (readUInt8 & 0xc0) >> 6;
            int versionNumber = (readUInt8 & 0x3e) >> 1;
            bool currentNextIndicator = (readUInt8 & 0x01) != 0;

            byte sectionNumber = ms.ReadUInt8();
            byte lastSectionNumber = ms.ReadUInt8();

            long numProgs = ms.Length;
            numProgs -= 4; //for crc32
            numProgs -= 8; //already wasted
            numProgs /= 4; //length of each program

            for (long i = 0; i < numProgs; i++)
            {
                ushort programNumber = ms.ReadUInt16BE();
                readUInt16Be = ms.ReadUInt16BE();
                int reversed3 = (readUInt16Be & 0xe000) >> 13;

                if (programNumber == 0)
                {
                    int networkPid = (readUInt16Be & 0x1fff);
                    PatEventHandler?.NetworkPidFromPat(networkPid);
                }
                else
                {
                    int programMapPid = (readUInt16Be & 0x1fff);
                    PatEventHandler?.ProgramMapPidFromPat(programMapPid, programNumber);
                }
            }

        }
    }
}
