using System.Collections.Generic;
using skyscraper5.Iso14496_1;
using skyscraper5.Iso14496_1.Descriptors;
using skyscraper5.Mpeg2.Descriptors;

namespace skyscraper5.Mpeg2.Psi.Model
{
    public class ProgramMapping
    {
        public ushort ProgramNumber { get; }
        public int PcrPid { get; }
        public List<ProgramMappingStream> Streams { get; }

        //from 0x0e maximum bitrrate descriptor
        public uint? MaximumBitrate { get; set; }

        //from 0x0c multiplex buffer utilization descriptor
        public bool? MultiplexBufferUtilizationBoundValidFlag { get; set; }
        public int? MultiplexLtwOffsetLowerBound { get; set; }
        public int? MultiplexLtwOffsetUpperBound { get; set; }
        
        //from 0x0b system clock descriptor
        public int? ClockAccuracyExponent { get; set; }
        public int? ClockAccuracyInteger { get; set; }
        public bool? ExternalClockReferenceIndicator { get; set; }
        
        //from 0x10 smoothing buffer descriptor
        public uint? SbLeakRate { get; set; }
        public uint? SbSize { get; set; }
        
        //from 0x09 ca system descriptor
        public int? CaPid { get; set; }
        public ushort? CaSystemId { get; set; }
        public byte[] CaPrivateData { get; set; }

        //from 0x5f private data specifier descriptor
        public uint? PrivateDataSpecifier { get; set; }

        //from 0x05 registration descriptor
        public byte[] RegistrationAdditionalIdentificationInfo { get; set; }
        public uint? RegistrationFormatIdentifier { get; set; }

        //from 0x60 service move descriptor
        public ushort? NewOriginalNetworkId { get; set; }
        public ushort? NewServiceId { get; set; }
        public ushort? NewTransportStreamId { get; set; }

        //from 0x52 stream identifier descriptor
        public byte? ComponentTag { get; set; }

        //from 0x38 metadata std descriptor
        public int? MetadataInputLeakRate { get; set; }
        public int? MetadataBufferSize { get; set; }
        public int? MetadataOutputLeakRate { get; set; }

        //from 0x65 scrambling descriptor
        public byte? ScramblingMode { get; set; }

        //from 0x1e sl descriptor
        public ushort? EsId { get; set; }

        //from 0x0a iso 639 language descriptor
        public AudioType? AudioType { get; set; }
        public string Iso639LanguageCode { get; set; }

        //from 0x1d iod descriptor
        public InitialObjectDescriptor InitialObjectDescriptor { get; set; }
        public byte? ScopeOfIodLabel { get; set; }
        public byte? IodLabel { get; set; }

        //from 0x0f private data indicator descriptor
        public uint? PrivateDataIndicator { get; set; }

        //From 0x02 video stream descriptor
        public double? FrameRate { get; set; }
        public int? ChromaFormat { get; set; }
        public bool? ConstrainedParameterFlag { get; set; }
        public int? FrameRateExtensionFlag { get; set; }
        public bool? Mpeg1OnlyFlag { get; set; }
        public bool? MultipleFramerateFlag { get; set; }
        public byte? ProfileAndLevelIndication { get; set; }
        public bool? StillPictureFlag { get; set; }

        //from 0x25 metadata pointer descriptor
        public ushort? MetadataProgramNumber { get; set; }
        public ushort? MetadataApplicationFormat { get; set; }
        public uint? MetadataApplicationFormatIdentifier { get; set; }
        public ushort? MetadataFormat { get; set; }
        public uint? MetadataFormatIdentifier { get; set; }
        public byte[] MetadataLocatorRecord { get; set; }
        public bool? MetadataLocatorRecordFlag { get; set; }
        public byte? MetadataServiceId { get; set; }
        public int? MpegCarriageFlag { get; set; }
        public byte[] MetadataPrivateData { get; set; }
        public ushort? TransportStreamId { get; set; }
        public ushort? TransportStreamLocation { get; set; }

        //From 0x03 audio stream descriptor
        public bool? FreeFormat { get; set; }
        public bool? AudioStreamId { get; set; }
        public int? Layer { get; set; }
        public bool? VariableRateAudio { get; set; }

        //from hdmv descriptor 0x88
        public byte[] CopyControlPrivateData { get; internal set; }

        //from 0x06 data stream alignment descriptor
        public byte? AlignmentType { get; internal set; }

        //from 0x04 hierarchy descriptory
        public int? HierarchyType { get; internal set; }
        public int? HierarchyLayerType { get; internal set; }
        public bool? TrefPresentFlag { get; internal set; }
        public int? HierarchyChannel { get; internal set; }
        public bool? NoViewScalabilityFlag { get; internal set; }
        public int? HierarchyEmbeddedLayerIndex { get; internal set; }
        public bool? NoQualityScalabilityFlag { get; internal set; }
        public bool? NoSpatialScalabilityFlag { get; internal set; }
        public bool? NoTemporalScalabilityFlag { get; internal set; }

        public ProgramMapping(ushort programNumber, int pcrPid)
        {
            ProgramNumber = programNumber;
            PcrPid = pcrPid;
            Streams = new List<ProgramMappingStream>();
        }

        protected bool Equals(ProgramMapping other)
        {
            return ProgramNumber == other.ProgramNumber;
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != this.GetType()) return false;
            return Equals((ProgramMapping)obj);
        }

        public override int GetHashCode()
        {
            return ProgramNumber.GetHashCode();
        }
    }
}
