/**
 * This queue runs tasks in the order they are added to the queue
 *
 * @implements {Queue<Task>}
 * @property {Task[]} queue used to be stored tasks pending for executing
 */
export class SynchronizeTaskQueue {
  /**
   * Define the task queue max length, the default is no length limit.
   *
   * @param {number} [maxTaskSize] the
   */
  constructor(maxTaskSize) {
    this.queue = [];
    this.maxSize = maxTaskSize;
  }
  /**
   * If immediatelyRun is true, run the task immediately while the queue is empty. Otherwise, add it to the queue.
   * If immediatelyRun is false, add it to the queue.
   *
   * @param {Task} item - Task - The task to be added to the queue.
   */
  async enqueue(item, immediatelyRun = true) {
    if (this.maxSize && this.queue.length === this.maxSize) {
      this.queue.shift();
    }
    const shouldRun = immediatelyRun && this.queue.length === 0;
    this.queue.push(item);
    if (shouldRun) {
      await this.runTask();
    }
  }
  /**
   * Run the first task in the queue, then remove it from the queue and run the next task if there is one
   */
  async runTask() {
    const firstTask = this.queue[0];
    if (firstTask) {
      await firstTask.run();
      this.queue.shift();
      if (this.queue.length > 0) {
        await this.runTask();
      }
    }
  }
}
