/********************************************************************
 *
 * This file is part of Easy3D. If it is useful in your research/work,
 * I would be grateful if you show your appreciation by citing it:
 * ------------------------------------------------------------------
 *      Liangliang Nan.
 *      Easy3D: a lightweight, easy-to-use, and efficient C++ library
 *      for processing and rendering 3D data.
 *      Journal of Open Source Software, 6(64), 3255, 2021.
 * ------------------------------------------------------------------
 *
 ********************************************************************/

#include <easy3d/util/timer.h>
#include <easy3d/core/signal.h>

#include <iostream>
#include <mutex>

std::mutex mutex;

using namespace easy3d;

// Trivial classes (that do not make sense, but can show the use of the Signal class).

class Vehicle {
public:
    virtual void start() {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "do nothing\n";
    }
};

class Car : public Vehicle {
public:

{}

public:
    int speed() const { return speed_; }

    void start() override {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "started\n";
    }

    void start(int new_speed) {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "speed changed from " << speed_ << " to " << new_speed << "\n";
        speed_ = new_speed;
    }

    void stop(int hours, const std::string &msg) const {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << msg << ". After driving for " << hours << " hours\n";
    }

private:
    int speed_;
};

void run_for_members(Car *car) {
    Timer<>::single_shot(33, car, &Car::start);

    Timer<int>::single_shot(33, car, &Car::start, 100);

    Timer<int, const std::string &>::single_shot(33, car, &Car::stop, 6, "I have to stop");

    {
        Timer<> t;
        t.single_shot(33, car, &Car::start);  // This works
        t.set_interval(33, car, &Car::start);          // This also works
        t.set_timeout(33, car, &Car::start);
    }

    {
        Timer<int> t;
        t.single_shot(33, car, &Car::start, 100);
        t.set_interval(33, car, &Car::start, 100);
        t.set_timeout(33, car, &Car::start, 100);
    }

    {
        Timer<int, const std::string &> t;
        t.single_shot(33, car, &Car::stop, 6, "I have to stop");
        t.set_interval(33, car, &Car::stop, 6, "I have to stop");
        t.set_timeout(33, car, &Car::stop, 6, "I have to stop");
    }
}

void func_start() {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << "started\n";
}

void func_start(Car *car) {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << "speed is " << car->speed() << "\n";
}

void func_report_speed(int max_allow_speed, const Car *car) {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << "max allowed is " << max_allow_speed << ". I am at " << car->speed() << "\n";
}

void func_stop(const Car *car, int hours, const std::string &msg) {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << msg << " after driving for " << hours << " hours. My speed was " << car->speed() << "\n";
}

void run_for_functions(Car *car) {

    Timer<>::single_shot(33, static_cast<void (*)(void)> (func_start));
    Timer<>::single_shot(33, overload<>(func_start));   // also works

    Timer<Car *>::single_shot(33, static_cast<void (*)(Car *)> (func_start), car);
    Timer<Car *>::single_shot(33, overload<Car *> (func_start), car);

    Timer<int, const Car *>::single_shot(33, func_report_speed, 120, car);

    Timer<const Car *, int, const std::string &>::single_shot(333, func_stop, car, 6, "I have to stop");

    {   // ---- no argument
        Timer<> t;
        t.single_shot(33, static_cast<void (*)(void)> (func_start));
        t.single_shot(33, overload<>(func_start));   // also works

        t.set_interval(33, static_cast<void (*)(void)> (func_start));
        t.set_interval(33, overload<>(func_start));   // also works

        t.set_timeout(33, static_cast<void (*)(void)> (func_start));
        t.set_timeout(33, overload<>(func_start));   // also works
    }

    {   // ---- one argument
        Timer<Car *> t;
        t.single_shot(33, static_cast<void (*)(Car *)> (func_start), car);
        t.single_shot(33, overload<Car*> (func_start), car);  // also works

        t.set_interval(33, static_cast<void (*)(Car *)> (func_start), car);
        t.set_interval(33, overload<Car*>  (func_start), car);  // also works

        t.set_timeout(33, static_cast<void (*)(Car *)> (func_start), car);
        t.set_timeout(33, overload<Car*> (func_start), car);  // also works
    }

    {   // ---- two argument
        Timer<int, const Car *> t;
        t.single_shot(33, func_report_speed, 120, car);
        t.set_interval(33, func_report_speed, 120, car);
        t.set_timeout(33, func_report_speed, 120, car);
    }

    {   // ---- three arguments
        Timer<const Car *, int, const std::string &> t;
        t.single_shot(333, func_stop, car, 6, "I have to stop");
        t.set_interval(333, func_stop, car, 6, "I have to stop");
        t.set_timeout(333, func_stop, car, 6, "I have to stop");
    }
}

void run_for_lambda_functions(Car *car) {
    auto lambda_start = []() -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "started\n";
    };

    auto lambda_start_1arg = [](Car *car) -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "speed is " << car->speed() << "\n";
    };

    auto lambda_report_speed = [](int max_allow_speed, const Car *car) -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "max allowed is " << max_allow_speed << ". I am at " << car->speed() << "\n";
    };

    auto lambda_stop = [](const Car *car, int hours, const std::string &msg) -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << msg << " after driving for " << hours << " hours. My speed was " << car->speed() << "\n";
    };

    Timer<>::single_shot(33, lambda_start);

    Timer<Car *>::single_shot(33, lambda_start_1arg, car);

    Timer<int, const Car *>::single_shot(33, lambda_report_speed, 120, car);

    Timer<const Car *, int, const std::string &>::single_shot(33, lambda_stop, car, 6, "I have to stop");

    {   // ---- no argument
        Timer<> t;
        t.single_shot(33, lambda_start);
        t.set_interval(33, lambda_start);
        t.set_timeout(33, lambda_start);
    }

    {   // ---- one argument
        Timer<Car *> t;
        t.single_shot(33, lambda_start_1arg, car);
        t.set_interval(33, lambda_start_1arg, car);
        t.set_timeout(33, lambda_start_1arg, car);
    }

    {   // ---- two argument
        Timer<int, const Car *> t;
        t.single_shot(33, lambda_report_speed, 120, car);
        t.set_interval(33, lambda_report_speed, 120, car);
        t.set_timeout(33, lambda_report_speed, 120, car);
    }

    {   // ---- three arguments
        Timer<const Car *, int, const std::string &> t;
        t.single_shot(333, lambda_stop, car, 6, "I have to stop");
        t.set_interval(333, lambda_stop, car, 6, "I have to stop");
        t.set_timeout(333, lambda_stop, car, 6, "I have to stop");
    }
}

bool test_timer() {
    Car car(100);

    std::cout << "triggers a class member ------------------------------------------------------------------\n\n";
    run_for_members(&car);
    std::this_thread::sleep_for(std::chrono::seconds(1));

    std::cout << "\n\ntriggers a function ------------------------------------------------------------------\n\n";
    run_for_functions(&car);
    std::this_thread::sleep_for(std::chrono::seconds(1));

    std::cout << "\n\ntriggers a lambda function -----------------------------------------------------------\n\n";
    run_for_lambda_functions(&car);
    std::this_thread::sleep_for(std::chrono::seconds(3));

    return EXIT_SUCCESS;
}


/********************************************************************
 *
 * This file is part of Easy3D. If it is useful in your research/work,
 * I would be grateful if you show your appreciation by citing it:
 * ------------------------------------------------------------------
 *      Liangliang Nan.
 *      Easy3D: a lightweight, easy-to-use, and efficient C++ library
 *      for processing and rendering 3D data.
 *      Journal of Open Source Software, 6(64), 3255, 2021.
 * ------------------------------------------------------------------
 *
 ********************************************************************/

#include <easy3d/util/timer.h>
#include <easy3d/core/signal.h>

#include <iostream>
#include <mutex>

std::mutex mutex;

using namespace easy3d;

// Trivial classes (that do not make sense, but can show the use of the Signal class).

class Vehicle {
public:
    virtual void start() {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "do nothing\n";
    }
};

class Car : public Vehicle {
public:
    Car(int speed) : speed_(speed) {}

public:
    int speed() const

    void start() override {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "started\n";
    }

    void start(int new_speed) {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "speed changed from " << speed_ << " to " << new_speed << "\n";
        speed_ = new_speed;
    }

    void stop(int hours, const std::string &msg) const {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << msg << ". After driving for " << hours << " hours\n";
    }

private:
    int speed_;
};

void run_for_members(Car *car) {
    Timer<>::single_shot(33, car, &Car::start);

    Timer<int>::single_shot(33, car, &Car::start, 100);

    Timer<int, const std::string &>::single_shot(33, car, &Car::stop, 6, "I have to stop");

    {
        Timer<> t;
        t.single_shot(33, car, &Car::start);  // This works
        t.set_interval(33, car, &Car::start);          // This also works
        t.set_timeout(33, car, &Car::start);
    }

    {
        Timer<int> t;
        t.single_shot(33, car, &Car::start, 100);
        t.set_interval(33, car, &Car::start, 100);
        t.set_timeout(33, car, &Car::start, 100);
    }

    {
        Timer<int, const std::string &> t;
        t.single_shot(33, car, &Car::stop, 6, "I have to stop");
        t.set_interval(33, car, &Car::stop, 6, "I have to stop");
        t.set_timeout(33, car, &Car::stop, 6, "I have to stop");
    }
}

void func_start() {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << "started\n";
}

void func_start(Car *car) {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << "speed is " << car->speed() << "\n";
}

void func_report_speed(int max_allow_speed, const Car *car) {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << "max allowed is " << max_allow_speed << ". I am at " << car->speed() << "\n";
}

void func_stop(const Car *car, int hours, const std::string &msg) {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << msg << " after driving for " << hours << " hours. My speed was " << car->speed() << "\n";
}

void run_for_functions(Car *car) {

    Timer<>::single_shot(33, static_cast<void (*)(void)> (func_start));
    Timer<>::single_shot(33, overload<>(func_start));   // also works

    Timer<Car *>::single_shot(33, static_cast<void (*)(Car *)> (func_start), car);
    Timer<Car *>::single_shot(33, overload<Car *> (func_start), car);

    Timer<int, const Car *>::single_shot(33, func_report_speed, 120, car);

    Timer<const Car *, int, const std::string &>::single_shot(333, func_stop, car, 6, "I have to stop");

    {   // ---- no argument
        Timer<> t;
        t.single_shot(33, static_cast<void (*)(void)> (func_start));
        t.single_shot(33, overload<>(func_start));   // also works

        t.set_interval(33, static_cast<void (*)(void)> (func_start));
        t.set_interval(33, overload<>(func_start));   // also works

        t.set_timeout(33, static_cast<void (*)(void)> (func_start));
        t.set_timeout(33, overload<>(func_start));   // also works
    }

    {   // ---- one argument
        Timer<Car *> t;
        t.single_shot(33, static_cast<void (*)(Car *)> (func_start), car);
        t.single_shot(33, overload<Car*> (func_start), car);  // also works

        t.set_interval(33, static_cast<void (*)(Car *)> (func_start), car);
        t.set_interval(33, overload<Car*>  (func_start), car);  // also works

        t.set_timeout(33, static_cast<void (*)(Car *)> (func_start), car);
        t.set_timeout(33, overload<Car*> (func_start), car);  // also works
    }

    {   // ---- two argument
        Timer<int, const Car *> t;
        t.single_shot(33, func_report_speed, 120, car);
        t.set_interval(33, func_report_speed, 120, car);
        t.set_timeout(33, func_report_speed, 120, car);
    }

    {   // ---- three arguments
        Timer<const Car *, int, const std::string &> t;
        t.single_shot(333, func_stop, car, 6, "I have to stop");
        t.set_interval(333, func_stop, car, 6, "I have to stop");
        t.set_timeout(333, func_stop, car, 6, "I have to stop");
    }
}

void run_for_lambda_functions(Car *car) {
    auto lambda_start = []() -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "started\n";
    };

    auto lambda_start_1arg = [](Car *car) -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "speed is " << car->speed() << "\n";
    };

    auto lambda_report_speed = [](int max_allow_speed, const Car *car) -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "max allowed is " << max_allow_speed << ". I am at " << car->speed() << "\n";
    };

    auto lambda_stop = [](const Car *car, int hours, const std::string &msg) -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << msg << " after driving for " << hours << " hours. My speed was " << car->speed() << "\n";
    };

    Timer<>::single_shot(33, lambda_start);

    Timer<Car *>::single_shot(33, lambda_start_1arg, car);

    Timer<int, const Car *>::single_shot(33, lambda_report_speed, 120, car);

    Timer<const Car *, int, const std::string &>::single_shot(33, lambda_stop, car, 6, "I have to stop");

    {   // ---- no argument
        Timer<> t;
        t.single_shot(33, lambda_start);
        t.set_interval(33, lambda_start);
        t.set_timeout(33, lambda_start);
    }

    {   // ---- one argument
        Timer<Car *> t;
        t.single_shot(33, lambda_start_1arg, car);
        t.set_interval(33, lambda_start_1arg, car);
        t.set_timeout(33, lambda_start_1arg, car);
    }

    {   // ---- two argument
        Timer<int, const Car *> t;
        t.single_shot(33, lambda_report_speed, 120, car);
        t.set_interval(33, lambda_report_speed, 120, car);
        t.set_timeout(33, lambda_report_speed, 120, car);
    }

    {   // ---- three arguments
        Timer<const Car *, int, const std::string &> t;
        t.single_shot(333, lambda_stop, car, 6, "I have to stop");
        t.set_interval(333, lambda_stop, car, 6, "I have to stop");
        t.set_timeout(333, lambda_stop, car, 6, "I have to stop");
    }
}

bool test_timer() {
    Car car(100);

    std::cout << "triggers a class member ------------------------------------------------------------------\n\n";
    run_for_members(&car);
    std::this_thread::sleep_for(std::chrono::seconds(1));

    std::cout << "\n\ntriggers a function ------------------------------------------------------------------\n\n";
    run_for_functions(&car);
    std::this_thread::sleep_for(std::chrono::seconds(1));

    std::cout << "\n\ntriggers a lambda function -----------------------------------------------------------\n\n";
    run_for_lambda_functions(&car);
    std::this_thread::sleep_for(std::chrono::seconds(3));

    return EXIT_SUCCESS;
}


/********************************************************************
 *
 * This file is part of Easy3D. If it is useful in your research/work,
 * I would be grateful if you show your appreciation by citing it:
 * ------------------------------------------------------------------
 *      Liangliang Nan.
 *      Easy3D: a lightweight, easy-to-use, and efficient C++ library
 *      for processing and rendering 3D data.
 *      Journal of Open Source Software, 6(64), 3255, 2021.
 * ------------------------------------------------------------------
 *
 ********************************************************************/

#include <easy3d/util/timer.h>
#include <easy3d/core/signal.h>

#include <iostream>
#include <mutex>

std::mutex mutex;

using namespace easy3d;

// Trivial classes (that do not make sense, but can show the use of the Signal class).

class Vehicle {
public:
    virtual void start() {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "do nothing\n";
    }
};

class Car : public Vehicle {
public:
    Car(int speed) : speed_(speed) {}

public:
    int speed() const { return speed_; }

    void start() override {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "started\n";
    }

    void start(int new_speed) {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "speed changed from " << speed_ << " to " << new_speed << "\n";
        speed_ = new_speed;
    }

    void stop(int hours, const std::string &msg) const {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << msg << ". After driving for " << hours << " hours\n";
    }

private:
    int speed_;
};

void run_for_members(Car *car) {
    Timer<>::single_shot(33, car, &Car::start);

    Timer<int>::single_shot(33, car, &Car::start, 100);

    Timer<int, const std::string &>::single_shot(33, car, &Car::stop, 6, "I have to stop");

    {
        Timer<> t;
        t.single_shot(33, car, &Car::start);  // This works
        t.set_interval(33, car, &Car::start);          // This also works
        t.set_timeout(33, car, &Car::start);
    }

    {
        Timer<int> t;
        t.single_shot(33, car, &Car::start, 100);
        t.set_interval(33, car, &Car::start, 100);
        t.set_timeout(33, car, &Car::start, 100);
    }

    {
        Timer<int, const std::string &> t;
        t.single_shot(33, car, &Car::stop, 6, "I have to stop");
        t.set_interval(33, car, &Car::stop, 6, "I have to stop");
        t.set_timeout(33, car, &Car::stop, 6, "I have to stop");
    }
}

void func_start() {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << "started\n";
}

void func_start(Car *car) {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << "speed is " << car->speed() << "\n";
}

void func_report_speed(int max_allow_speed, const Car *car) {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << "max allowed is " << max_allow_speed << ". I am at " << car->speed() << "\n";
}

void func_stop(const Car *car, int hours, const std::string &msg) {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << msg << " after driving for " << hours << " hours. My speed was " << car->speed() << "\n";
}

void run_for_functions(Car *car) {

    Timer<>::single_shot(33, static_cast<void (*)(void)> (func_start));
    Timer<>::single_shot(33, overload<>(func_start));   // also works

    Timer<Car *>::single_shot(33, static_cast<void (*)(Car *)> (func_start), car);
    Timer<Car *>::single_shot(33, overload<Car *> (func_start), car);

    Timer<int, const Car *>::single_shot(33, func_report_speed, 120, car);

    Timer<const Car *, int, const std::string &>::single_shot(333, func_stop, car, 6, "I have to stop");

    {   // ---- no argument
        Timer<> t;
        t.single_shot(33, static_cast<void (*)(void)> (func_start));
        t.single_shot(33, overload<>(func_start));   // also works

        t.set_interval(33, static_cast<void (*)(void)> (func_start));
        t.set_interval(33, overload<>(func_start));   // also works

        t.set_timeout(33, static_cast<void (*)(void)> (func_start));
        t.set_timeout(33, overload<>(func_start));   // also works
    }

    {   // ---- one argument
        Timer<Car *> t;
        t.single_shot(33, static_cast<void (*)(Car *)> (func_start), car);
        t.single_shot(33, overload<Car*> (func_start), car);  // also works

        t.set_interval(33, static_cast<void (*)(Car *)> (func_start), car);
        t.set_interval(33, overload<Car*>  (func_start), car);  // also works

        t.set_timeout(33, static_cast<void (*)(Car *)> (func_start), car);
        t.set_timeout(33, overload<Car*> (func_start), car);  // also works
    }

    {   // ---- two argument
        Timer<int, const Car *> t;
        t.single_shot(33, func_report_speed, 120, car);
        t.set_interval(33, func_report_speed, 120, car);
        t.set_timeout(33, func_report_speed, 120, car);
    }

    {   // ---- three arguments
        Timer<const Car *, int, const std::string &> t;
        t.single_shot(333, func_stop, car, 6, "I have to stop");
        t.set_interval(333, func_stop, car, 6, "I have to stop");
        t.set_timeout(333, func_stop, car, 6, "I have to stop");
    }
}

void run_for_lambda_functions(Car *car) {
    auto lambda_start = []() -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "started\n";
    };

    auto lambda_start_1arg = [](Car *car) -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "speed is " << car->speed() << "\n";
    };

    auto lambda_report_speed = [](int max_allow_speed, const Car *car) -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "max allowed is " << max_allow_speed << ". I am at " << car->speed() << "\n";
    };

    auto lambda_stop = [](const Car *car, int hours, const std::string &msg) -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << msg << " after driving for " << hours << " hours. My speed was " << car->speed() << "\n";
    };

    Timer<>::single_shot(33, lambda_start);

    Timer<Car *>::single_shot(33, lambda_start_1arg, car);

    Timer<int, const Car *>::single_shot(33, lambda_report_speed, 120, car);

    Timer<const Car *, int, const std::string &>::single_shot(33, lambda_stop, car, 6, "I have to stop");

    {   // ---- no argument
        Timer<> t;
        t.single_shot(33, lambda_start);
        t.set_interval(33, lambda_start);
        t.set_timeout(33, lambda_start);
    }

    {   // ---- one argument
        Timer<Car *> t;
        t.single_shot(33, lambda_start_1arg, car);
        t.set_interval(33, lambda_start_1arg, car);
        t.set_timeout(33, lambda_start_1arg, car);
    }

    {   // ---- two argument
        Timer<int, const Car *> t;
        t.single_shot(33, lambda_report_speed, 120, car);
        t.set_interval(33, lambda_report_speed, 120, car);
        t.set_timeout(33, lambda_report_speed, 120, car);
    }

    {   // ---- three arguments
        Timer<const Car *, int, const std::string &> t;
        t.single_shot(333, lambda_stop, car, 6, "I have to stop");
        t.set_interval(333, lambda_stop, car, 6, "I have to stop");
        t.set_timeout(333, lambda_stop, car, 6, "I have to stop");
    }
}

bool test_timer()

    std::cout << "\n\ntriggers a function ------------------------------------------------------------------\n\n";
    run_for_functions(&car);
    std::this_thread::sleep_for(std::chrono::seconds(1));

    std::cout << "\n\ntriggers a lambda function -----------------------------------------------------------\n\n";
    run_for_lambda_functions(&car);
    std::this_thread::sleep_for(std::chrono::seconds(3));

    return EXIT_SUCCESS;
}


/********************************************************************
 *
 * This file is part of Easy3D. If it is useful in your research/work,
 * I would be grateful if you show your appreciation by citing it:
 * ------------------------------------------------------------------
 *      Liangliang Nan.
 *      Easy3D: a lightweight, easy-to-use, and efficient C++ library
 *      for processing and rendering 3D data.
 *      Journal of Open Source Software, 6(64), 3255, 2021.
 * ------------------------------------------------------------------
 *
 ********************************************************************/

#include <easy3d/util/timer.h>
#include <easy3d/core/signal.h>

#include <iostream>
#include <mutex>

std::mutex mutex;

using namespace easy3d;

// Trivial classes (that do not make sense, but can show the use of the Signal class).

class Vehicle {
public:
    virtual void start() {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "do nothing\n";
    }
};

class Car : public Vehicle {
public:
    Car(int speed) : speed_(speed) {}

public:
    int speed() const { return speed_; }

    void start() override {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "started\n";
    }

    void start(int new_speed) {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "speed changed from " << speed_ << " to " << new_speed << "\n";
        speed_ = new_speed;
    }

    void stop(int hours, const std::string &msg) const {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << msg << ". After driving for " << hours << " hours\n";
    }

private:
    int speed_;
};

void run_for_members(Car *car) {
    Timer<>::single_shot(33, car, &Car::start);

    Timer<int>::single_shot(33, car, &Car::start, 100);

    Timer<int, const std::string &>::single_shot(33, car, &Car::stop, 6, "I have to stop");

    {
        Timer<> t;
        t.single_shot(33, car, &Car::start);  // This works
        t.set_interval(33, car, &Car::start);          // This also works
        t.set_timeout(33, car, &Car::start);
    }

    {
        Timer<int> t;
        t.single_shot(33, car, &Car::start, 100);
        t.set_interval(33, car, &Car::start, 100);
        t.set_timeout(33, car, &Car::start, 100);
    }

    {
        Timer<int, const std::string &> t;
        t.single_shot(33, car, &Car::stop, 6, "I have to stop");
        t.set_interval(33, car, &Car::stop, 6, "I have to stop");
        t.set_timeout(33, car, &Car::stop, 6, "I have to stop");
    }
}

void func_start() {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << "started\n";
}

void func_start(Car *car) {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << "speed is " << car->speed() << "\n";
}

void func_report_speed(int max_allow_speed, const Car *car) {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << "max allowed is " << max_allow_speed << ". I am at " << car->speed() << "\n";
}

void func_stop(const Car *car, int hours, const std::string &msg) {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << msg << " after driving for " << hours << " hours. My speed was " << car->speed() << "\n";
}

void run_for_functions(Car *car) {

    Timer<>::single_shot(33, static_cast<void (*)(void)> (func_start));
    Timer<>::single_shot(33, overload<>(func_start));   // also works

    Timer<Car *>::single_shot(33, static_cast<void (*)(Car *)> (func_start), car);
    Timer<Car *>::single_shot(33, overload<Car *> (func_start), car);

    Timer<int, const Car *>::single_shot(33, func_report_speed, 120, car);

    Timer<const Car *, int, const std::string &>::single_shot(333, func_stop, car, 6, "I have to stop");

    {   // ---- no argument
        Timer<> t;
        t.single_shot(33, static_cast<void (*)(void)> (func_start));
        t.single_shot(33, overload<>(func_start));   // also works

        t.set_interval(33, static_cast<void (*)(void)> (func_start));
        t.set_interval(33, overload<>(func_start));   // also works

        t.set_timeout(33, static_cast<void (*)(void)> (func_start));
        t.set_timeout(33, overload<>(func_start));   // also works
    }

    {   // ---- one argument
        Timer<Car *> t;
        t.single_shot(33, static_cast<void (*)(Car *)> (func_start), car);
        t.single_shot(33, overload<Car*> (func_start), car);  // also works

        t.set_interval(33, static_cast<void (*)(Car *)> (func_start), car);
        t.set_interval(33, overload<Car*>  (func_start), car);  // also works

        t.set_timeout(33, static_cast<void (*)(Car *)> (func_start), car);
        t.set_timeout(33, overload<Car*> (func_start), car);  // also works
    }

    {   // ---- two argument
        Timer<int, const Car *> t;
        t.single_shot(33, func_report_speed, 120, car);
        t.set_interval(33, func_report_speed, 120, car);
        t.set_timeout(33, func_report_speed, 120, car);
    }

    {   // ---- three arguments
        Timer<const Car *, int, const std::string &> t;
        t.single_shot(333, func_stop, car, 6, "I have to stop");
        t.set_interval(333, func_stop, car, 6, "I have to stop");
        t.set_timeout(333, func_stop, car, 6, "I have to stop");
    }
}

void run_for_lambda_functions(Car *car) {
    auto lambda_start = []() -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "started\n";
    };

    auto lambda_start_1arg = [](Car *car) -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "speed is " << car->speed() << "\n";
    };

    auto lambda_report_speed = [](int max_allow_speed, const Car *car) -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "max allowed is " << max_allow_speed << ". I am at " << car->speed() << "\n";
    };

    auto lambda_stop = [](const Car *car, int hours, const std::string &msg) -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << msg << " after driving for " << hours << " hours. My speed was " << car->speed() << "\n";
    };

    Timer<>::single_shot(33, lambda_start);

    Timer<Car *>::single_shot(33, lambda_start_1arg, car);

    Timer<int, const Car *>::single_shot(33, lambda_report_speed, 120, car);

    Timer<const Car *, int, const std::string &>::single_shot(33, lambda_stop, car, 6, "I have to stop");

    {   // ---- no argument
        Timer<> t;
        t.single_shot(33, lambda_start);
        t.set_interval(33, lambda_start);
        t.set_timeout(33, lambda_start);
    }

    {   // ---- one argument
        Timer<Car *> t;
        t.single_shot(33, lambda_start_1arg, car);
        t.set_interval(33, lambda_start_1arg, car);
        t.set_timeout(33, lambda_start_1arg, car);
    }

    {   // ---- two argument
        Timer<int, const Car *> t;
        t.single_shot(33, lambda_report_speed, 120, car);
        t.set_interval(33, lambda_report_speed, 120, car);
        t.set_timeout(33, lambda_report_speed, 120, car);
    }

    {   // ---- three arguments
        Timer<const Car *, int, const std::string &> t;
        t.single_shot(333, lambda_stop, car, 6, "I have to stop");
        t.set_interval(333, lambda_stop, car, 6, "I have to stop");
        t.set_timeout(333, lambda_stop, car, 6, "I have to stop");
    }
}

bool test_timer() {
    Car car(100);

    std::cout << "triggers a class member ------------------------------------------------------------------\n\n";
    run_for_members(&car);
    std::this_thread::sleep_for(std::chrono::seconds(1));

    run_for_lambda_functions(&car);
    std::this_thread::sleep_for(std::chrono::seconds(3));

    return EXIT_SUCCESS;
}


run_for_lambda_functions(&car);
    std::this_thread::sleep_for(std::chrono::seconds(3));

    return EXIT_SUCCESS;
}

/********************************************************************
 *
 * This file is part of Easy3D. If it is useful in your research/work,
 * I would be grateful if you show your appreciation by citing it:
 * ------------------------------------------------------------------
 *      Liangliang Nan.
 *      Easy3D: a lightweight, easy-to-use, and efficient C++ library
 *      for processing and rendering 3D data.
 *      Journal of Open Source Software, 6(64), 3255, 2021.
 * ------------------------------------------------------------------
 *
 ********************************************************************/

#include <easy3d/util/timer.h>
#include <easy3d/core/signal.h>

#include <iostream>
#include <mutex>

std::mutex mutex;

using namespace easy3d;

// Trivial classes (that do not make sense, but can show the use of the Signal class).

class Vehicle {
public:
    virtual void start() {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "do nothing\n";
    }
};

class Car : public Vehicle {
public:
    Car(int speed) : speed_(speed) {}

public:
    int speed() const { return speed_; }

    void start() override {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "started\n";
    }

    void start(int new_speed) {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "speed changed from " << speed_ << " to " << new_speed << "\n";
        speed_ = new_speed;
    }

    void stop(int hours, const std::string &msg) const {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << msg << ". After driving for " << hours << " hours\n";
    }

private:
    int speed_;
};

void run_for_members(Car *car) {
    Timer<>::single_shot(33, car, &Car::start);

    Timer<int>::single_shot(33, car, &Car::start, 100);

    Timer<int, const std::string &>::single_shot(33, car, &Car::stop, 6, "I have to stop");

    {
        Timer<> t;
        t.single_shot(33, car, &Car::start);  // This works
        t.set_interval(33, car, &Car::start);          // This also works
        t.set_timeout(33, car, &Car::start);
    }

    {
        Timer<int> t;
        t.single_shot(33, car, &Car::start, 100);
        t.set_interval(33, car, &Car::start, 100);
        t.set_timeout(33, car, &Car::start, 100);
    }

    {
        Timer<int, const std::string &> t;
        t.single_shot(33, car, &Car::stop, 6, "I have to stop");
        t.set_interval(33, car, &Car::stop, 6, "I have to stop");
        t.set_timeout(33, car, &Car::stop, 6, "I have to stop");
    }
}

void func_start() {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << "started\n";
}

void func_start(Car *car) {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << "speed is " << car->speed() << "\n";
}

void func_report_speed(int max_allow_speed, const Car *car) {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << "max allowed is " << max_allow_speed << ". I am at " << car->speed() << "\n";
}

void func_stop(const Car *car, int hours, const std::string &msg) {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << msg << " after driving for " << hours << " hours. My speed was " << car->speed() << "\n";
}

void run_for_functions(Car *car) {

    Timer<>::single_shot(33, static_cast<void (*)(void)> (func_start));
    Timer<>::single_shot(33, overload<>(func_start));   // also works

    Timer<Car *>::single_shot(33, static_cast<void (*)(Car *)> (func_start), car);
    Timer<Car *>::single_shot(33, overload<Car *> (func_start), car);

    Timer<int, const Car *>::single_shot(33, func_report_speed, 120, car);

    Timer<const Car *, int, const std::string &>::single_shot(333, func_stop, car, 6, "I have to stop");

    {   // ---- no argument
        Timer<> t;
        t.single_shot(33, static_cast<void (*)(void)> (func_start));
        t.single_shot(33, overload<>(func_start));   // also works

        t.set_interval(33, static_cast<void (*)(void)> (func_start));
        t.set_interval(33, overload<>(func_start));   // also works

        t.set_timeout(33, static_cast<void (*)(void)> (func_start));
        t.set_timeout(33, overload<>(func_start));   // also works
    }

    {   // ---- one argument
        Timer<Car *> t;
        t.single_shot(33, static_cast<void (*)(Car *)> (func_start), car);
        t.single_shot(33, overload<Car*> (func_start), car);  // also works

        t.set_interval(33, static_cast<void (*)(Car *)> (func_start), car);
        t.set_interval(33, overload<Car*>  (func_start), car);  // also works

        t.set_timeout(33, static_cast<void (*)(Car *)> (func_start), car);
        t.set_timeout(33, overload<Car*> (func_start), car);  // also works
    }

    {   // ---- two argument
        Timer<int, const Car *> t;
        t.single_shot(33, func_report_speed, 120, car);
        t.set_interval(33, func_report_speed, 120, car);
        t.set_timeout(33, func_report_speed, 120, car);
    }

    {   // ---- three arguments
        Timer<const Car *, int, const std::string &> t;
        t.single_shot(333, func_stop, car, 6, "I have to stop");
        t.set_interval(333, func_stop, car, 6, "I have to stop");
        t.set_timeout(333, func_stop, car, 6, "I have to stop");
    }
}

void run_for_lambda_functions(Car *car) {
    auto lambda_start = []() -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "started\n";
    };

    auto lambda_start_1arg = [](Car *car) -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "speed is " << car->speed() << "\n";
    };

    auto lambda_report_speed = [](int max_allow_speed, const Car *car) -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "max allowed is " << max_allow_speed << ". I am at " << car->speed() << "\n";
    };

    auto lambda_stop = [](const Car *car, int hours, const std::string &msg) -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << msg << " after driving for " << hours << " hours. My speed was " << car->speed() << "\n";
    };

    Timer<>::single_shot(33, lambda_start);

    Timer<Car *>::single_shot(33, lambda_start_1arg, car);

    Timer<int, const Car *>::single_shot(33, lambda_report_speed, 120, car);

    Timer<const Car *, int, const std::string &>::single_shot(33, lambda_stop, car, 6, "I have to stop");

    {   // ---- no argument
        Timer<> t;
        t.single_shot(33, lambda_start);
        t.set_interval(33, lambda_start);
        t.set_timeout(33, lambda_start);
    }

    {   // ---- one argument
        Timer<Car *> t;
        t.single_shot(33, lambda_start_1arg, car);
        t.set_interval(33, lambda_start_1arg, car);
        t.set_timeout(33, lambda_start_1arg, car);
    }

    {   // ---- two argument
        Timer<int, const Car *> t;
        t.single_shot(33, lambda_report_speed, 120, car);
        t.set_interval(33, lambda_report_speed, 120, car);
        t.set_timeout(33, lambda_report_speed, 120, car);
    }

    {   // ---- three arguments
        Timer<const Car *, int, const std::string &> t;
        t.single_shot(333, lambda_stop, car, 6, "I have to stop");
        t.set_interval(333, lambda_stop, car, 6, "I have to stop");
        t.set_timeout(333, lambda_stop, car, 6, "I have to stop");
    }
}

bool test_timer() {
    Car car(100);

    std::cout << "triggers a class member ------------------------------------------------------------------\n\n";
    run_for_members(&car);
    std::this_thread::sleep_for(std::chrono::seconds(1));

    std::cout << "\n\ntriggers a function ------------------------------------------------------------------\n\n";
    run_for_functions(&car);
    std::this_thread::sleep_for(std::chrono::seconds(1));

    std::cout << "\n\ntriggers a lambda function -----------------------------------------------------------\n\n";


ot(33, overload<Car *> (func_start), car);

/********************************************************************
 *
 * This file is part of Easy3D. If it is useful in your research/work,
 * I would be grateful if you show your appreciation by citing it:
 * ------------------------------------------------------------------
 *      Liangliang Nan.
 *      Easy3D: a lightweight, easy-to-use, and efficient C++ library
 *      for processing and rendering 3D data.
 *      Journal of Open Source Software, 6(64), 3255, 2021.
 * ------------------------------------------------------------------
 *
 ********************************************************************/

#include <easy3d/util/timer.h>
#include <easy3d/core/signal.h>

#include <iostream>
#include <mutex>

std::mutex mutex;

using namespace easy3d;

// Trivial classes (that do not make sense, but can show the use of the Signal class).

class Vehicle {
public:
    virtual void start() {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "do nothing\n";
    }
};

class Car : public Vehicle {
public:
    Car(int speed) : speed_(speed) {}

public:
    int speed() const { return speed_; }

    void start() override {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "started\n";
    }

    void start(int new_speed) {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "speed changed from " << speed_ << " to " << new_speed << "\n";
        speed_ = new_speed;
    }

    void stop(int hours, const std::string &msg) const {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << msg << ". After driving for " << hours << " hours\n";
    }

private:
    int speed_;
};

void run_for_members(Car *car) {
    Timer<>::single_shot(33, car, &Car::start);

    Timer<int>::single_shot(33, car, &Car::start, 100);

    Timer<int, const std::string &>::single_shot(33, car, &Car::stop, 6, "I have to stop");

    {
        Timer<> t;
        t.single_shot(33, car, &Car::start);  // This works
        t.set_interval(33, car, &Car::start);          // This also works
        t.set_timeout(33, car, &Car::start);
    }

    {
        Timer<int> t;
        t.single_shot(33, car, &Car::start, 100);
        t.set_interval(33, car, &Car::start, 100);
        t.set_timeout(33, car, &Car::start, 100);
    }

    {
        Timer<int, const std::string &> t;
        t.single_shot(33, car, &Car::stop, 6, "I have to stop");
        t.set_interval(33, car, &Car::stop, 6, "I have to stop");
        t.set_timeout(33, car, &Car::stop, 6, "I have to stop");
    }
}

void func_start() {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << "started\n";
}

void func_start(Car *car) {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << "speed is " << car->speed() << "\n";
}

void func_report_speed(int max_allow_speed, const Car *car) {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << "max allowed is " << max_allow_speed << ". I am at " << car->speed() << "\n";
}

void func_stop(const Car *car, int hours, const std::string &msg) {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << msg << " after driving for " << hours << " hours. My speed was " << car->speed() << "\n";
}

void run_for_functions(Car *car) {

    Timer<>::single_shot(33, static_cast<void (*)(void)> (func_start));
    Timer<>::single_shot(33, overload<>(func_start));   // also works

    Timer<Car *>::single_shot(33, static_cast<void (*)(Car *)> (func_start), car);
    Timer<Car *>::single_sh

    Timer<int, const Car *>::single_shot(33, func_report_speed, 120, car);

    Timer<const Car *, int, const std::string &>::single_shot(333, func_stop, car, 6, "I have to stop");

    {   // ---- no argument
        Timer<> t;
        t.single_shot(33, static_cast<void (*)(void)> (func_start));
        t.single_shot(33, overload<>(func_start));   // also works

        t.set_interval(33, static_cast<void (*)(void)> (func_start));
        t.set_interval(33, overload<>(func_start));   // also works

        t.set_timeout(33, static_cast<void (*)(void)> (func_start));
        t.set_timeout(33, overload<>(func_start));   // also works
    }

    {   // ---- one argument
        Timer<Car *> t;
        t.single_shot(33, static_cast<void (*)(Car *)> (func_start), car);
        t.single_shot(33, overload<Car*> (func_start), car);  // also works

        t.set_interval(33, static_cast<void (*)(Car *)> (func_start), car);
        t.set_interval(33, overload<Car*>  (func_start), car);  // also works

        t.set_timeout(33, static_cast<void (*)(Car *)> (func_start), car);
        t.set_timeout(33, overload<Car*> (func_start), car);  // also works
    }

    {   // ---- two argument
        Timer<int, const Car *> t;
        t.single_shot(33, func_report_speed, 120, car);
        t.set_interval(33, func_report_speed, 120, car);
        t.set_timeout(33, func_report_speed, 120, car);
    }

    {   // ---- three arguments
        Timer<const Car *, int, const std::string &> t;
        t.single_shot(333, func_stop, car, 6, "I have to stop");
        t.set_interval(333, func_stop, car, 6, "I have to stop");
        t.set_timeout(333, func_stop, car, 6, "I have to stop");
    }
}

void run_for_lambda_functions(Car *car) {
    auto lambda_start = []() -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "started\n";
    };

    auto lambda_start_1arg = [](Car *car) -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "speed is " << car->speed() << "\n";
    };

    auto lambda_report_speed = [](int max_allow_speed, const Car *car) -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "max allowed is " << max_allow_speed << ". I am at " << car->speed() << "\n";
    };

    auto lambda_stop = [](const Car *car, int hours, const std::string &msg) -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << msg << " after driving for " << hours << " hours. My speed was " << car->speed() << "\n";
    };

    Timer<>::single_shot(33, lambda_start);

    Timer<Car *>::single_shot(33, lambda_start_1arg, car);

    Timer<int, const Car *>::single_shot(33, lambda_report_speed, 120, car);

    Timer<const Car *, int, const std::string &>::single_shot(33, lambda_stop, car, 6, "I have to stop");

    {   // ---- no argument
        Timer<> t;
        t.single_shot(33, lambda_start);
        t.set_interval(33, lambda_start);
        t.set_timeout(33, lambda_start);
    }

    {   // ---- one argument
        Timer<Car *> t;
        t.single_shot(33, lambda_start_1arg, car);
        t.set_interval(33, lambda_start_1arg, car);
        t.set_timeout(33, lambda_start_1arg, car);
    }

    {   // ---- two argument
        Timer<int, const Car *> t;
        t.single_shot(33, lambda_report_speed, 120, car);
        t.set_interval(33, lambda_report_speed, 120, car);
        t.set_timeout(33, lambda_report_speed, 120, car);
    }

    {   // ---- three arguments
        Timer<const Car *, int, const std::string &> t;
        t.single_shot(333, lambda_stop, car, 6, "I have to stop");
        t.set_interval(333, lambda_stop, car, 6, "I have to stop");
        t.set_timeout(333, lambda_stop, car, 6, "I have to stop");
    }
}

bool test_timer() {
    Car car(100);

    std::cout << "triggers a class member ------------------------------------------------------------------\n\n";
    run_for_members(&car);
    std::this_thread::sleep_for(std::chrono::seconds(1));

    std::cout << "\n\ntriggers a function ------------------------------------------------------------------\n\n";
    run_for_functions(&car);
    std::this_thread::sleep_for(std::chrono::seconds(1));

    std::cout << "\n\ntriggers a lambda function -----------------------------------------------------------\n\n";
    run_for_lambda_functions(&car);
    std::this_thread::sleep_for(std::chrono::seconds(3));

    return EXIT_SUCCESS;
}


grateful if you show your appreciation by citing it:
 * ------------------------------------------------------------------
 *      Liangliang Nan.
 *      Easy3D: a lightweight, easy-to-use, and efficient C++ library
 *      for processing and rendering 3D data.
 *      Journal of Open Source Software, 6(64), 3255, 2021.
 * ------------------------------------------------------------------
 *
 ********************************************************************/

#include <easy3d/util/timer.h>
#include <easy3d/core/signal.h>

#include <iostream>
#include <mutex>

std::mutex mutex;

using namespace easy3d;

// Trivial classes (that do not make sense, but can show the use of the Signal class).

class Vehicle {
public:
    virtual void start() {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "do nothing\n";
    }
};

class Car : public Vehicle {
public:
    Car(int speed) : speed_(speed) {}

public:
    int speed() const { return speed_; }

    void start() override {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "started\n";
    }

    void start(int new_speed) {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "speed changed from " << speed_ << " to " << new_speed << "\n";
        speed_ = new_speed;
    }

    void stop(int hours, const std::string &msg) const {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << msg << ". After driving for " << hours << " hours\n";
    }

private:
    int speed_;
};

void run_for_members(Car *car) {
    Timer<>::single_shot(33, car, &Car::start);

    Timer<int>::single_shot(33, car, &Car::start, 100);

    Timer<int, const std::string &>::single_shot(33, car, &Car::stop, 6, "I have to stop");

    {
        Timer<> t;
        t.single_shot(33, car, &Car::start);  // This works
        t.set_interval(33, car, &Car::start);          // This also works
        t.set_timeout(33, car, &Car::start);
    }

    {
        Timer<int> t;
        t.single_shot(33, car, &Car::start, 100);
        t.set_interval(33, car, &Car::start, 100);
        t.set_timeout(33, car, &Car::start, 100);
    }

    {
        Timer<int, const std::string &> t;
        t.single_shot(33, car, &Car::stop, 6, "I have to stop");
        t.set_interval(33, car, &Car::stop, 6, "I have to stop");
        t.set_timeout(33, car, &Car::stop, 6, "I have to stop");
    }
}

void func_start() {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << "started\n";
}

void func_start(Car *car) {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << "speed is " << car->speed() << "\n";
}

void func_report_speed(int max_allow_speed, const Car *car) {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << "max allowed is " << max_allow_speed << ". I am at " << car->speed() << "\n";
}

void func_stop(const Car *car, int hours, const std::string &msg) {
    std::lock_guard<std::mutex> guard(mutex);
    std::cout << msg << " after driving for " << hours << " hours. My speed was " << car->speed() << "\n";
}

void run_for_functions(Car *car) {

    Timer<>::single_shot(33, static_cast<void (*)(void)> (func_start));
    Timer<>::single_shot(33, overload<>(func_start));   // also works

    Timer<Car *>::single_shot(33, static_cast<void (*)(Car *)> (func_start), car);
    Timer<Car *>::single_shot(33, overload<Car *> (func_start), car);

    Timer<int, const Car *>::single_shot(33, func_report_speed, 120, car);

    Timer<const Car *, int, const std::string &>::single_shot(333, func_stop, car, 6, "I have to stop");

    {   // ---- no argument
        Timer<> t;
        t.single_shot(33, static_cast<void (*)(void)> (func_start));
        t.single_shot(33, overload<>(func_start));   // also works

        t.set_interval(33, static_cast<void (*)(void)> (func_start));
        t.set_interval(33, overload<>(func_start));   // also works

        t.set_timeout(33, static_cast<void (*)(void)> (func_start));
        t.set_timeout(33, overload<>(func_start));   // also works
    }

    {   // ---- one argument
        Timer<Car *> t;
        t.single_shot(33, static_cast<void (*)(Car *)> (func_start), car);
        t.single_shot(33, overload<Car*> (func_start), car);  // also works

        t.set_interval(33, static_cast<void (*)(Car *)> (func_start), car);
        t.set_interval(33, overload<Car*>  (func_start), car);  // also works

        t.set_timeout(33, static_cast<void (*)(Car *)> (func_start), car);
        t.set_timeout(33, overload<Car*> (func_start), car);  // also works
    }

    {   // ---- two argument
        Timer<int, const Car *> t;
        t.single_shot(33, func_report_speed, 120, car);
        t.set_interval(33, func_report_speed, 120, car);
        t.set_timeout(33, func_report_speed, 120, car);
    }

    {   // ---- three arguments
        Timer<const Car *, int, const std::string &> t;
        t.single_shot(333, func_stop, car, 6, "I have to stop");
        t.set_interval(333, func_stop, car, 6, "I have to stop");
        t.set_timeout(333, func_stop, car, 6, "I have to stop");
    }
}

void run_for_lambda_functions(Car *car) {
    auto lambda_start = []() -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "started\n";
    };

    auto lambda_start_1arg = [](Car *car) -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "speed is " << car->speed() << "\n";
    };

    auto lambda_report_speed = [](int max_allow_speed, const Car *car) -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << "max allowed is " << max_allow_speed << ". I am at " << car->speed() << "\n";
    };

    auto lambda_stop = [](const Car *car, int hours, const std::string &msg) -> void {
        std::lock_guard<std::mutex> guard(mutex);
        std::cout << msg << " after driving for " << hours << " hours. My speed was " << car->speed() << "\n";
    };

    Timer<>::single_shot(33, lambda_start);

    Timer<Car *>::single_shot(33, lambda_start_1arg, car);

    Timer<int, const Car *>::single_shot(33, lambda_report_speed, 120, car);

    Timer<const Car *, int, const std::string &>::single_shot(33, lambda_stop, car, 6, "I have to stop");

    {   // ---- no argument
        Timer<> t;
        t.single_shot(33, lambda_start);
        t.set_interval(33, lambda_start);
        t.set_timeout(33, lambda_start);
    }

    {   // ---- one argument
        Timer<Car *> t;
        t.single_shot(33, lambda_start_1arg, car);
        t.set_interval(33, lambda_start_1arg, car);
        t.set_timeout(33, lambda_start_1arg, car);
    }

    {   // ---- two argument
        Timer<int, const Car *> t;
        t.single_shot(33, lambda_report_speed, 120, car);
        t.set_interval(33, lambda_report_speed, 120, car);
        t.set_timeout(33, lambda_report_speed, 120, car);
    }

    {   // ---- three arguments
        Timer<const Car *, int, const std::string &> t;
        t.single_shot(333, lambda_stop, car, 6, "I have to stop");
        t.set_interval(333, lambda_stop, car, 6, "I have to stop");
        t.set_timeout(333, lambda_stop, car, 6, "I have to stop");
    }
}

bool test_timer() {
    Car car(100);

    std::cout << "triggers a class member ------------------------------------------------------------------\n\n";
    run_for_members(&car);
    std::this_thread::sleep_for(std::chrono::seconds(1));

    std::cout << "\n\ntriggers a function ------------------------------------------------------------------\n\n";
    run_for_functions(&car);
    std::this_thread::sleep_for(std::chrono::seconds(1));

    std::cout << "\n\ntriggers a lambda function -----------------------------------------------------------\n\n";
    run_for_lambda_functions(&car);
    std::this_thread::sleep_for(std::chrono::seconds(3));

    return EXIT_SUCCESS;
}


ArmSubsystem::ArmSubsystem()
    : frc2::TrapezoidProfileSubsystem<units::radians>(
          {kMaxVelocity, kMaxAcceleration}, kArmOffset),
      m_motor(kMotorPort),
      m_feedforward(kS, kCos, kV, kA)

#include "subsystems/ArmSubsystem.h"

#include "Constants.h"

using namespace ArmConstants;
using State = frc::TrapezoidProfile<units::radians>::State;

{
  m_motor.SetPID(kP, 0, 0);
}

void ArmSubsystem::UseState(State setpoint) {
  // Calculate the feedforward from the sepoint
  units::volt_t feedforward =
      m_feedforward.Calculate(setpoint.position, setpoint.velocity);
  // Add the feedforward to the PID output to get the motor output
  m_motor.SetSetpoint(ExampleSmartMotorController::PIDMode::kPosition,
                      setpoint.position.value(), feedforward / 12_V);
}


{
  // Calculate the feedforward from the sepoint
  units::volt_t feedforward =
      m_feedforward.Calculate(setpoint.position, setpoint.velocity);
  // Add the feedforward to the PID output to get the motor output
  m_motor.SetSetpoint(ExampleSmartMotorController::PIDMode::kPosition,
                      setpoint.position.value(), feedforward / 12_V);
}

#include "subsystems/ArmSubsystem.h"

#include "Constants.h"

using namespace ArmConstants;
using State = frc::TrapezoidProfile<units::radians>::State;

ArmSubsystem::ArmSubsystem()
    : frc2::TrapezoidProfileSubsystem<units::radians>(
          {kMaxVelocity, kMaxAcceleration}, kArmOffset),
      m_motor(kMotorPort),
      m_feedforward(kS, kCos, kV, kA) {
  m_motor.SetPID(kP, 0, 0);
}

void ArmSubsystem::UseState(State setpoint)


{
  // Calculate the feedforward from the sepoint

  units::volt_t feedforward =
      m_feedforward.Calculate(setpoint.position, setpoint.velocity);
  // Add the feedforward to the PID output to get the motor output
  m_motor.SetSetpoint(ExampleSmartMotorController::PIDMode::kPosition,
                      setpoint.position.value(), feedforward / 12_V);
}


units::volt_t feedforward =
      m_feedforward.Calculate(setpoint.position, setpoint.velocity);
  // Add the feedforward to the PID output to get the motor output

#include "subsystems/ArmSubsystem.h"

#include "Constants.h"

using namespace ArmConstants;
using State = frc::TrapezoidProfile<units::radians>::State;

ArmSubsystem::ArmSubsystem()
    : frc2::TrapezoidProfileSubsystem<units::radians>(
          {kMaxVelocity, kMaxAcceleration}, kArmOffset),
      m_motor(kMotorPort),
      m_feedforward(kS, kCos, kV, kA) {
  m_motor.SetPID(kP, 0, 0);
}

void ArmSubsystem::UseState(State setpoint) {
  // Calculate the feedforward from the sepoint

  m_motor.SetSetpoint(ExampleSmartMotorController::PIDMode::kPosition,
                      setpoint.position.value(), feedforward / 12_V);
}


m_motor.SetSetpoint(ExampleSmartMotorController::PIDMode::kPosition,
                      setpoint.position.value(), feedforward / 12_V);
}

#include "subsystems/ArmSubsystem.h"

#include "Constants.h"

using namespace ArmConstants;
using State = frc::TrapezoidProfile<units::radians>::State;

ArmSubsystem::ArmSubsystem()
    : frc2::TrapezoidProfileSubsystem<units::radians>(
          {kMaxVelocity, kMaxAcceleration}, kArmOffset),
      m_motor(kMotorPort),
      m_feedforward(kS, kCos, kV, kA) {
  m_motor.SetPID(kP, 0, 0);
}

void ArmSubsystem::UseState(State setpoint) {
  // Calculate the feedforward from the sepoint
  units::volt_t feedforward =
      m_feedforward.Calculate(setpoint.position, setpoint.velocity);
  // Add the feedforward to the PID output to get the motor output


#include "subsystems/ArmSubsystem.h"

#include "Constants.h"

using namespace ArmConstants;
using State = frc::TrapezoidProfile<units::radians>::State;

ArmSubsystem::ArmSubsystem()
    : frc2::TrapezoidProfileSubsystem<units::radians>(
          {kMaxVelocity, kMaxAcceleration}, kArmOffset),
      m_motor(kMotorPort),
      m_feedforward(kS, kCos, kV, kA) {
  m

}

void ArmSubsystem::UseState(State setpoint) {
  // Calculate the feedforward from the sepoint
  units::volt_t feedforward =
      m_feedforward.Calculate(setpoint.position, setpoint.velocity);
  // Add the feedforward to the PID output to get the motor output
  m_motor.SetSetpoint(ExampleSmartMotorController::PIDMode::kPosition,
                      setpoint.position.value(), feedforward / 12_V);
}


#include "subsystems/ArmSubsystem.h"

#include "Constants.h"

using namespace ArmConstants;
using State = frc::TrapezoidProfile<units::radians>::State;

ArmSubsystem::ArmSubsystem()
    : frc2::TrapezoidProfileSubsystem<units::radians>(
          {kMaxVelocity, kMaxAcceleration}, kArmOffset),
      m_motor(kMotorPort),
      m_feedforward(kS, kCos, kV, kA) {
  m_motor.SetPID(kP, 0, 0);
}

void ArmSubsystem::UseState(State

setpoint) {
  // Calculate the feedforward from the sepoint
  units::volt_t feedforward =
      m_feedforward.Calculate(setpoint.position, setpoint.velocity);
  // Add the feedforward to the PID output to get the motor output
  m_motor.SetSetpoint(ExampleSmartMotorController::PIDMode::kPosition,
                      setpoint.position.value(), feedforward / 12_V);
}


// This sample enumerates all the tasks registered in the root task
// folder on the local computer and displays their name and status.

#define _WIN32_DCOM

#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <comdef.h>
//  Include the task header file.
#include "rpcsal.h"
#include "taskschd.h"
# pragma comment(lib, "taskschd.lib")
# pragma comment(lib, "comsupp.lib")

using namespace std;

{
    //  Initialize COM.
    HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    if( FAILED(hr) )
    {
        printf("\nCoInitializeEx failed: %x", hr );
        return;
    }

    //  Set general COM security levels.
    hr = CoInitializeSecurity(
        NULL,
        -1,
        NULL,
        NULL,
        RPC_C_AUTHN_LEVEL_PKT,
        RPC_C_IMP_LEVEL_IMPERSONATE,
        NULL,
        0,
        NULL);
    if( FAILED(hr) )
    {
        printf("\nCoInitializeSecurity failed: %x", hr );
        return;
    }

    //  Create an instance of the Task Service.
    ITaskService *pService = NULL;
    hr = CoCreateInstance( CLSID_TaskScheduler,
                           NULL,
                           CLSCTX_INPROC_SERVER,
                           IID_ITaskService,
                           (void**)&pService );
    if( FAILED(hr) )
    {
          printf("Failed to CoCreate an instance of the TaskService class: %x", hr);
          CoUninitialize();
          return;
    }

    //  Connect to the local task service.
    hr = pService->Connect(_variant_t(), _variant_t(),
        _variant_t(), _variant_t());
    if( FAILED(hr) )
    {
        printf("ITaskService::Connect failed: %x", hr );
        pService->Release();
        CoUninitialize();
        return;
    }

    //  Get the pointer to the root task folder.
    ITaskFolder *pRootFolder = NULL;
    hr = pService->GetFolder( _bstr_t( L"\\") , &pRootFolder );

    pService->Release();
    if( FAILED(hr) )
    {
        printf("Cannot get Root Folder pointer: %x", hr );
        CoUninitialize();
        return;
    }

    //  Get the registered tasks in the folder.
    IRegisteredTaskCollection* pTaskCollection = NULL;
    hr = pRootFolder->GetTasks( NULL, &pTaskCollection );

    pRootFolder->Release();
    if( FAILED(hr) )
    {
        printf("Cannot get the registered tasks.: %x", hr);
        CoUninitialize();
        return;
    }

    LONG numTasks = 0;
    hr = pTaskCollection->get_Count(&numTasks);
    if( FAILED(hr) )
    {
        printf("Cannot get the task collection.: %x", hr);
        CoUninitialize();
        return;
    }

    if( numTasks == 0 )
    {
        printf("\nNo Tasks are currently running");
        pTaskCollection->Release();
        CoUninitialize();
        return;
    }

    printf("\nNumber of Tasks : %d", numTasks );

    //  Visit each task in the folder.
    for(LONG i=0; i < numTasks; i++)
    {
        IRegisteredTask* pRegisteredTask = NULL;
        _bstr_t taskName;
        TASK_STATE taskState;
        _bstr_t taskStateStr;

        hr = pTaskCollection->get_Item( _variant_t(i+1), &pRegisteredTask );
        if( FAILED(hr) )
        {
            printf("Cannot get the registered task: %x", hr);
            continue;
        }

        hr = pRegisteredTask->get_Name(taskName.GetAddress());
        if( FAILED(hr) )
        {
            printf("Cannot get the registered task name: %x", hr);
            pRegisteredTask->Release();
            continue;
        }

        hr = pRegisteredTask->get_State(&taskState);
        if( FAILED(hr) )
        {
            printf("Cannot get the registered task state: %x", hr);
        }
        else
        {
            printf("\n\nTask Name: %S", (LPCWSTR)taskName);

            switch(taskState)
            {
            case TASK_STATE_DISABLED:
                taskStateStr = "disabled";
                break;
            case TASK_STATE_QUEUED:
                taskStateStr = "queued";
                break;
            case TASK_STATE_READY:
                taskStateStr = "ready";
                break;
            case TASK_STATE_RUNNING:
                taskStateStr = "running";
                break;
            default:
                taskStateStr = "unknown";
                break;
            }
            printf("\n\tState: %s", (LPCSTR)taskStateStr);
        }

        pRegisteredTask->Release();
    }

    pTaskCollection->Release();
    CoUninitialize();
    return;
}


{
    //  Initialize COM.
    HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    if( FAILED(hr) )
    {
        printf("\nCoInitializeEx failed: %x", hr );
        return;
    }

    //  Set general COM security levels.
    hr = CoInitializeSecurity(
        NULL,
        -1,
        NULL,
        NULL,
        RPC_C_AUTHN_LEVEL_PKT,
        RPC_C_IMP_LEVEL_IMPERSONATE,
        NULL,
        0,
        NULL);
    if( FAILED(hr) )
    {
        printf("\nCoInitializeSecurity failed: %x", hr );
        return;
    }

    //  Create an instance of the Task Service.
    ITaskService *pService = NULL;
    hr = CoCreateInstance( CLSID_TaskScheduler,
                           NULL,
                           CLSCTX_INPROC_SERVER,
                           IID_ITaskService,
                           (void**)&pService );
    if( FAILED(hr) )
    {
          printf("Failed to CoCreate an instance of the TaskService class: %x", hr);
          CoUninitialize();
          return;
    }

    //  Connect to the local task service.

// This sample enumerates all the tasks registered in the root task
// folder on the local computer and displays their name and status.

#define _WIN32_DCOM

#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <comdef.h>
//  Include the task header file.
#include "rpcsal.h"
#include "taskschd.h"
# pragma comment(lib, "taskschd.lib")
# pragma comment(lib, "comsupp.lib")

using namespace std;

void main(void)

    hr = pService->Connect(_variant_t(), _variant_t(),
        _variant_t(), _variant_t());
    if( FAILED(hr) )
    {
        printf("ITaskService::Connect failed: %x", hr );
        pService->Release();
        CoUninitialize();
        return;
    }

    //  Get the pointer to the root task folder.
    ITaskFolder *pRootFolder = NULL;
    hr = pService->GetFolder( _bstr_t( L"\\") , &pRootFolder );

    pService->Release();
    if( FAILED(hr) )
    {
        printf("Cannot get Root Folder pointer: %x", hr );
        CoUninitialize();
        return;
    }

    //  Get the registered tasks in the folder.
    IRegisteredTaskCollection* pTaskCollection = NULL;
    hr = pRootFolder->GetTasks( NULL, &pTaskCollection );

    pRootFolder->Release();
    if( FAILED(hr) )
    {
        printf("Cannot get the registered tasks.: %x", hr);
        CoUninitialize();
        return;
    }

    LONG numTasks = 0;
    hr = pTaskCollection->get_Count(&numTasks);
    if( FAILED(hr) )
    {
        printf("Cannot get the task collection.: %x", hr);
        CoUninitialize();
        return;
    }

    if( numTasks == 0 )
    {
        printf("\nNo Tasks are currently running");
        pTaskCollection->Release();
        CoUninitialize();
        return;
    }

    printf("\nNumber of Tasks : %d", numTasks );

    //  Visit each task in the folder.
    for(LONG i=0; i < numTasks; i++)
    {
        IRegisteredTask* pRegisteredTask = NULL;
        _bstr_t taskName;
        TASK_STATE taskState;
        _bstr_t taskStateStr;

        hr = pTaskCollection->get_Item( _variant_t(i+1), &pRegisteredTask );
        if( FAILED(hr) )
        {
            printf("Cannot get the registered task: %x", hr);
            continue;
        }

        hr = pRegisteredTask->get_Name(taskName.GetAddress());
        if( FAILED(hr) )
        {
            printf("Cannot get the registered task name: %x", hr);
            pRegisteredTask->Release();
            continue;
        }

        hr = pRegisteredTask->get_State(&taskState);
        if( FAILED(hr) )
        {
            printf("Cannot get the registered task state: %x", hr);
        }
        else
        {
            printf("\n\nTask Name: %S", (LPCWSTR)taskName);

            switch(taskState)
            {
            case TASK_STATE_DISABLED:
                taskStateStr = "disabled";
                break;
            case TASK_STATE_QUEUED:
                taskStateStr = "queued";
                break;
            case TASK_STATE_READY:
                taskStateStr = "ready";
                break;
            case TASK_STATE_RUNNING:
                taskStateStr = "running";
                break;
            default:
                taskStateStr = "unknown";
                break;
            }
            printf("\n\tState: %s", (LPCSTR)taskStateStr);
        }

        pRegisteredTask->Release();
    }

    pTaskCollection->Release();
    CoUninitialize();
    return;
}


hr = pService->Connect(_variant_t(), _variant_t(),
        _variant_t(), _variant_t());
    if( FAILED(hr) )
    {
        printf("ITaskService::Connect failed: %x", hr );
        pService->Release();
        CoUninitialize();
        return;
    }

    //  Get the pointer to the root task folder.
    ITaskFolder *pRootFolder = NULL;
    hr = pService->GetFolder( _bstr_t( L"\\") , &pRootFolder );

    pService->Release();
    if( FAILED(hr) )
    {
        printf("Cannot get Root Folder pointer: %x", hr );
        CoUninitialize();
        return;
    }

    //  Get the registered tasks in the folder.
    IRegisteredTaskCollection* pTaskCollection = NULL;
    hr = pRootFolder->GetTasks( NULL, &pTaskCollection );

    pRootFolder->Release();

// This sample enumerates all the tasks registered in the root task
// folder on the local computer and displays their name and status.

#define _WIN32_DCOM

#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <comdef.h>
//  Include the task header file.
#include "rpcsal.h"
#include "taskschd.h"
# pragma comment(lib, "taskschd.lib")
# pragma comment(lib, "comsupp.lib")

using namespace std;

void main(void)
{
    //  Initialize COM.
    HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    if( FAILED(hr) )
    {
        printf("\nCoInitializeEx failed: %x", hr );
        return;
    }

    //  Set general COM security levels.
    hr = CoInitializeSecurity(
        NULL,
        -1,
        NULL,
        NULL,
        RPC_C_AUTHN_LEVEL_PKT,
        RPC_C_IMP_LEVEL_IMPERSONATE,
        NULL,
        0,
        NULL);
    if( FAILED(hr) )
    {
        printf("\nCoInitializeSecurity failed: %x", hr );
        return;
    }

    //  Create an instance of the Task Service.
    ITaskService *pService = NULL;
    hr = CoCreateInstance( CLSID_TaskScheduler,
                           NULL,
                           CLSCTX_INPROC_SERVER,
                           IID_ITaskService,
                           (void**)&pService );
    if( FAILED(hr) )
    {
          printf("Failed to CoCreate an instance of the TaskService class: %x", hr);
          CoUninitialize();
          return;
    }

    //  Connect to the local task service.

    if( FAILED(hr) )
    {
        printf("Cannot get the registered tasks.: %x", hr);
        CoUninitialize();
        return;
    }

    LONG numTasks = 0;
    hr = pTaskCollection->get_Count(&numTasks);
    if( FAILED(hr) )
    {
        printf("Cannot get the task collection.: %x", hr);
        CoUninitialize();
        return;
    }

    if( numTasks == 0 )
    {
        printf("\nNo Tasks are currently running");
        pTaskCollection->Release();
        CoUninitialize();
        return;
    }

    printf("\nNumber of Tasks : %d", numTasks );

    //  Visit each task in the folder.
    for(LONG i=0; i < numTasks; i++)
    {
        IRegisteredTask* pRegisteredTask = NULL;
        _bstr_t taskName;
        TASK_STATE taskState;
        _bstr_t taskStateStr;

        hr = pTaskCollection->get_Item( _variant_t(i+1), &pRegisteredTask );
        if( FAILED(hr) )
        {
            printf("Cannot get the registered task: %x", hr);
            continue;
        }

        hr = pRegisteredTask->get_Name(taskName.GetAddress());
        if( FAILED(hr) )
        {
            printf("Cannot get the registered task name: %x", hr);
            pRegisteredTask->Release();
            continue;
        }

        hr = pRegisteredTask->get_State(&taskState);
        if( FAILED(hr) )
        {
            printf("Cannot get the registered task state: %x", hr);
        }
        else
        {
            printf("\n\nTask Name: %S", (LPCWSTR)taskName);

            switch(taskState)
            {
            case TASK_STATE_DISABLED:
                taskStateStr = "disabled";
                break;
            case TASK_STATE_QUEUED:
                taskStateStr = "queued";
                break;
            case TASK_STATE_READY:
                taskStateStr = "ready";
                break;
            case TASK_STATE_RUNNING:
                taskStateStr = "running";
                break;
            default:
                taskStateStr = "unknown";
                break;
            }
            printf("\n\tState: %s", (LPCSTR)taskStateStr);
        }

        pRegisteredTask->Release();
    }

    pTaskCollection->Release();
    CoUninitialize();
    return;
}


if( FAILED(hr) )
    {
        printf("Cannot get the registered tasks.: %x", hr);
        CoUninitialize();
        return;
    }

    LONG numTasks = 0;
    hr = pTaskCollection->get_Count(&numTasks);
    if( FAILED(hr) )
    {
        printf("Cannot get the task collection.: %x", hr);
        CoUninitialize();
        return;
    }

    if( numTasks == 0 )
    {
        printf("\nNo Tasks are currently running");
        pTaskCollection->Release();
        CoUninitialize();
        return;
    }

    printf("\nNumber of Tasks : %d", numTasks );

    //  Visit each task in the folder.
    for(LONG i=0; i < numTasks; i++)
    {
        IRegisteredTask* pRegisteredTask = NULL;
        _bstr_t taskName;
        TASK_STATE taskState;
        _bstr_t taskStateStr;

        hr = pTaskCollection->get_Item( _variant_t(i+1), &pRegisteredTask );
        if( FAILED(hr) )
        {
            printf("Cannot get the registered task: %x", hr);
            continue;
        }

        hr = pRegisteredTask->get_Name(taskName.GetAddress());
        if( FAILED(hr) )
        {
            printf("Cannot get the registered task name: %x", hr);
            pRegisteredTask->Release();
            continue;
        }

        hr = pRegisteredTask->get_State(&taskState);
        if( FAILED(hr) )
        {
            printf("Cannot get the registered task state: %x", hr);
        }
        else
        {
            printf("\n\nTask Name: %S", (LPCWSTR)taskName);

            switch(taskState)
            {
            case TASK_STATE_DISABLED:
                taskStateStr = "disabled";
                break;
            case TASK_STATE_QUEUED:
                taskStateStr = "queued";
                break;
            case TASK_STATE_READY:
                taskStateStr = "ready";
                break;
            case TASK_STATE_RUNNING:
                taskStateStr = "running";
                break;
            default:
                taskStateStr = "unknown";
                break;
            }
            printf("\n\tState: %s", (LPCSTR)taskStateStr);
        }

        pRegisteredTask->Release();
    }

    pTaskCollection->Release();
    CoUninitialize();
    return;
}

// This sample enumerates all the tasks registered in the root task
// folder on the local computer and displays their name and status.

#define _WIN32_DCOM

#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <comdef.h>
//  Include the task header file.
#include "rpcsal.h"
#include "taskschd.h"
# pragma comment(lib, "taskschd.lib")
# pragma comment(lib, "comsupp.lib")

using namespace std;

void main(void)
{
    //  Initialize COM.
    HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    if( FAILED(hr) )
    {
        printf("\nCoInitializeEx failed: %x", hr );
        return;
    }

    //  Set general COM security levels.
    hr = CoInitializeSecurity(
        NULL,
        -1,
        NULL,
        NULL,
        RPC_C_AUTHN_LEVEL_PKT,
        RPC_C_IMP_LEVEL_IMPERSONATE,
        NULL,
        0,
        NULL);
    if( FAILED(hr) )
    {
        printf("\nCoInitializeSecurity failed: %x", hr );
        return;
    }

    //  Create an instance of the Task Service.
    ITaskService *pService = NULL;
    hr = CoCreateInstance( CLSID_TaskScheduler,
                           NULL,
                           CLSCTX_INPROC_SERVER,
                           IID_ITaskService,
                           (void**)&pService );
    if( FAILED(hr) )
    {
          printf("Failed to CoCreate an instance of the TaskService class: %x", hr);
          CoUninitialize();
          return;
    }

    //  Connect to the local task service.
    hr = pService->Connect(_variant_t(), _variant_t(),
        _variant_t(), _variant_t());
    if( FAILED(hr) )
    {
        printf("ITaskService::Connect failed: %x", hr );
        pService->Release();
        CoUninitialize();
        return;
    }

    //  Get the pointer to the root task folder.
    ITaskFolder *pRootFolder = NULL;
    hr = pService->GetFolder( _bstr_t( L"\\") , &pRootFolder );

    pService->Release();
    if( FAILED(hr) )
    {
        printf("Cannot get Root Folder pointer: %x", hr );
        CoUninitialize();
        return;
    }

    //  Get the registered tasks in the folder.
    IRegisteredTaskCollection* pTaskCollection = NULL;
    hr = pRootFolder->GetTasks( NULL, &pTaskCollection );

    pRootFolder->Release();


rintf("\nNumber of Tasks : %d", numTasks );

// This sample enumerates all the tasks registered in the root task
// folder on the local computer and displays their name and status.

#define _WIN32_DCOM

#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <comdef.h>
//  Include the task header file.
#include "rpcsal.h"
#include "taskschd.h"
# pragma comment(lib, "taskschd.lib")
# pragma comment(lib, "comsupp.lib")

using namespace std;

void main(void)
{
    //  Initialize COM.
    HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    if( FAILED(hr) )
    {
        printf("\nCoInitializeEx failed: %x", hr );
        return;
    }

    //  Set general COM security levels.
    hr = CoInitializeSecurity(
        NULL,
        -1,
        NULL,
        NULL,
        RPC_C_AUTHN_LEVEL_PKT,
        RPC_C_IMP_LEVEL_IMPERSONATE,
        NULL,
        0,
        NULL);
    if( FAILED(hr) )
    {
        printf("\nCoInitializeSecurity failed: %x", hr );
        return;
    }

    //  Create an instance of the Task Service.
    ITaskService *pService = NULL;
    hr = CoCreateInstance( CLSID_TaskScheduler,
                           NULL,
                           CLSCTX_INPROC_SERVER,
                           IID_ITaskService,
                           (void**)&pService );
    if( FAILED(hr) )
    {
          printf("Failed to CoCreate an instance of the TaskService class: %x", hr);
          CoUninitialize();
          return;
    }

    //  Connect to the local task service.
    hr = pService->Connect(_variant_t(), _variant_t(),
        _variant_t(), _variant_t());
    if( FAILED(hr) )
    {
        printf("ITaskService::Connect failed: %x", hr );
        pService->Release();
        CoUninitialize();
        return;
    }

    //  Get the pointer to the root task folder.
    ITaskFolder *pRootFolder = NULL;
    hr = pService->GetFolder( _bstr_t( L"\\") , &pRootFolder );

    pService->Release();
    if( FAILED(hr) )
    {
        printf("Cannot get Root Folder pointer: %x", hr );
        CoUninitialize();
        return;
    }

    //  Get the registered tasks in the folder.
    IRegisteredTaskCollection* pTaskCollection = NULL;
    hr = pRootFolder->GetTasks( NULL, &pTaskCollection );

    pRootFolder->Release();
    if( FAILED(hr) )
    {
        printf("Cannot get the registered tasks.: %x", hr);
        CoUninitialize();
        return;
    }

    LONG numTasks = 0;
    hr = pTaskCollection->get_Count(&numTasks);
    if( FAILED(hr) )
    {
        printf("Cannot get the task collection.: %x", hr);
        CoUninitialize();
        return;
    }

    if( numTasks == 0 )
    {
        printf("\nNo Tasks are currently running");
        pTaskCollection->Release();
        CoUninitialize();
        return;
    }

    p

    //  Visit each task in the folder.
    for(LONG i=0; i < numTasks; i++)
    {
        IRegisteredTask* pRegisteredTask = NULL;
        _bstr_t taskName;
        TASK_STATE taskState;
        _bstr_t taskStateStr;

        hr = pTaskCollection->get_Item( _variant_t(i+1), &pRegisteredTask );
        if( FAILED(hr) )
        {
            printf("Cannot get the registered task: %x", hr);
            continue;
        }

        hr = pRegisteredTask->get_Name(taskName.GetAddress());
        if( FAILED(hr) )
        {
            printf("Cannot get the registered task name: %x", hr);
            pRegisteredTask->Release();
            continue;
        }

        hr = pRegisteredTask->get_State(&taskState);
        if( FAILED(hr) )
        {
            printf("Cannot get the registered task state: %x", hr);
        }
        else
        {
            printf("\n\nTask Name: %S", (LPCWSTR)taskName);

            switch(taskState)
            {
            case TASK_STATE_DISABLED:
                taskStateStr = "disabled";
                break;
            case TASK_STATE_QUEUED:
                taskStateStr = "queued";
                break;
            case TASK_STATE_READY:
                taskStateStr = "ready";
                break;
            case TASK_STATE_RUNNING:
                taskStateStr = "running";
                break;
            default:
                taskStateStr = "unknown";
                break;
            }
            printf("\n\tState: %s", (LPCSTR)taskStateStr);
        }

        pRegisteredTask->Release();
    }

    pTaskCollection->Release();
    CoUninitialize();
    return;
}


if( FAILED(hr) )
        {
            printf("Cannot get the registered task: %x", hr);
            continue;
        }

// This sample enumerates all the tasks registered in the root task
// folder on the local computer and displays their name and status.

#define _WIN32_DCOM

#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <comdef.h>
//  Include the task header file.
#include "rpcsal.h"
#include "taskschd.h"
# pragma comment(lib, "taskschd.lib")
# pragma comment(lib, "comsupp.lib")

using namespace std;

void main(void)
{
    //  Initialize COM.
    HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    if( FAILED(hr) )
    {
        printf("\nCoInitializeEx failed: %x", hr );
        return;
    }

    //  Set general COM security levels.
    hr = CoInitializeSecurity(
        NULL,
        -1,
        NULL,
        NULL,
        RPC_C_AUTHN_LEVEL_PKT,
        RPC_C_IMP_LEVEL_IMPERSONATE,
        NULL,
        0,
        NULL);
    if( FAILED(hr) )
    {
        printf("\nCoInitializeSecurity failed: %x", hr );
        return;
    }

    //  Create an instance of the Task Service.
    ITaskService *pService = NULL;
    hr = CoCreateInstance( CLSID_TaskScheduler,
                           NULL,
                           CLSCTX_INPROC_SERVER,
                           IID_ITaskService,
                           (void**)&pService );
    if( FAILED(hr) )
    {
          printf("Failed to CoCreate an instance of the TaskService class: %x", hr);
          CoUninitialize();
          return;
    }

    //  Connect to the local task service.
    hr = pService->Connect(_variant_t(), _variant_t(),
        _variant_t(), _variant_t());
    if( FAILED(hr) )
    {
        printf("ITaskService::Connect failed: %x", hr );
        pService->Release();
        CoUninitialize();
        return;
    }

    //  Get the pointer to the root task folder.
    ITaskFolder *pRootFolder = NULL;
    hr = pService->GetFolder( _bstr_t( L"\\") , &pRootFolder );

    pService->Release();
    if( FAILED(hr) )
    {
        printf("Cannot get Root Folder pointer: %x", hr );
        CoUninitialize();
        return;
    }

    //  Get the registered tasks in the folder.
    IRegisteredTaskCollection* pTaskCollection = NULL;
    hr = pRootFolder->GetTasks( NULL, &pTaskCollection );

    pRootFolder->Release();
    if( FAILED(hr) )
    {
        printf("Cannot get the registered tasks.: %x", hr);
        CoUninitialize();
        return;
    }

    LONG numTasks = 0;
    hr = pTaskCollection->get_Count(&numTasks);
    if( FAILED(hr) )
    {
        printf("Cannot get the task collection.: %x", hr);
        CoUninitialize();
        return;
    }

    if( numTasks == 0 )
    {
        printf("\nNo Tasks are currently running");
        pTaskCollection->Release();
        CoUninitialize();
        return;
    }

    printf("\nNumber of Tasks : %d", numTasks );

    //  Visit each task in the folder.
    for(LONG i=0; i < numTasks; i++)
    {
        IRegisteredTask* pRegisteredTask = NULL;
        _bstr_t taskName;
        TASK_STATE taskState;
        _bstr_t taskStateStr;

        hr = pTaskCollection->get_Item( _variant_t(i+1), &pRegisteredTask );

        hr = pRegisteredTask->get_Name(taskName.GetAddress());
        if( FAILED(hr) )
        {
            printf("Cannot get the registered task name: %x", hr);
            pRegisteredTask->Release();
            continue;
        }

        hr = pRegisteredTask->get_State(&taskState);
        if( FAILED(hr) )
        {
            printf("Cannot get the registered task state: %x", hr);
        }
        else
        {
            printf("\n\nTask Name: %S", (LPCWSTR)taskName);

            switch(taskState)
            {
            case TASK_STATE_DISABLED:
                taskStateStr = "disabled";
                break;
            case TASK_STATE_QUEUED:
                taskStateStr = "queued";
                break;
            case TASK_STATE_READY:
                taskStateStr = "ready";
                break;
            case TASK_STATE_RUNNING:
                taskStateStr = "running";
                break;
            default:
                taskStateStr = "unknown";
                break;
            }
            printf("\n\tState: %s", (LPCSTR)taskStateStr);
        }

        pRegisteredTask->Release();
    }

    pTaskCollection->Release();
    CoUninitialize();
    return;
}


// This sample enumerates all the tasks registered in the root task
// folder on the local computer and displays their name and status.

#define _WIN32_DCOM

#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <comdef.h>
//  Include the task header file.
#include "rpcsal.h"
#include "taskschd.h"
# pragma comment(lib, "taskschd.lib")
# pragma comment(lib, "comsupp.lib")

using namespace std;

void main(void)
{
    //  Initialize COM.
    HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    if( FAILED(hr) )
    {
        printf("\nCoInitializeEx failed: %x", hr );
        return;
    }

    //  Set general COM security levels.
    hr = CoInitializeSecurity(
        NULL,
        -1,
        NULL,
        NULL,
        RPC_C_AUTHN_LEVEL_PKT,
        RPC_C_IMP_LEVEL_IMPERSONATE,
        NULL,
        0,
        NULL);
    if( FAILED(hr) )
    {
        printf("\nCoInitializeSecurity failed: %x", hr );
        return;
    }

    //  Create an instance of the Task Service.
    ITaskService *pService = NULL;
    hr = CoCreateInstance( CLSID_TaskScheduler,
                           NULL,
                           CLSCTX_INPROC_SERVER,
                           IID_ITaskService,
                           (void**)&pService );
    if( FAILED(hr) )
    {
          printf("Failed to CoCreate an instance of the TaskService class: %x", hr);
          CoUninitialize();
          return;
    }

    //  Connect to the local task service.
    hr = pService->Connect(_variant_t(), _variant_t(),
        _variant_t(), _variant_t());
    if( FAILED(hr) )
    {
        printf("ITaskService::Connect failed: %x", hr );
        pService->Release();
        CoUninitialize();
        return;
    }

    //  Get the pointer to the root task folder.
    ITaskFolder *pRootFolder = NULL;
    hr = pService->GetFolder( _bstr_t( L"\\") , &pRootFolder );

    pService->Release();
    if( FAILED(hr) )
    {
        printf("Cannot get Root Folder pointer: %x", hr );
        CoUninitialize();
        return;
    }

    //  Get the registered tasks in the folder.
    IRegisteredTaskCollection* pTaskCollection = NULL;
    hr = pRootFolder->GetTasks( NULL, &pTaskCollection );

    pRootFolder->Release();
    if( FAILED(hr) )
    {
        printf("Cannot get the registered tasks.: %x", hr);
        CoUninitialize();
        return;
    }

    LONG numTasks = 0;
    hr = pTaskCollection->get_Count(&numTasks);
    if( FAILED(hr) )
    {
        printf("Cannot get the task collection.: %x", hr);
        CoUninitialize();
        return;
    }

    if( numTasks == 0 )
    {
        printf("\nNo Tasks are currently running");
        pTaskCollection->Release();
        CoUninitialize();
        return;
    }

    printf("\nNumber of Tasks : %d", numTasks );

    //  Visit each task in the folder.
    for(LONG i=0; i < numTasks; i++)
    {
        IRegisteredTask* pRegisteredTask = NULL;
        _bstr_t taskName;
        TASK_STATE taskState;
        _bstr_t taskStateStr;

        hr = pTaskCollection->get_Item( _variant_t(i+1), &pRegisteredTask );
        if( FAILED(hr) )

       {
            printf("Cannot get the registered task: %x", hr);
            continue;
        }

        hr = pRegisteredTask->get_Name(taskName.GetAddress());
        if( FAILED(hr) )
        {
            printf("Cannot get the registered task name: %x", hr);
            pRegisteredTask->Release();
            continue;
        }

        hr = pRegisteredTask->get_State(&taskState);
        if( FAILED(hr) )
        {
            printf("Cannot get the registered task state: %x", hr);
        }
        else
        {
            printf("\n\nTask Name: %S", (LPCWSTR)taskName);

            switch(taskState)
            {
            case TASK_STATE_DISABLED:
                taskStateStr = "disabled";
                break;
            case TASK_STATE_QUEUED:
                taskStateStr = "queued";
                break;
            case TASK_STATE_READY:
                taskStateStr = "ready";
                break;
            case TASK_STATE_RUNNING:
                taskStateStr = "running";
                break;
            default:
                taskStateStr = "unknown";
                break;
            }
            printf("\n\tState: %s", (LPCSTR)taskStateStr);
        }

        pRegisteredTask->Release();
    }

    pTaskCollection->Release();
    CoUninitialize();
    return;
}