/*  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.
 */

//---------------------------------------------------------------------------
// Pre-compilation
#include "MediaInfo/PreComp.h"
#ifdef __BORLANDC__
    #pragma hdrstop
#endif
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#include "MediaInfo/Setup.h"
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#if defined(MEDIAINFO_SDP_YES)
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#include "MediaInfo/Text/File_Sdp.h"
#include "MediaInfo/Text/File_Teletext.h"
#include "MediaInfo/MediaInfo_Config_MediaInfo.h"
//---------------------------------------------------------------------------

namespace MediaInfoLib
{

//***************************************************************************
// Constructor/Destructor
//***************************************************************************

//---------------------------------------------------------------------------
File_Sdp::File_Sdp()
:File__Analyze()
{
    //Configuration
    ParserName="SDP";
    #if MEDIAINFO_EVENTS
        ParserIDs[0]=MediaInfo_Parser_Sdp;
        StreamIDs_Width[0]=2;
    #endif //MEDIAINFO_EVENTS
    #if MEDIAINFO_TRACE
        Trace_Layers_Update(8); //Stream
    #endif //MEDIAINFO_TRACE
    PTS_DTS_Needed=true;
    MustSynchronize=true;
}

//---------------------------------------------------------------------------
File_Sdp::~File_Sdp()
{
}

//***************************************************************************
// Streams management
//***************************************************************************

//---------------------------------------------------------------------------
void File_Sdp::Streams_Fill()
{
    Fill(Stream_General, 0, General_Format, "SDP");
}

//---------------------------------------------------------------------------
void File_Sdp::Streams_Finish()
{
    for (streams::iterator Stream=Streams.begin(); Stream!=Streams.end(); ++Stream)
    {
        if (Stream->second.Parser)
        {
            Finish(Stream->second.Parser);
            for (size_t StreamKind=Stream_General+1; StreamKind<Stream_Max; StreamKind++)
                for (size_t StreamPos=0; StreamPos<Stream->second.Parser->Count_Get((stream_t)StreamKind); StreamPos++)
                {
                    Merge(*Stream->second.Parser, (stream_t)StreamKind, StreamPos, StreamPos);
                    Fill((stream_t)StreamKind, StreamPos, General_ID, Stream->second.Parser->Get((stream_t)StreamKind, StreamPos, General_ID), true);
                }
        }
    }
}

//***************************************************************************
// Buffer - Synchro
//***************************************************************************

//---------------------------------------------------------------------------
bool File_Sdp::Synchronize()
{
    auto Buffer_Current = Buffer_Offset;
    auto i = 0;
    const auto Count = IsSub ? 0 : 4; // Found one file with unknown bytes at the end of the stream, so removing this integrity test for the moment
    while (i <= Count) {
        if (Buffer_Current > Buffer_Size || Buffer_Size - Buffer_Current <= 2) {
            if (i
             && ((IsSub && Buffer_Current == Buffer_Size)
              || (File_Offset + Buffer_Offset < File_Size && File_Offset + Buffer_Size == File_Size))) {
                break;
            }
            return false; // Wait for more data
        }
        auto Identifier = BigEndian2int16u(Buffer + Buffer_Current);
        auto Length = BigEndian2int8u(Buffer + Buffer_Current + 2);
        if (Identifier != 0x5115 || Length < 9) {
            i = 0;
            Buffer_Current = ++Buffer_Offset;
            continue;
        }
        Buffer_Current += Length;
        ++i;
    }

    //Synched is OK
    if (!Status[IsAccepted]) {
        Accept();
    }
    return true;

    //Synchronizing
    for (; Buffer_Size - Buffer_Offset > 1; Buffer_Offset++)
    {
        auto Identifier = BigEndian2int16u(Buffer + Buffer_Offset);
        if (Identifier != 0x5115) {
            continue;
        }

        // Testing if size is coherent
        if (IsSub) {
            break; // Found one file with unknown bytes at the end of the stream, so removing this integrity test for the moment
        }
        if (Buffer_Size - Buffer_Offset <= 2) {
            return false; // Wait for more data
        }
        int8u Length = Buffer[Buffer_Offset + 2];
        if (Length < 9) {
            continue;
        }
        if (Buffer_Size - Buffer_Offset <= (size_t)Length + 1) {
            return false; // Wait for more data
        }
        auto Identifier2 = BigEndian2int16u(Buffer + Buffer_Offset + Length);
        if (Identifier2 != 0x5115) {
            continue;
        }

        break;
    }

    //Synched is OK
    if (!Status[IsAccepted]) {
        Accept();
    }
    return true;
}

//---------------------------------------------------------------------------
bool File_Sdp::Synched_Test()
{
    //Must have enough buffer for having header
    if (Buffer_Offset+3>Buffer_Size)
        return false;

    //Quick test of synchro
    if (Buffer[Buffer_Offset  ]!=0x51
     || Buffer[Buffer_Offset+1]!=0x15)
    {
        Synched=false;
        return true;
    }

    //We continue
    return true;
}

//***************************************************************************
// Buffer - Global
//***************************************************************************

//---------------------------------------------------------------------------
void File_Sdp::Read_Buffer_Unsynched()
{
    for (streams::iterator Stream=Streams.begin(); Stream!=Streams.end(); ++Stream)
    {
        if (Stream->second.Parser)
        {
            Stream->second.Parser->Open_Buffer_Unsynch();
        }
    }
}

//***************************************************************************
// Buffer - Elements
//***************************************************************************

//---------------------------------------------------------------------------
void File_Sdp::Header_Parse()
{
    //Parsing
    int8u Length, FormatCode;
    Skip_B2(                                                    "Identifier");
    Get_B1 (Length,                                             "Length");
    Get_B1 (FormatCode,                                         "Format Code");
    for (int8u Pos=0; Pos<5; Pos++)
    {
        FieldLines[Pos]=0;
        #if MEDIAINFO_TRACE
            Element_Begin1("Field/Line");
            BS_Begin();
            Info_SB(   Field,                                   "Field Number");
            Info_S1(2, Reserved,                                "Reserved");
            Info_S1(5, Line,                                    "Line Number");
            BS_End();
            FieldLines[Pos]=((Field?1:0)<<7) |(Reserved<<5) | Line; //Removing field information ((Field?1:0)<<7) |
            if (FieldLines[Pos])
            {
                Element_Info1(Field?2:1);
                Element_Info1(Line);
            }
            else
                Element_Info1("None");
            Element_End0();
        #else //MEDIAINFO_TRACE
            Get_B1(FieldLines[Pos],                             "Field/Line");
            FieldLines[Pos]&=0x7F; //Removing field information
        #endif //MEDIAINFO_TRACE
    }

    if (IsSub)
        Header_Fill_Size(Buffer_Size);
    else
        Header_Fill_Size(Length);
}

//---------------------------------------------------------------------------
void File_Sdp::Data_Parse()
{
    Element_Name("Packet");

    for (int8u Pos=0; Pos<5; Pos++)
    {
        if (FieldLines[Pos])
        {
            Element_Code=(int64u)-1;
            stream &Stream=Streams[0];
            if (Stream.Parser==NULL)
            {
                Stream.Parser=new File_Teletext();
                Open_Buffer_Init(Stream.Parser);
            }
            if (Stream.Parser->PTS_DTS_Needed)
                Stream.Parser->FrameInfo=FrameInfo;
            Demux(Buffer+Buffer_Offset+Element_Offset, 45, ContentType_MainStream);
            Open_Buffer_Continue(Stream.Parser, Buffer+Buffer_Offset+Element_Offset, 45);
            Element_Offset+=45;
        }
    }

    Element_Begin1("SDP Footer");
    Skip_B1(                                                    "Footer ID");
    Skip_B2(                                                    "Footer Sequence number");
    Skip_B1(                                                    "SDP Cheksum");
    if (Element_Offset<Element_Size)
        Skip_XX(Element_Size-Element_Offset,                    "Unknown, out of specs");
    Element_End0();
}

//***************************************************************************
// C++
//***************************************************************************

} //NameSpace

#endif //MEDIAINFO_SDP_YES
