#include "utils/Clock.h"

#include <threads.h>
#include <time.h>

Core::Clock::Clock() : index(0), last(0), sum(0), time(0) {
}

Core::Error Core::Clock::update(Clock::Nanos& n) {
    Nanos current = 0;
    CORE_RETURN_ERROR(getNanos(current));
    if(last == 0) {
        last = current;
        n = 0;
        return Error::NONE;
    }
    index = (index + 1) & (LENGTH - 1);
    sum -= time[index];
    time[index] = current - last;
    sum += time[index];
    last = current;
    n = time[index];
    return Error::NONE;
}

float Core::Clock::getUpdatesPerSecond() const {
    return (LENGTH * 1000000000.0f) / static_cast<float>(sum);
}

Core::Error Core::Clock::getNanos(Clock::Nanos& n) {
    timespec ts;
    if(timespec_get(&ts, TIME_UTC) == 0) {
        return Error::TIME_NOT_AVAILABLE;
    }
    n = static_cast<Clock::Nanos>(ts.tv_sec) * 1'000'000'000L +
        static_cast<Clock::Nanos>(ts.tv_nsec);
    return Error::NONE;
}

Core::Error Core::Clock::wait(Nanos nanos) const {
    timespec t;
    t.tv_nsec = nanos % 1'000'000'000;
    t.tv_sec = nanos / 1'000'000'000;
    return thrd_sleep(&t, nullptr) != 0 ? Error::SLEEP_INTERRUPTED
                                        : Error::NONE;
}