Program Listing for File Action.hpp

Return to documentation for file (src/Action.hpp)

#pragma once
#include <KPFoundation.hpp>
#include <functional>
#include <vector>

class TimedAction {
protected:
    friend class ActionScheduler;
    bool removable = false;
    long start     = 0;

    void begin() {
        removable = false;
        start     = millis();
    }

public:
    long interval         = 0;
    signed char repeatFor = 0;
    const char * name;

    std::function<void()> callback;
    TimedAction() = default;
    TimedAction(const char * name) : name(name) {}

    long timeElapsed() const {
        return millis() - start;
    }

    bool isReady() const {
        return timeElapsed() >= interval;
    }
};

class ActionScheduler : public KPComponent {
public:
    std::vector<TimedAction> actions;

    ActionScheduler(const char * name) : KPComponent(name) {}

    template <typename T>
    void add(T && action) {
        actions.push_back(std::move(action));
        actions.back().begin();
    }

    void markForRemoval(const char * name) {
        for (auto & action : actions) {
            if (strcmp(action.name, name) == 0) {
                action.removable = true;
            }
        }
    }

    void removeCompletedActions() {
        auto predicate = std::remove_if(actions.begin(), actions.end(),
                                        [](const TimedAction & a) { return a.removable; });

        actions.erase(predicate, actions.end());
    }

    void update() override {
        removeCompletedActions();

        for (auto & action : actions) {
            if (action.isReady()) {
                action.callback();
            } else {
                continue;
            }

            if (action.repeatFor == 0) {
                action.removable = true;
            }

            if (!action.removable) {
                action.begin();
                action.repeatFor = std::max(action.repeatFor - 1, -1);
            }
        }
    }

    static ActionScheduler & sharedInstance() {
        static ActionScheduler shared("Shared ActionScheduler");
        return shared;
    }
};

template <typename T>
inline void run(T && action) {
    ActionScheduler::sharedInstance().add(std::forward<T>(action));
}

inline void run(long delay, std::function<void()> callback) {
    TimedAction action;
    action.interval = delay;
    action.callback = callback;
    ActionScheduler::sharedInstance().add(action);
}

inline void runForever(long delay, const char * name, std::function<void()> callback) {
    TimedAction action;
    action.name      = name;
    action.interval  = delay;
    action.callback  = callback;
    action.repeatFor = -1;
    ActionScheduler::sharedInstance().add(action);
}

inline void runForever(TimedAction action) {
    action.repeatFor = -1;
    ActionScheduler::sharedInstance().add(std::move(action));
}

inline void cancel(const char * name) {
    ActionScheduler::sharedInstance().markForRemoval(name);
}