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

namespace skyscraper5.Mpeg2
{
    public class PsiSection
    {
        public int Need { get; internal set; }
        public bool HeaderComplete { get; internal set; }

        public ushort SectionLength
        {
            get
            {
                if (!HeaderComplete)
                    throw new DvbException("PSI Section not completed");

                byte[] databuffer = data.GetBuffer();
                MemoryStream subms = new MemoryStream(databuffer, 1, 2, false);
                ushort result = subms.ReadUInt16BE();
                result &= 0x0fff;
                return result;
            }
        }

        public bool Valid => Validate();

        public bool Validate()
        {
            if (!HeaderComplete)
                return false;

            bool validCrc32 = false;

            if (HasCrc32)
                validCrc32 = DvbCrc32.ValidatePsi(this);

            return !HasCrc32 || validCrc32;
        }

        public bool HasCrc32
        {
            get
            {
                if (TableId == 0x70 || TableId == 0x71 || TableId == 0x72 || TableId == 0x7E)
                    return false;

                return (SyntaxIndicator != 0) || TableId == 0x73;
            }
        }

        public int SyntaxIndicator
        {
            get
            {
                if (!HeaderComplete)
                    throw new DvbException("incomplete psi");

                int syntaxIndicator = data.GetBuffer()[1] & 0x80;
                return syntaxIndicator;
            }
        }

        public int TableId
        {
            get
            {
                if (!HeaderComplete)
                    throw new DvbException("header incomplete");

                int tableId = ((int)data.GetBuffer()[0]) & 0xff;
                return tableId;
            }
        }

        private MemoryStream data;
        private int receivedBytes;
        public void Append(byte[] temp1)
        {
            Append(temp1, 0, temp1.Length);
        }

        public void Append(byte[] temp1, int offset, int count)
        {
            if (data == null)
                data = new MemoryStream();
            data.Write(temp1, offset, count);
            receivedBytes += temp1.Length;
        }

        public byte[] GetData()
        {
            return data.GetBuffer();
        }

        public byte[] GetDataCopy()
        {
            return data.ToArray();
        }

        public int BytesContained => receivedBytes;

        internal static PsiSection FromByteArray(byte[] alreadyGathered)
        {
	        PsiSection child = new PsiSection();
	        child.data = new MemoryStream(alreadyGathered, false);
	        return child;
        }
    }
}
