#include "./std_headers.h"

#include <atomic>

struct AsyncJoy {
  AsyncJoy(std::function<void(string const &err)> const &_cb);
  ~AsyncJoy();

  AsyncJoy(AsyncJoy const &) = delete;
  AsyncJoy(AsyncJoy &&) = delete;
  AsyncJoy &operator=(AsyncJoy const &) = delete;
  AsyncJoy &operator=(AsyncJoy &&) = delete;

  std::function<void(string const &err)> cb;
  std::atomic<int> started;
  std::atomic<int> pending;
  std::atomic<int> triggered;
  std::atomic<int> errors;
  std::mutex errorAccumMutex;
  string errorAccum;

  string progress();
  
  double fractionDone()
  {
    return double(started - pending) / double(started);
  }

  void start() noexcept
  {
    started++;
    pending++;
  }

  void error(string const &str)
  {
    setError(str);
    end();
  }

  void setError(string const &str);
  void runCallbacks();

  bool hasError() const
  {
    return errors > 0;
  }

  void end()
  {
    if (--pending == 0) {
      runCallbacks();
    }
  }

};
