// Copyright (C) 2003-2024 VLC authors and VideoLAN
// SPDX-License-Identifier: LGPL-2.1-or-later
//
// chapter_command_script.cpp : Matroska Script Codec for Matroska Chapter Codecs
// Authors: Laurent Aimar <fenrir@via.ecp.fr>
//          Steve Lhomme <steve.lhomme@free.fr>


#include "chapter_command_script.hpp"
#include "virtual_segment.hpp"

namespace mkv {

#define M_MS_MAX_DEPTH 8
//Matroska Script
const std::string matroska_script_interpretor_c::CMD_MS_GOTO_AND_PLAY = "GotoAndPlay";

// see http://www.matroska.org/technical/specs/chapters/index.html#mscript
//  for a description of existing commands
bool matroska_script_interpretor_c::Interpret( MatroskaChapterProcessTime time, const binary * p_command, size_t i_size )
{
    static thread_local int n_call = 0;
    if( n_call > M_MS_MAX_DEPTH )
      return false;
    n_call++;

    bool b_result = false;

    std::string sz_command( reinterpret_cast<const char*> (p_command), i_size );

    vlc_debug( l, "command : %s", sz_command.c_str() );

    if ( sz_command.compare( 0, CMD_MS_GOTO_AND_PLAY.size(), CMD_MS_GOTO_AND_PLAY ) == 0 )
    {
        size_t i,j;

        // find the (
        for ( i=CMD_MS_GOTO_AND_PLAY.size(); i<sz_command.size(); i++)
        {
            if ( sz_command[i] == ' ' )
                continue;
            if ( sz_command[i] == '(' )
            {
                i++;
                break;
            }
            return false; // extra characters between command and ( is not supported
        }
        // find the )
        for ( j=i; j<sz_command.size(); j++)
        {
            if ( sz_command[j] == ')' )
            {
                i--;
                break;
            }
        }

        if(i+1 < j-i-1)
        {
            std::string st = sz_command.substr( i+1, j-i-1 );
            chapter_uid i_chapter_uid = std::stoull( st );

            virtual_segment_c *p_vsegment;
            virtual_chapter_c *p_vchapter = vm.FindVChapter( i_chapter_uid, p_vsegment );

            if ( p_vchapter == NULL )
                vlc_debug( l, "Chapter %" PRId64 " not found", i_chapter_uid);
            else
            {
                auto current_chapter = vm.GetCurrentVSegment()->CurrentChapter();
                if ( p_vchapter == current_chapter) {
                    if ( time == MATROSKA_CHAPPROCESSTIME_BEFORE )
                        // the enter command is enter itself, avoid infinite loop
                        return false;
                    vm.JumpTo( *p_vsegment, *p_vchapter );
                }
                else if ( !p_vchapter->EnterAndLeave( current_chapter, false ) )
                    vm.JumpTo( *p_vsegment, *p_vchapter );
                b_result = true;
            }
        }
    }

    n_call--;
    return b_result;
}

} // namespace
