explicit TaskScheduler(P&& predicate)
        : self_reference(this, [](TaskScheduler const*) { }), _now(clock_t::now()), _predicate(std::forward(predicate)) { }
    TaskScheduler(TaskScheduler const&) = delete;
    TaskScheduler(TaskScheduler&&) = delete;
    TaskScheduler& operator= (TaskScheduler const&) = delete;
    TaskScheduler& operator= (TaskScheduler&&) = delete;
    ~TaskScheduler();
    /// Sets a validator which is asked if tasks are allowed to be executed.
    template
    TaskScheduler& SetValidator(P&& predicate)
    {
        _predicate = std::forward(predicate);
        return *this;
    }
    /// Clears the validator which is asked if tasks are allowed to be executed.
    TaskScheduler& ClearValidator();
    /// Update the scheduler to the current time.
    /// Calls the optional callback on successfully finish.
    TaskScheduler& Update(success_t const& callback = nullptr);
    /// Update the scheduler with a difftime in ms.
    /// Calls the optional callback on successfully finish.
    TaskScheduler& Update(size_t milliseconds, success_t const& callback = nullptr);
    /// Update the scheduler with a difftime.
    /// Calls the optional callback on successfully finish.
    TaskScheduler& Update(duration_t difftime, success_t const& callback = nullptr);
    /// Schedule an callable function that is executed at the next update tick.
    /// Its safe to modify the TaskScheduler from within the callable.
    TaskScheduler& Async(std::function callable);
    /// Schedule an event with a fixed rate.
    /// Never call this from within a task context! Use TaskContext::Schedule instead!
    TaskScheduler& Schedule(duration_t time,
        task_handler_t task)
    {
        return this->ScheduleAt(_now, time, std::move(task));
    }
    /// Schedule an event with a fixed rate.
    /// Never call this from within a task context! Use TaskContext::Schedule instead!
    TaskScheduler& Schedule(duration_t time,
        group_t const group, task_handler_t task)
    {
        return this->ScheduleAt(_now, time, group, std::move(task));
    }
    /// Schedule an event with a randomized rate between min and max rate.
    /// Never call this from within a task context! Use TaskContext::Schedule instead!
    TaskScheduler& Schedule(std::chrono::milliseconds min,
        std::chrono::milliseconds max, task_handler_t task)
    {
        return this->Schedule(::randtime(min, max), std::move(task));
    }
    /// Schedule an event with a fixed rate.
    /// Never call this from within a task context! Use TaskContext::Schedule instead!
    TaskScheduler& Schedule(std::chrono::milliseconds min,
        std::chrono::milliseconds max, group_t const group,
        task_handler_t task)
    {
        return this->Schedule(::randtime(min, max), group, std::move(task));
    }
    /// Cancels all tasks.
    /// Never call this from within a task context! Use TaskContext::CancelAll instead!
    TaskScheduler& CancelAll();
    /// Cancel all tasks of a single group.
    /// Never call this from within a task context! Use TaskContext::CancelGroup instead!
    TaskScheduler& CancelGroup(group_t group);
    /// Cancels all groups in the given std::vector.
    /// Hint: Use std::initializer_list for this: "{1, 2, 3, 4}"
    TaskScheduler& CancelGroupsOf(std::vector const& groups);
    /// Delays all tasks with the given duration.
    TaskScheduler& DelayAll(duration_t duration);
    /// Delays all tasks with a random duration between min and max.
    TaskScheduler& DelayAll(std::chrono::milliseconds min,
        std::chrono::milliseconds max)
    {
        return this->DelayAll(::randtime(min, max));
    }
    /// Delays all tasks of a group with the given duration.
    TaskScheduler& DelayGroup(group_t const group, duration_t duration);
    /// Delays all tasks of a group with a random duration between min and max.
    TaskScheduler& DelayGroup(group_t const group,
        std::chrono::milliseconds min,
        std::chrono::milliseconds max)
    {
        return this->DelayGroup(group, ::randtime(min, max));
    }
    /// Reschedule all tasks with a given duration.
    TaskScheduler& RescheduleAll(duration_t duration);
    /// Reschedule all tasks with a random duration between min and max.
    TaskScheduler& RescheduleAll(std::chrono::milliseconds min, std::chrono::milliseconds max)
    {
        return this->RescheduleAll(::randtime(min, max));
    }
    /// Reschedule all tasks of a group with the given duration.
    TaskScheduler& RescheduleGroup(group_t const group, duration_t duration);
    /// Reschedule all tasks of a group with a random duration between min and max.
    TaskScheduler& RescheduleGroup(group_t const group,
        std::chrono::milliseconds min,
        std::chrono::milliseconds max)
    {
        return this->RescheduleGroup(group, ::randtime(min, max));
    }
private:
    /// Insert a new task to the enqueued tasks.
    TaskScheduler& InsertTask(TaskContainer task);
    TaskScheduler& ScheduleAt(timepoint_t end,
        duration_t time, task_handler_t task);
    /// Schedule an event with a fixed rate.
    /// Never call this from within a task context! Use TaskContext::schedule instead!
    TaskScheduler& ScheduleAt(timepoint_t end,
        duration_t time,
        group_t const group, task_handler_t task);
    /// Dispatch remaining tasks
    void Dispatch(success_t const& callback);
};
class TC_COMMON_API TaskContext
{
    friend class TaskScheduler;
    /// Associated task
    TaskScheduler::TaskContainer _task;
    /// Owner
    std::weak_ptr _owner;
    /// Marks the task as consumed
    std::shared_ptr _consumed;
    /// Dispatches an action safe on the TaskScheduler
    TaskContext& Dispatch(std::function const& apply);
public:
    // Empty constructor
    TaskContext()
        : _task(), _owner(), _consumed(std::make_shared(true)) { }
    // Construct from task and owner
    explicit TaskContext(TaskScheduler::TaskContainer&& task, std::weak_ptr&& owner)
        : _task(std::move(task)), _owner(std::move(owner)), _consumed(std::make_shared(false)) { }
    // Copy construct
    TaskContext(TaskContext const& right) = default;
    // Move construct
    TaskContext(TaskContext&& right) noexcept = default;
    // Copy assign
    TaskContext& operator=(TaskContext const& right) = default;
    // Move assign
    TaskContext& operator=(TaskContext&& right) noexcept = default;
    ~TaskContext() = default;
    /// Returns true if the owner was deallocated and this context has expired.
    bool IsExpired() const;
    /// Returns true if the event is in the given group
    bool IsInGroup(TaskScheduler::group_t const group) const;
    /// Sets the event in the given group
    TaskContext& SetGroup(TaskScheduler::group_t const group);
    /// Removes the group from the event
    TaskContext& ClearGroup();
    /// Returns the repeat counter which increases every time the task is repeated.
    TaskScheduler::repeated_t GetRepeatCounter() const;
    /// Repeats the event and sets a new duration.
    /// std::chrono::seconds(5) for example.
    /// This will consume the task context, its not possible to repeat the task again
    /// from the same task context!
    TaskContext& Repeat(TaskScheduler::duration_t duration);
    /// Repeats the event with the same duration.
    /// This will consume the task context, its not possible to repeat the task again
    /// from the same task context!
    TaskContext& Repeat()
    {
        return Repeat(_task->_duration);
    }
    /// Repeats the event and set a new duration that is randomized between min and max.
    /// std::chrono::seconds(5) for example.
    /// This will consume the task context, its not possible to repeat the task again
    /// from the same task context!
    TaskContext& Repeat(std::chrono::milliseconds min,
        std::chrono::milliseconds max)
    {
        return this->Repeat(::randtime(min, max));
    }
    /// Schedule a callable function that is executed at the next update tick from within the context.
    /// Its safe to modify the TaskScheduler from within the callable.
    TaskContext& Async(std::function const& callable);
    /// Schedule an event with a fixed rate from within the context.
    /// Its possible that the new event is executed immediately!
    /// Use TaskScheduler::Async to create a task
    /// which will be called at the next update tick.
    TaskContext& Schedule(TaskScheduler::duration_t time,
        TaskScheduler::task_handler_t task);
    /// Schedule an event with a fixed rate from within the context.
    /// Its possible that the new event is executed immediately!
    /// Use TaskScheduler::Async to create a task
    /// which will be called at the next update tick.
    TaskContext& Schedule(TaskScheduler::duration_t time,
        TaskScheduler::group_t const group, TaskScheduler::task_handler_t task);
    /// Schedule an event with a randomized rate between min and max rate from within the context.
    /// Its possible that the new event is executed immediately!
    /// Use TaskScheduler::Async to create a task
    /// which will be called at the next update tick.
    TaskContext& Schedule(std::chrono::milliseconds min,
        std::chrono::milliseconds max, TaskScheduler::task_handler_t task)
    {
        return this->Schedule(::randtime(min, max), std::move(task));
    }
    /// Schedule an event with a randomized rate between min and max rate from within the context.
    /// Its possible that the new event is executed immediately!
    /// Use TaskScheduler::Async to create a task
    /// which will be called at the next update tick.
    TaskContext& Schedule(std::chrono::milliseconds min,
        std::chrono::milliseconds max, TaskScheduler::group_t const group,
        TaskScheduler::task_handler_t task)
    {
        return this->Schedule(::randtime(min, max), group, std::move(task));
    }
    /// Cancels all tasks from within the context.
    TaskContext& CancelAll();
    /// Cancel all tasks of a single group from within the context.
    TaskContext& CancelGroup(TaskScheduler::group_t const group);
    /// Cancels all groups in the given std::vector from within the context.
    /// Hint: Use std::initializer_list for this: "{1, 2, 3, 4}"
    TaskContext& CancelGroupsOf(std::vector const& groups);
    /// Delays all tasks with the given duration from within the context.
    TaskContext& DelayAll(TaskScheduler::duration_t duration);
    /// Delays all tasks with a random duration between min and max from within the context.
    TaskContext& DelayAll(std::chrono::milliseconds min,
        std::chrono::milliseconds max)
    {
        return this->DelayAll(::randtime(min, max));
    }
    /// Delays all tasks of a group with the given duration from within the context.
    TaskContext& DelayGroup(TaskScheduler::group_t const group, TaskScheduler::duration_t duration);
    /// Delays all tasks of a group with a random duration between min and max from within the context.
    TaskContext& DelayGroup(TaskScheduler::group_t const group,
        std::chrono::milliseconds min,
        std::chrono::milliseconds max)
    {
        return this->DelayGroup(group, ::randtime(min, max));
    }
    /// Reschedule all tasks with the given duration.
    TaskContext& RescheduleAll(TaskScheduler::duration_t duration);
    /// Reschedule all tasks with a random duration between min and max.
    TaskContext& RescheduleAll(std::chrono::milliseconds min,
        std::chrono::milliseconds max)
    {
        return this->RescheduleAll(::randtime(min, max));
    }
    /// Reschedule all tasks of a group with the given duration.
    TaskContext& RescheduleGroup(TaskScheduler::group_t const group, TaskScheduler::duration_t duration);
    /// Reschedule all tasks of a group with a random duration between min and max.
    TaskContext& RescheduleGroup(TaskScheduler::group_t const group,
        std::chrono::milliseconds min,
        std::chrono::milliseconds max)
    {
        return this->RescheduleGroup(group, ::randtime(min, max));
    }
private:
    /// Asserts if the task was consumed already.
    void AssertOnConsumed() const;
    /// Invokes the associated hook of the task.
    void Invoke();
};
#endif /// TRINITYCORE_TASK_SCHEDULER_H