using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.IO;
using skyscraper5.Skyscraper.Plugins;

namespace skyscraper5.Scte35.Descriptors
{
	[SkyscraperPlugin]
	[TsDescriptor(0x02, "SCTE35")]
    public class SegmentationDescriptor : TsDescriptor
    {
        public SegmentationDescriptor(byte[] buffer)
        {
            MemoryStream ms = new MemoryStream(buffer, false);
            Identifier = ms.ReadUInt32BE();
            SegmentationEventId = ms.ReadUInt32BE();
            byte readUInt8 = ms.ReadUInt8();
            SegmentationEventCancelIndicator = (readUInt8 & 0x80) != 0;
            if (!SegmentationEventCancelIndicator)
            {
                readUInt8 = ms.ReadUInt8();
                ProgramSegmentationFlag = (readUInt8 & 0x80) != 0;
                SegmentationDurationFlag = (readUInt8 & 0x40) != 0;
                bool deliveryNotRestrictedFlag = (readUInt8 & 0x20) != 0;
                if (!deliveryNotRestrictedFlag)
                {
                    WebDeliveryFlag = (readUInt8 & 0x10) != 0;
                    NoRegionalBlackoutFlag = (readUInt8 & 0x08) != 0;
                    ArchiveAllowedFlag = (readUInt8 & 0x04) != 0;
                    DeviceRestrictions = (readUInt8 & 0x03);
                }
                else
                {
                    //reserved
                }

                if (!ProgramSegmentationFlag.Value)
                {
                    byte componentCount = ms.ReadUInt8();
                    Components = new Component[componentCount];
                    for (int i = 0; i < componentCount; i++)
                    {
                        Components[i] = new Component();
                        Components[i].ComponentTag = ms.ReadUInt8();
                        readUInt8 = ms.ReadUInt8();
                        Components[i].PtsOffset = ms.ReadUInt32BE();
                        Components[i].PtsOffset <<= 1;
                        Components[i].PtsOffset += (uint)(readUInt8 & 0x01);
                    }
                }

                if (SegmentationDurationFlag.Value)
                {
                    readUInt8 = ms.ReadUInt8();
                    SegmentationDuration = ms.ReadUInt32BE();
                    SegmentationDuration <<= 8;
                    SegmentationDuration += readUInt8;
                }

                SegmentationUpidType = ms.ReadUInt8();
                byte segmentationUpidLength = ms.ReadUInt8();
                SegmentationUpid = Encoding.ASCII.GetString(ms.ReadBytes(segmentationUpidLength));

                SegmentationTypeId = ms.ReadUInt8();
                SegmentNum = ms.ReadUInt8();
                SegmentsExpected = ms.ReadUInt8();
                if (SegmentationTypeId.Value == 0x34 || SegmentationTypeId.Value == 0x36 ||
                    SegmentationTypeId.Value == 0x38 || SegmentationTypeId.Value == 0x3a)
                {
                    SubSegmentNum = ms.ReadUInt8();
                    SubSegmentsExpected = ms.ReadUInt8();
                }
            }
        }

        public byte? SubSegmentsExpected { get; set; }

        public byte? SubSegmentNum { get; set; }

        public byte? SegmentsExpected { get; set; }

        public byte? SegmentNum { get; set; }

        public byte? SegmentationTypeId { get; set; }

        public string SegmentationUpid { get; set; }

        public byte? SegmentationUpidType { get; set; }

        public ulong? SegmentationDuration { get; set; }

        public Component[] Components { get; set; }

        public class Component
        {
            public byte ComponentTag { get; set; }
            public ulong PtsOffset { get; set; }
        }

        public bool? ProgramSegmentationFlag { get; set; }

        public bool SegmentationEventCancelIndicator { get; set; }

        public int? DeviceRestrictions { get; set; }

        public bool? ArchiveAllowedFlag { get; set; }

        public bool? NoRegionalBlackoutFlag { get; set; }

        public bool? WebDeliveryFlag { get; set; }

        public bool? SegmentationDurationFlag { get; set; }

        public uint SegmentationEventId { get; set; }

        public uint Identifier { get; set; }
    }
}
