/* scheduler.cc
****************************************************************************************************************
****************************************************************************************************************

    Copyright (C) 2021, 2026 Askar Almatov

    This file is part of Trafficmeter.

    Trafficmeter is free software: you can redistribute it and/or modify it under the terms of the GNU General
    Public License as published by the Free Software Foundation, either version 3 of the License, or (at your
    option) any later version.

    Trafficmeter is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
    implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
    License for more details.

    You should have received a copy of the GNU General Public License along with Trafficmeter. If not, see
    <http://www.gnu.org/licenses/>.
*/

#include <cassert>
#include <iostream>
#include <libiclass/time>

#include "now.h"
#include "scheduler.h"
#include "substrate.h"

using namespace iclass;
using namespace trafficmeter;

using std::cout;
using std::endl;
using std::string;

constexpr const int     FLUSH_THRESHOLD_ = 20;  // number of source idle timeouts

/**************************************************************************************************************/
Scheduler::Scheduler( Source* source ) :
    source_( source ),
    headQueue_( nullptr )
{
}

/**************************************************************************************************************/
Scheduler::~Scheduler()
{
}

/**************************************************************************************************************/
void
Scheduler::attach( Extractor* extractor )
{
    extractor->inputQueue()->tieTo( headQueue_ );

    if ( headQueue_ == nullptr )
    {
        headQueue_ = extractor->inputQueue();
    }
}

/**************************************************************************************************************/
void
Scheduler::routine()
{
    assert( headQueue_ != nullptr );
    cout << Now() << "tid=" << tid() << " " << source_->name() << " scheduler started" << endl;
    source_->open();

    SubstrateQueue*     queue = headQueue_;
    Substrate*          substrate = queue->newSubstrate();
    bool                hasRecords = false;
    int                 nTimeouts = 0;

    while ( !stopped() )
    {
        if ( !hasRecords && !source_->checkForRecords() )
        {
            if ( !substrate->isEmpty() )
            {
                if ( ++nTimeouts > FLUSH_THRESHOLD_ )
                {
                    queue->push( substrate );
                    queue = queue->next();
                    substrate = queue->newSubstrate();
                    nTimeouts = 0;
                }
            }

            continue;
        }

        hasRecords = substrate->emplaceRecords( source_ );

        if ( hasRecords )
        {
            queue->push( substrate );
            queue = queue->next();
            substrate = queue->newSubstrate();
        }
    }

    queue->push( substrate );
    source_->close();
    cout << Now() << "tid=" << tid() << " " << source_->name() << " scheduler finished" << endl;
}

