#include "refresh_scheduler.h"

#include <algorithm>

namespace dragonx {
namespace services {

RefreshScheduler::Intervals RefreshScheduler::intervalsForPage(ui::NavPage page)
{
    using NP = ui::NavPage;
    // Intervals are {core, transactions, addresses, peers} in seconds (0 = disabled).
    // The peers value keeps the status-bar peer count current on EVERY tab — previously it was 0
    // off the Peers tab, so the count never updated until you opened Peers. A slow 20s cadence is
    // plenty for a status-bar number; the Peers tab itself stays fast (5s) for its live list. During
    // sync this is overridden by kSyncProfile (peers 0) so it can't contend with block download.
    switch (page) {
        case NP::Overview: return {2.0f, 10.0f, 15.0f, 20.0f};
        case NP::Send:     return {3.0f, 10.0f,  5.0f, 20.0f};
        case NP::Receive:  return {5.0f, 15.0f,  5.0f, 20.0f};
        case NP::History:  return {5.0f,  3.0f, 15.0f, 20.0f};
        case NP::Mining:   return {5.0f, 15.0f, 15.0f, 20.0f};
        case NP::Peers:    return {5.0f, 15.0f, 15.0f, 5.0f};
        case NP::Market:   return {5.0f, 15.0f, 15.0f, 20.0f};
        case NP::Console:  return {10.0f, 30.0f, 30.0f, 30.0f};
        default:           return {5.0f, 15.0f, 15.0f, 20.0f};
    }
}

void RefreshScheduler::applyPage(ui::NavPage page)
{
    setIntervals(intervalsForPage(page));
}

void RefreshScheduler::setIntervals(Intervals intervals)
{
    intervals_ = intervals;
}

void RefreshScheduler::tick(float deltaSeconds)
{
    float delta = std::max(0.0f, deltaSeconds);
    timers_.core += delta;
    timers_.transactions += delta;
    timers_.addresses += delta;
    timers_.peers += delta;
    timers_.price += delta;
    timers_.fast += delta;
    timers_.txAge += delta;
    timers_.opid += delta;
}

bool RefreshScheduler::isDue(Timer timer) const
{
    float timerInterval = interval(timer);
    return timerInterval > 0.0f && timerRef(timer) >= timerInterval;
}

bool RefreshScheduler::consumeDue(Timer timer)
{
    if (!isDue(timer)) return false;
    reset(timer);
    return true;
}

void RefreshScheduler::reset(Timer timer)
{
    timerRef(timer) = 0.0f;
}

void RefreshScheduler::markDue(Timer timer)
{
    float timerInterval = interval(timer);
    timerRef(timer) = timerInterval > 0.0f ? timerInterval : 0.0f;
}

void RefreshScheduler::setTimer(Timer timer, float seconds)
{
    timerRef(timer) = std::max(0.0f, seconds);
}

float RefreshScheduler::timer(Timer timer) const
{
    return timerRef(timer);
}

float RefreshScheduler::interval(Timer timer) const
{
    switch (timer) {
        case Timer::Core:         return intervals_.core;
        case Timer::Transactions: return intervals_.transactions;
        case Timer::Addresses:    return intervals_.addresses;
        case Timer::Peers:        return intervals_.peers;
        case Timer::Price:        return kPrice;
        case Timer::Fast:         return kFast;
        case Timer::TxAge:        return kTxMaxAge;
        case Timer::Opid:         return kOpidPoll;
    }
    return 0.0f;
}

void RefreshScheduler::markImmediateRefresh()
{
    markDue(Timer::Core);
    markDue(Timer::Transactions);
    markDue(Timer::Addresses);
    markDue(Timer::Peers);
}

void RefreshScheduler::markWalletMutationRefresh()
{
    markDue(Timer::Core);
    markDue(Timer::Transactions);
    markDue(Timer::Addresses);
}

void RefreshScheduler::resetTxAge()
{
    reset(Timer::TxAge);
}

bool RefreshScheduler::shouldRefreshTransactions(int lastTxBlockHeight,
                                                 int currentBlockHeight,
                                                 bool transactionsDirty) const
{
    return lastTxBlockHeight < 0
        || currentBlockHeight != lastTxBlockHeight
        || transactionsDirty;
}

float& RefreshScheduler::timerRef(Timer timer)
{
    switch (timer) {
        case Timer::Core:         return timers_.core;
        case Timer::Transactions: return timers_.transactions;
        case Timer::Addresses:    return timers_.addresses;
        case Timer::Peers:        return timers_.peers;
        case Timer::Price:        return timers_.price;
        case Timer::Fast:         return timers_.fast;
        case Timer::TxAge:        return timers_.txAge;
        case Timer::Opid:         return timers_.opid;
    }
    return timers_.core;
}

const float& RefreshScheduler::timerRef(Timer timer) const
{
    switch (timer) {
        case Timer::Core:         return timers_.core;
        case Timer::Transactions: return timers_.transactions;
        case Timer::Addresses:    return timers_.addresses;
        case Timer::Peers:        return timers_.peers;
        case Timer::Price:        return timers_.price;
        case Timer::Fast:         return timers_.fast;
        case Timer::TxAge:        return timers_.txAge;
        case Timer::Opid:         return timers_.opid;
    }
    return timers_.core;
}

} // namespace services
} // namespace dragonx
