#include "pinger.h"

using namespace NBalancerClient;
using namespace NSrvKernel;

TPinger::TPinger(TPinger::TOptions options): Options_{std::move(options)} {}

void TPinger::Shedule(TPingContext& pingContext) {
    pingContext.LastDataReceived_ = Executor().Now();
    Contexts_.PushBack(&pingContext);
    if (!Coroutine_.Running()) {
        Coroutine_ = TCoroutine{ECoroType::Service, "pinger_coroutine", &Executor(), std::mem_fn(&TPinger::Start), this};
    }
    pingContext.SetState(TPingContext::EState::IdleTimer);
}

void TPinger::Cancel() {
    Coroutine_.Cancel();
}

void TPinger::Start() {
    while (!RunningCont()->Cancelled()) {
        if (Contexts_.Empty()) {
            break;
        }

        auto pingTime = Contexts_.Front()->LastDataReceived_ + Options_.TimeWithoutDataBeforePing;
        if (pingTime > Executor().Now()) {
            RunningCont()->SleepD(pingTime);
            continue;
        }

        auto context = Contexts_.PopFront();
        context->Ping();
    }

    while (!Contexts_.Empty()) {
        Contexts_.PopFront()->Cancel();
    }
}

TContExecutor& TPinger::Executor() const {
    return Options_.ContExecutor ? *Options_.ContExecutor : *RunningCont()->Executor();
}
