/*  Copyright (c) MediaArea.net SARL. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license that can
 *  be found in the License.html file in the root of the source tree.
 */

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Information about MPEG files, Descriptors
//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//---------------------------------------------------------------------------
#ifndef MediaInfo_Mpeg_DescriptorsH
#define MediaInfo_Mpeg_DescriptorsH
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#include "MediaInfo/Multiple/File_Mpeg4_Descriptors.h"
#include "MediaInfo/Duplicate/File__Duplicate_MpegTs.h"
#if defined(MEDIAINFO_EIA608_YES) || defined(MEDIAINFO_EIA708_YES)
    #include "MediaInfo/File__Analyze.h"
#endif
#include <cfloat>
#include <set>
//---------------------------------------------------------------------------

namespace MediaInfoLib
{

//***************************************************************************
// Global object
//***************************************************************************

struct complete_stream
{
    //Global
    int16u transport_stream_id; //The processed transport_stream_id
    bool   transport_stream_id_IsValid; //The processed transport_stream_id
    Ztring original_network_name;
    Ztring network_name;
    Ztring Duration_Start;
    Ztring Duration_End;
    bool   Duration_End_IsUpdated;
    std::map<Ztring, Ztring> TimeZones; //Key is country code
#if defined(MEDIAINFO_EIA608_YES) || defined(MEDIAINFO_EIA708_YES)
    class service_desc_holder
    {
    public:
        File__Analyze::servicedescriptors* ServiceDescriptors;
        service_desc_holder() : ServiceDescriptors(NULL)
        {
        }
        ~service_desc_holder()
        {
            reset();
        }
        void Clone_Desc(File__Analyze::servicedescriptors* src)
        {
            if (src)
            {
                reset(new File__Analyze::servicedescriptors);
                *ServiceDescriptors = *src;
            }
            else
            {
                reset();
            }
        }
        void reset(File__Analyze::servicedescriptors* new_ptr = NULL)
        {
            if(ServiceDescriptors)
               delete ServiceDescriptors;
            ServiceDescriptors = new_ptr;
        }
    };
#endif
    //Per transport_stream
    struct transport_stream
#if defined(MEDIAINFO_EIA608_YES) || defined(MEDIAINFO_EIA708_YES)
        : public service_desc_holder
#endif
    {
        bool HasChanged;
        std::map<std::string, Ztring> Infos;
        struct program 
#if defined(MEDIAINFO_EIA608_YES) || defined(MEDIAINFO_EIA708_YES)
            : public service_desc_holder
#endif
        {
            bool HasChanged;
            std::map<std::string, Ztring> Infos;
            std::map<std::string, Ztring> ExtraInfos_Content;
            std::map<std::string, Ztring> ExtraInfos_Option;
            std::map<Ztring, Ztring> EPGs;
            std::vector<int16u> elementary_PIDs;
            size_t StreamPos; //Stream_Menu
            int32u registration_format_identifier;
            int16u pid;
            int16u PCR_PID;
            int16u source_id; //ATSC
            bool   source_id_IsValid;
            bool   IsParsed;
            bool   IsRegistered;
            bool   HasNotDisplayableStreams; //e.g. unknown stream, KLV, SCTE 35
            bool   Update_Needed_IsRegistered;
            bool   Update_Needed_StreamCount;
            bool   Update_Needed_StreamPos;
            bool   Update_Needed_Info;

            //DVB
            struct dvb_epg_block
            {
                struct event
                {
                    Ztring  start_time;
                    Ztring  duration;
                    struct short_event_
                    {
                        Ztring  event_name;
                        Ztring  text;
                    };
                    short_event_ short_event;
                    Ztring  content;
                    Ztring  running_status;
                };

                typedef std::map<int16u, event> events; //Key is event_id
                events Events; //Key is event_id
            };
            typedef std::map<int8u, dvb_epg_block> dvb_epg_blocks; //Key is table_id
            dvb_epg_blocks DVB_EPG_Blocks; //Key is table_id
            bool DVB_EPG_Blocks_IsUpdated;

            //SCTE 35
            struct scte35
            {
                struct segmentation
                {
                    struct segment
                    {
                        int8u Status; //If it is currently in the program: 0=Running, 1=Ended, 2=Early termination

                        segment()
                        {
                            Status=(int8u)-1;
                        }
                    };

                    typedef std::map<int8u, segment> segments; //Key is segmentation_type_id
                    segments Segments;
                    ;
                };

                typedef std::map<int32u, segmentation> segmentations; //Key is segmentation_event_id
                segmentations Segmentations;
                int16u  pid;

                scte35()
                {
                    pid=(int16u)-1;
                }
            };
            scte35* Scte35;

            //Constructor/Destructor
            program()
            :
                HasChanged(false),
                StreamPos((size_t)-1),
                registration_format_identifier(0x00000000),
                pid(0x00000),
                PCR_PID(0x0000),
                source_id((int16u)-1),
                source_id_IsValid(false),
                IsParsed(false),
                IsRegistered(false),
                HasNotDisplayableStreams(false),
                Update_Needed_IsRegistered(false),
                Update_Needed_StreamCount(false),
                Update_Needed_StreamPos(false),
                Update_Needed_Info(false),
                DVB_EPG_Blocks_IsUpdated(false),
                Scte35(NULL)
            {}

            program(const program& p)
            :
                HasChanged(p.HasChanged),
                Infos(p.Infos),
                ExtraInfos_Content(p.ExtraInfos_Content),
                ExtraInfos_Option(p.ExtraInfos_Option),
                EPGs(p.EPGs),
                elementary_PIDs(p.elementary_PIDs),
                StreamPos(p.StreamPos),
                registration_format_identifier(p.registration_format_identifier),
                pid(p.pid),
                PCR_PID(p.PCR_PID),
                source_id(p.source_id),
                source_id_IsValid(p.source_id_IsValid),
                IsParsed(p.IsParsed),
                IsRegistered(p.IsRegistered),
                HasNotDisplayableStreams(p.HasNotDisplayableStreams),
                Update_Needed_IsRegistered(p.Update_Needed_IsRegistered),
                Update_Needed_StreamCount(p.Update_Needed_StreamCount),
                Update_Needed_StreamPos(p.Update_Needed_StreamPos),
                Update_Needed_Info(p.Update_Needed_Info),
                DVB_EPG_Blocks_IsUpdated(p.DVB_EPG_Blocks_IsUpdated),
                Scte35(p.Scte35)
            {
                #if defined(MEDIAINFO_EIA608_YES) || defined(MEDIAINFO_EIA708_YES)
                Clone_Desc(p.ServiceDescriptors);
                #endif
            }

            program& operator=(const program& p)
            {
                #if defined(MEDIAINFO_EIA608_YES) || defined(MEDIAINFO_EIA708_YES)
                Clone_Desc(p.ServiceDescriptors);
                #endif
                HasChanged=p.HasChanged;
                Infos=p.Infos;
                ExtraInfos_Content=p.ExtraInfos_Content;
                ExtraInfos_Option=p.ExtraInfos_Option;
                EPGs=p.EPGs;
                elementary_PIDs=p.elementary_PIDs;
                StreamPos=p.StreamPos;
                registration_format_identifier=p.registration_format_identifier;
                pid=p.pid;
                PCR_PID=p.PCR_PID;
                source_id=p.source_id;
                source_id_IsValid=p.source_id_IsValid;
                IsParsed=p.IsParsed;
                IsRegistered=p.IsRegistered;
                HasNotDisplayableStreams=p.HasNotDisplayableStreams;
                Update_Needed_IsRegistered=p.Update_Needed_IsRegistered;
                Update_Needed_StreamCount=p.Update_Needed_StreamCount;
                Update_Needed_StreamPos=p.Update_Needed_StreamPos;
                Update_Needed_Info=p.Update_Needed_Info;
                DVB_EPG_Blocks_IsUpdated=p.DVB_EPG_Blocks_IsUpdated;
                Scte35=p.Scte35;

                return *this;
            }
        };
        typedef std::map<int16u, program> programs; //Key is program_number
        programs Programs; //Key is program_number
        std::vector<int16u> programs_List;
        size_t   Programs_NotParsedCount;

        //Per IOD
        struct iod_es
        {
            File__Analyze*                                  Parser;
            #ifdef MEDIAINFO_MPEG4_YES
                File_Mpeg4_Descriptors::slconfig*           SLConfig;
            #endif

            //Constructor/Destructor
            iod_es()
            {
                Parser=NULL;
                #ifdef MEDIAINFO_MPEG4_YES
                    SLConfig=NULL;
                #endif
            }

            ~iod_es()
            {
                delete Parser; //Parser=NULL;
                #ifdef MEDIAINFO_MPEG4_YES
                    delete SLConfig; //SLConfig=NULL;
                #endif
            }
        };
        typedef std::map<int16u, iod_es> iod_ess; //Key is ES_ID
        std::map<int16u, iod_es> IOD_ESs; //Key is ES_ID

        //ATSC
        int16u source_id; //Global
        bool   source_id_IsValid;

        transport_stream()
        {
            HasChanged=false;
            source_id=(int16u)-1;
            source_id_IsValid=false;
            Programs_NotParsedCount=(size_t)-1;
        }
    };
    typedef std::map<int16u, transport_stream> transport_streams; //Key is transport_stream_id
    transport_streams Transport_Streams; //Key is transport_stream_id

    //Per pid
    struct stream
    {
        File__Analyze*                              Parser;

        enum ts_kind
        {
            //MPEG
            unknown,
            pes,
            psi,
            ts_kind_Max,
        };
        std::vector<int16u>                         program_numbers;
        struct table_id
        {
            struct table_id_extension
            {
                typedef std::vector<bool>           section_numbers; //Key is section_number
                section_numbers                     Section_Numbers; //Key is section_number
                int8u version_number;
            };
            typedef std::map<int16u, table_id_extension> table_id_extensions; //Key is table_id_extensions
            table_id_extensions                     Table_ID_Extensions; //Key is table_id_extensions
            bool                                    Table_ID_Extensions_CanAdd;

            table_id()
            {
                Table_ID_Extensions_CanAdd=true;
            }
        };
        typedef std::vector<table_id*>              table_ids;
        table_ids                                   Table_IDs; //Key is table_id
        std::map<std::string, Ztring>               Infos;
        std::map<std::string, Ztring>               Infos_Option;
        #if defined(MEDIAINFO_TELETEXT_YES)
            std::map<int16u, File__Analyze::teletext> Teletexts; //Key is teletext_magazine_number;
        #endif
        #if MEDIAINFO_TRACE
            Ztring Element_Info1;
        #endif //MEDIAINFO_TRACE
        stream_t                                    StreamKind;
        stream_t                                    StreamKind_FromDescriptor;
        size_t                                      StreamPos;
        ts_kind                                     Kind;
        bool                                        IsParsed;
        bool                                        IsPCR;
        float64                                     IsPCR_Duration;
        #ifdef MEDIAINFO_MPEGTS_PCR_YES
            int64u                                  TimeStamp_Start;
            int64u                                  TimeStamp_Start_Offset;
            int64u                                  TimeStamp_End;
            int64u                                  TimeStamp_End_Offset;
            int16u                                  PCR_PID; //If this pid has no PCR, decide which PCR should be used
            bool                                    TimeStamp_End_IsUpdated;
            float64                                 TimeStamp_InstantaneousBitRate_Current_Min;
            float64                                 TimeStamp_InstantaneousBitRate_Current_Raw;
            float64                                 TimeStamp_InstantaneousBitRate_Current_Max;
            int64u                                  TimeStamp_InstantaneousBitRate_BitRateMode_IsCbr;
            int64u                                  TimeStamp_InstantaneousBitRate_BitRateMode_IsVbr;
            #if MEDIAINFO_ADVANCED
                float64                             TimeStamp_InstantaneousBitRate_Min_Raw;
                float64                             TimeStamp_InstantaneousBitRate_Max_Raw;
                int64u                              TimeStamp_Distance_Min;
                int64u                              TimeStamp_Distance_Max;
                int64u                              TimeStamp_Distance_Total;
                int64u                              TimeStamp_Distance_Count;
                int64u                              TimeStamp_HasProblems;
                std::vector<int64u>                 TimeStamp_Intermediate;
            #endif // MEDIAINFO_ADVANCED
        #endif //MEDIAINFO_MPEGTS_PCR_YES
        int32u                                      registration_format_identifier;
        int16u                                      FMC_ES_ID;
        int16u                                      table_type; //ATSC
        int8u                                       stream_type;
        int8u                                       descriptor_tag;
        int8u                                       DtsNeural_config_id;
        bool                                        FMC_ES_ID_IsValid;
        bool                                        Searching;
        bool                                        Searching_Payload_Start;
        bool                                        Searching_Payload_Continue;
        #ifdef MEDIAINFO_MPEGTS_PCR_YES
            bool                                    Searching_TimeStamp_Start;
            bool                                    Searching_TimeStamp_End;
        #endif //MEDIAINFO_MPEGTS_PCR_YES
        #ifdef MEDIAINFO_MPEGTS_PESTIMESTAMP_YES
            bool                                    Searching_ParserTimeStamp_Start;
            bool                                    Searching_ParserTimeStamp_End;
        #endif //MEDIAINFO_MPEGTS_PESTIMESTAMP_YES
        bool                                        EndTimeStampMoreThanxSeconds;
        bool                                        ShouldDuplicate;
        bool                                        IsRegistered;
        bool                                        IsUpdated_IsRegistered;
        bool                                        IsUpdated_Info;
        bool                                        CA_system_ID_MustSkipSlices;
        bool                                        EBP_Marker_Detected;
        size_t                                      Scrambled_Count;
        int16u                                      CA_system_ID;
        int16u                                      SubStream_pid;
        #if MEDIAINFO_IBIUSAGE
            int64u                                  Ibi_SynchronizationOffset_BeginOfFrame;
        #endif //MEDIAINFO_IBIUSAGE
        #if defined(MEDIAINFO_EIA608_YES) || defined(MEDIAINFO_EIA708_YES)
            File__Analyze::servicedescriptors ServiceDescriptors;
            bool                              ServiceDescriptors_IsPresent;
        #endif

        //Constructor/Destructor
        stream()
        {
            Parser=NULL;
            StreamKind=Stream_Max;
            StreamKind_FromDescriptor=Stream_Max;
            StreamPos=(size_t)-1;
            Kind=unknown;
            IsParsed=false;
            IsPCR=false;
            IsPCR_Duration=0;
            #ifdef MEDIAINFO_MPEGTS_PCR_YES
                TimeStamp_Start=(int64u)-1;
                TimeStamp_Start_Offset=(int64u)-1;
                TimeStamp_End=(int64u)-1;
                TimeStamp_End_Offset=(int64u)-1;
                PCR_PID=0x0000;
                TimeStamp_End_IsUpdated=false;
                TimeStamp_InstantaneousBitRate_Current_Min=0;
                TimeStamp_InstantaneousBitRate_Current_Raw=0;
                TimeStamp_InstantaneousBitRate_Current_Max=0;
                TimeStamp_InstantaneousBitRate_BitRateMode_IsCbr=0;
                TimeStamp_InstantaneousBitRate_BitRateMode_IsVbr=0;
                #if MEDIAINFO_ADVANCED
                    TimeStamp_InstantaneousBitRate_Min_Raw=DBL_MAX;
                    TimeStamp_InstantaneousBitRate_Max_Raw=0;
                    TimeStamp_Distance_Min=(int64u)-1;
                    TimeStamp_Distance_Max=0;
                    TimeStamp_Distance_Total=0;
                    TimeStamp_Distance_Count=0;
                    TimeStamp_HasProblems=0;
                #endif // MEDIAINFO_ADVANCED
            #endif //MEDIAINFO_MPEGTS_PCR_YES
            registration_format_identifier=0x00000000;
            FMC_ES_ID=0x0000;
            table_type=0x0000;
            stream_type=(int8u)-1;
            descriptor_tag=(int8u)-1;
            DtsNeural_config_id=(int8u)-1;
            FMC_ES_ID_IsValid=false;
            Searching=false;
            Searching_Payload_Start=false;
            Searching_Payload_Continue=false;
            #ifdef MEDIAINFO_MPEGTS_PCR_YES
                Searching_TimeStamp_Start=false;
                Searching_TimeStamp_End=false;
            #endif //MEDIAINFO_MPEGTS_PCR_YES
            #ifdef MEDIAINFO_MPEGTS_PESTIMESTAMP_YES
                Searching_ParserTimeStamp_Start=false;
                Searching_ParserTimeStamp_End=false;
            #endif //MEDIAINFO_MPEGTS_PESTIMESTAMP_YES
            EndTimeStampMoreThanxSeconds=false;
            ShouldDuplicate=false;
            IsRegistered=false;
            IsUpdated_IsRegistered=false;
            IsUpdated_Info=false;
            Scrambled_Count=0;
            CA_system_ID_MustSkipSlices=false;
            CA_system_ID=0x0000;
            EBP_Marker_Detected=false;
            SubStream_pid=0x0000;
            #if MEDIAINFO_IBIUSAGE
                Ibi_SynchronizationOffset_BeginOfFrame=(int64u)-1;
            #endif //MEDIAINFO_IBIUSAGE
            #if defined(MEDIAINFO_EIA608_YES) || defined(MEDIAINFO_EIA708_YES)
                ServiceDescriptors_IsPresent=false;
            #endif
        }

        ~stream()
        {
            delete Parser; //Parser=NULL;
            for (size_t Pos=0; Pos<Table_IDs.size(); Pos++)
                delete Table_IDs[Pos]; //Table_IDs[Pos]=NULL;
        }

        //Helpers
        void Searching_Payload_Start_Set(bool ToSet)
        {
            Searching_Payload_Start=ToSet;
            Searching_Test();
        }
        void Searching_Payload_Continue_Set(bool ToSet)
        {
            Searching_Payload_Continue=ToSet;
            Searching_Test();
        }
        #ifdef MEDIAINFO_MPEGTS_PCR_YES
            void Searching_TimeStamp_Start_Set(bool ToSet)
            {
                Searching_TimeStamp_Start=ToSet;
                Searching_Test();
            }
            void Searching_TimeStamp_End_Set(bool ToSet)
            {
                Searching_TimeStamp_End=ToSet;
                Searching_Test();
            }
        #endif //MEDIAINFO_MPEGTS_PCR_YES
        #ifdef MEDIAINFO_MPEGTS_PESTIMESTAMP_YES
            void Searching_ParserTimeStamp_Start_Set(bool ToSet)
            {
                Searching_ParserTimeStamp_Start=ToSet;
                Searching_Test();
            }
            void Searching_ParserTimeStamp_End_Set(bool ToSet)
            {
                Searching_ParserTimeStamp_End=ToSet;
                Searching_Test();
            }
        #endif //MEDIAINFO_MPEGTS_PESTIMESTAMP_YES
        void Searching_Test()
        {
            Searching=Searching_Payload_Start
                    | Searching_Payload_Continue
                    #ifdef MEDIAINFO_MPEGTS_PCR_YES
                    | Searching_TimeStamp_Start
                    | Searching_TimeStamp_End
                    #endif //MEDIAINFO_MPEGTS_PCR_YES
                    #ifdef MEDIAINFO_MPEGTS_PESTIMESTAMP_YES
                        | Searching_ParserTimeStamp_Start
                        | Searching_ParserTimeStamp_End
                    #endif //MEDIAINFO_MPEGTS_PESTIMESTAMP_YES
                    ;
        }
        void init(const size_t ID)
        {
            Searching_Payload_Start_Set(true);
            Kind = complete_stream::stream::psi;
            Table_IDs.resize(0x100);
            Table_IDs[ID] = new complete_stream::stream::table_id;
        }
    };
    typedef std::vector<stream*> streams;
    streams Streams; //Key is pid
    size_t Streams_NotParsedCount;
    size_t Streams_With_StartTimeStampCount;
    size_t Streams_With_EndTimeStampMoreThanxSecondsCount;

    //ATSC
    int8u GPS_UTC_offset;
    struct source 
    {
        std::map<int16u, Ztring> texts;
        struct atsc_epg_block
        {
            struct event 
#if defined(MEDIAINFO_EIA608_YES) || defined(MEDIAINFO_EIA708_YES)
                : public service_desc_holder
#endif
            {
                int32u  start_time;
                Ztring  duration;
                Ztring  title;
                std::map<int16u, Ztring> texts;

                event() : start_time((int32u)-1)
                {}

                event(const event& e)
                :
                    start_time(e.start_time)
                {
                    #if defined(MEDIAINFO_EIA608_YES) || defined(MEDIAINFO_EIA708_YES)
                    Clone_Desc(e.ServiceDescriptors);
                    #endif
                }
                event& operator=(const event& e)
                {
                    #if defined(MEDIAINFO_EIA608_YES) || defined(MEDIAINFO_EIA708_YES)
                    Clone_Desc(e.ServiceDescriptors);
                    #endif
                    start_time=e.start_time;

                    return *this;
                }
            };

            typedef std::map<int16u, event> events; //Key is event_id
            events Events; //Key is event_id
        };
        typedef std::map<int16u, atsc_epg_block> atsc_epg_blocks; //Key is table_id
        atsc_epg_blocks ATSC_EPG_Blocks; //Key is table_id
        bool ATSC_EPG_Blocks_IsUpdated;

        source()
        {
            ATSC_EPG_Blocks_IsUpdated=false;
        }
    };
    typedef std::map<int16u, source> sources; //Key is source_id
    sources Sources; //Key is source_id
    bool Sources_IsUpdated; //For EPG ATSC
    bool Programs_IsUpdated; //For EPG DVB

    //File__Duplicate
    #if MEDIAINFO_DUPLICATE
    bool                                                File__Duplicate_HasChanged_;
    size_t                                              Config_File_Duplicate_Get_AlwaysNeeded_Count;
    std::vector<File__Duplicate_MpegTs*>                Duplicates_Speed;
    std::vector<std::vector<File__Duplicate_MpegTs*> >  Duplicates_Speed_FromPID;
    std::map<const String, File__Duplicate_MpegTs*>     Duplicates;
    bool File__Duplicate_Get_From_PID (int16u pid) const
    {
        if (Duplicates_Speed_FromPID.empty())
            return false;
        return !Duplicates_Speed_FromPID[pid].empty();
    }
    #endif //MEDIAINFO_DUPLICATE

    //SpeedUp information
    std::vector<std::vector<size_t> >   StreamPos_ToRemove;
    std::map<int16u, int16u>            PCR_PIDs; //Key is PCR_PID, value is count of programs using it
    std::set<int16u>                    PES_PIDs; //Key is pid
    std::vector<int16u>                 program_number_Order;

    //Constructor/Destructor
    complete_stream()
    {
        transport_stream_id=(int16u)-1;
        transport_stream_id_IsValid=false;
        Duration_End_IsUpdated=false;
        Streams_NotParsedCount=(size_t)-1;
        Streams_With_StartTimeStampCount=0;
        Streams_With_EndTimeStampMoreThanxSecondsCount=0;
        GPS_UTC_offset=0;
        Sources_IsUpdated=false;
        Programs_IsUpdated=false;
        StreamPos_ToRemove.resize(Stream_Max);
        #if MEDIAINFO_DUPLICATE
        File__Duplicate_HasChanged_ = false;
        Config_File_Duplicate_Get_AlwaysNeeded_Count = 0;
        #endif //MEDIAINFO_DUPLICATE
    }

    ~complete_stream()
    {
        for (size_t StreamID=0; StreamID<Streams.size(); StreamID++)
            delete Streams[StreamID]; //Streams[StreamID]=NULL;

        #if MEDIAINFO_DUPLICATE
        std::map<const String, File__Duplicate_MpegTs*>::iterator Duplicates_Temp=Duplicates.begin();
        while (Duplicates_Temp!=Duplicates.end())
        {
            delete Duplicates_Temp->second; //Duplicates_Temp->second=NULL
            ++Duplicates_Temp;
        }
        #endif //MEDIAINFO_DUPLICATE
    }
};

//***************************************************************************
// Class File_Mpeg_Descriptors
//***************************************************************************

class File_Mpeg_Descriptors : public File__Analyze
{
public :
    //In
    complete_stream* Complete_Stream;
    int16u transport_stream_id;
    int16u pid;
    int8u  table_id;
    int16u table_id_extension;
    int16u elementary_PID;
    int16u program_number;
    int32u registration_format_identifier;
    int8u  stream_type;
    int16u event_id;
    bool   elementary_PID_IsValid;
    bool   program_number_IsValid;
    bool   registration_format_identifier_IsValid;
    bool   stream_type_IsValid;
    bool   event_id_IsValid;

    //Out

    //Constructor/Destructor
    File_Mpeg_Descriptors();

private :
    //Buffer - File header
    void FileHeader_Parse();

    //Buffer - Per element
    void Header_Parse();
    void Data_Parse();

    //Elements
    void Descriptors();
    void Descriptor();
    void Descriptor_00() {Skip_XX(Element_Size, "Data");};
    void Descriptor_01() {Skip_XX(Element_Size, "Data");};
    void Descriptor_02();
    void Descriptor_03();
    void Descriptor_04() {Skip_XX(Element_Size, "Data");};
    void Descriptor_05();
    void Descriptor_06();
    void Descriptor_07();
    void Descriptor_08();
    void Descriptor_09();
    void Descriptor_0A();
    void Descriptor_0B();
    void Descriptor_0C() {Skip_XX(Element_Size, "Data");};
    void Descriptor_0D();
    void Descriptor_0E();
    void Descriptor_0F();
    void Descriptor_10();
    void Descriptor_11();
    void Descriptor_12() {Skip_XX(Element_Size, "Data");};
    void Descriptor_13() {Skip_XX(Element_Size, "Data");};
    void Descriptor_14() {Skip_XX(Element_Size, "Data");};
    void Descriptor_15() {Skip_XX(Element_Size, "Data");};
    void Descriptor_16() {Skip_XX(Element_Size, "Data");};
    void Descriptor_17() {Skip_XX(Element_Size, "Data");};
    void Descriptor_18() {Skip_XX(Element_Size, "Data");};
    void Descriptor_19() {Skip_XX(Element_Size, "Data");};
    void Descriptor_1A() {Skip_XX(Element_Size, "Data");};
    void Descriptor_1B() {Skip_XX(Element_Size, "Data");};
    void Descriptor_1C();
    void Descriptor_1D();
    void Descriptor_1E() {Skip_XX(Element_Size, "Data");};
    void Descriptor_1F();
    void Descriptor_20() {Skip_XX(Element_Size, "Data");};
    void Descriptor_21() {Skip_XX(Element_Size, "Data");};
    void Descriptor_22() {Skip_XX(Element_Size, "Data");};
    void Descriptor_23() {Skip_XX(Element_Size, "Data");};
    void Descriptor_24() {Skip_XX(Element_Size, "Data");};
    void Descriptor_25() {Skip_XX(Element_Size, "Data");};
    void Descriptor_26() {Skip_XX(Element_Size, "Data");};
    void Descriptor_27() {Skip_XX(Element_Size, "Data");};
    void Descriptor_28();
    void Descriptor_29() {Skip_XX(Element_Size, "Data");};
    void Descriptor_2A();
    void Descriptor_2B() {Skip_XX(Element_Size, "Data");};
    void Descriptor_2C() {Skip_XX(Element_Size, "Data");};
    void Descriptor_2D() {Skip_XX(Element_Size, "Data");};
    void Descriptor_2E() {Skip_XX(Element_Size, "Data");};
    void Descriptor_2F();
    void Descriptor_30() {Skip_XX(Element_Size, "Data");};
    void Descriptor_31() {Skip_XX(Element_Size, "Data");};
    void Descriptor_32() {Skip_XX(Element_Size, "Data");};
    void Descriptor_33() {Skip_XX(Element_Size, "Data");};
    void Descriptor_34() {Skip_XX(Element_Size, "Data");};
    void Descriptor_35() {Skip_XX(Element_Size, "Data");};
    void Descriptor_36() {Skip_XX(Element_Size, "Data");};
    void Descriptor_37() {Skip_XX(Element_Size, "Data");};
    void Descriptor_38();
    void Descriptor_39();
    void Descriptor_3F();
    void Descriptor_3F_00() {Skip_XX(Element_Size-Element_Offset, "Data");};
    void Descriptor_3F_01() {Skip_XX(Element_Size-Element_Offset, "Data");};
    void Descriptor_3F_02() {Skip_XX(Element_Size-Element_Offset, "Data");};
    void Descriptor_3F_03();
    void Descriptor_3F_04() {Skip_XX(Element_Size-Element_Offset, "Data");};
    void Descriptor_3F_05() {Skip_XX(Element_Size-Element_Offset, "Data");};
    void Descriptor_3F_06() {Skip_XX(Element_Size-Element_Offset, "Data");};
    void Descriptor_3F_07() {Skip_XX(Element_Size-Element_Offset, "Data");};
    void Descriptor_3F_08();
    void Descriptor_3F_09() {Skip_XX(Element_Size-Element_Offset, "Data");};
    void Descriptor_3F_0A() {Skip_XX(Element_Size-Element_Offset, "Data");};
    void Descriptor_3F_0B() {Skip_XX(Element_Size-Element_Offset, "Data");};
    void Descriptor_3F_0C() {Skip_XX(Element_Size-Element_Offset, "Data");};
    void Descriptor_3F_0D() {Skip_XX(Element_Size-Element_Offset, "Data");};
    void Descriptor_3F_0E() {Skip_XX(Element_Size-Element_Offset, "Data");};
    void Descriptor_3F_0F() {Skip_XX(Element_Size-Element_Offset, "Data");};
    void Descriptor_3F_10() {Skip_XX(Element_Size-Element_Offset, "Data");};
    void Descriptor_3F_11() {Skip_XX(Element_Size-Element_Offset, "Data");};
    void Descriptor_3F_12() {Skip_XX(Element_Size-Element_Offset, "Data");};
    void Descriptor_3F_13() {Skip_XX(Element_Size-Element_Offset, "Data");};
    void Descriptor_3F_14();
    void Descriptor_40();
    void Descriptor_41();
    void Descriptor_42() {Skip_XX(Element_Size, "Data");};
    void Descriptor_43();
    void Descriptor_44() {Skip_XX(Element_Size, "Data");};
    void Descriptor_45() {Skip_XX(Element_Size, "Data");};
    void Descriptor_46() {Skip_XX(Element_Size, "Data");};
    void Descriptor_47() {Skip_XX(Element_Size, "Data");};
    void Descriptor_48();
    void Descriptor_49() {Skip_XX(Element_Size, "Data");};
    void Descriptor_4A();
    void Descriptor_4B() {Skip_XX(Element_Size, "Data");};
    void Descriptor_4C() {Skip_XX(Element_Size, "Data");};
    void Descriptor_4D();
    void Descriptor_4E() {Skip_XX(Element_Size, "Data");};
    void Descriptor_4F() {Skip_XX(Element_Size, "Data");};
    void Descriptor_50();
    void Descriptor_51() {Skip_XX(Element_Size, "Data");};
    void Descriptor_52();
    void Descriptor_53() {Skip_XX(Element_Size, "Data");};
    void Descriptor_54();
    void Descriptor_55();
    void Descriptor_56();
    void Descriptor_57() {Skip_XX(Element_Size, "Data");};
    void Descriptor_58();
    void Descriptor_59();
    void Descriptor_5A();
    void Descriptor_5B() {Skip_XX(Element_Size, "Data");};
    void Descriptor_5C() {Skip_XX(Element_Size, "Data");};
    void Descriptor_5D();
    void Descriptor_5E() {Skip_XX(Element_Size, "Data");};
    void Descriptor_5F();
    void Descriptor_60() {Skip_XX(Element_Size, "Data");};
    void Descriptor_61() {Skip_XX(Element_Size, "Data");};
    void Descriptor_62() {Skip_XX(Element_Size, "Data");};
    void Descriptor_63();
    void Descriptor_64() {Skip_XX(Element_Size, "Data");};
    void Descriptor_65() {Skip_XX(Element_Size, "Data");};
    void Descriptor_66();
    void Descriptor_67() {Skip_XX(Element_Size, "Data");};
    void Descriptor_68() {Skip_XX(Element_Size, "Data");};
    void Descriptor_69() {Skip_XX(Element_Size, "Data");};
    void Descriptor_6A();
    void Descriptor_6B() {Skip_XX(Element_Size, "Data");};
    void Descriptor_6C() {Skip_XX(Element_Size, "Data");};
    void Descriptor_6D() {Skip_XX(Element_Size, "Data");};
    void Descriptor_6E() {Skip_XX(Element_Size, "Data");};
    void Descriptor_6F() {Skip_XX(Element_Size, "Data");};
    void Descriptor_70() {Skip_XX(Element_Size, "Data");};
    void Descriptor_71() {Skip_XX(Element_Size, "Data");};
    void Descriptor_72() {Skip_XX(Element_Size, "Data");};
    void Descriptor_73() {Skip_XX(Element_Size, "Data");};
    void Descriptor_74() {Skip_XX(Element_Size, "Data");};
    void Descriptor_75() {Skip_XX(Element_Size, "Data");};
    void Descriptor_76() {Skip_XX(Element_Size, "Data");};
    void Descriptor_77() {Skip_XX(Element_Size, "Data");};
    void Descriptor_78() {Skip_XX(Element_Size, "Data");};
    void Descriptor_79() {Skip_XX(Element_Size, "Data");};
    void Descriptor_7A();
    void Descriptor_7B();
    void Descriptor_7C();
    void Descriptor_7D() {Skip_XX(Element_Size, "Data");};
    void Descriptor_7E() {Skip_XX(Element_Size, "Data");};
    void Descriptor_7F();
    void Descriptor_7F_06();
    void Descriptor_7F_0F();
    void Descriptor_7F_15();
    void Descriptor_7F_19();
    void Descriptor_80() {Skip_XX(Element_Size, "Data");};
    void Descriptor_81();
    void Descriptor_86();
    void Descriptor_87();
    void Descriptor_A0();
    void Descriptor_A1();
    void Descriptor_A2() {Skip_XX(Element_Size, "Data");};
    void Descriptor_A3();
    void Descriptor_A8() {Skip_XX(Element_Size, "Data");};
    void Descriptor_A9() {Skip_XX(Element_Size, "Data");};
    void Descriptor_AA();
    void Descriptor_AB() {Skip_XX(Element_Size, "Data");};
    void Descriptor_B0();
    void Descriptor_C1();
    void Descriptor_C4() {Skip_XX(Element_Size, "Data");};
    void Descriptor_C8();
    void Descriptor_DE();
    void Descriptor_E9();
    void Descriptor_FC();
    void Descriptor_FD();

    //SCTE 35
    void CUEI_00();
    void CUEI_01();
    void CUEI_02();

    //Helpers
    void ATSC_multiple_string_structure(Ztring &Value, const char* Info);
    void Get_DVB_Text(int64u Size, int32u LanguageCode, Ztring &Value, const char* Info);
    void Skip_DVB_Text(int64u Size, int32u LanguageCode, const char* Info) {Ztring Temp; Get_DVB_Text(Size, LanguageCode, Temp, Info);};
    static Ztring TimeHHMM_BCD(int16u Time);
    static Ztring Frequency_DVB__BCD(int32u Frequency);
    static Ztring OrbitalPosition_DVB__BCD(int32u OrbitalPosition);
};

} //NameSpace

#endif
