Source: core/Queue.js

import { Each } from "@fizzwiz/fluent";
import { Collection } from "./Collection.js";

/**
 * The {@link Queue} class extends {@link Collection} and acts as a<br>
 * template for defining essential methods that every sorted collection should implement:<br><br>
 *
 * <b>Abstract Methods</b>:<br>
 * - [peek()](#peek)<br>
 * - [poll()](#poll)<br>
 * - [reverse()](#reverse)<br><br>
 *
 * <b>Concrete Methods</b>:<br>
 * Based on the abstract methods, these are inherited by all subclasses<br>
 * of sorted collections:<br>
 * - [select()](#select)<br>
 */
export class Queue extends Collection {
	
	constructor() {
		super();
	}

	/**
	 * Retrieves the first item of `this` {@link Queue}.
	 * 
	 * @param {boolean} [first=true] If false, retrieves the last item instead.
	 * @returns {any} The retrieved item.
	 */
	peek(first = true) {
		throw new Error('Abstract method: peek() must be implemented by subclass.');
	}

	/**
	 * Extracts (removes and returns) the first item of `this` {@link Queue}.
	 * 
	 * @param {boolean} [first=true] If false, extracts the last item instead.
	 * @returns {any} The extracted item.
	 */
	poll(first = true) {
		const got = this.peek(first);
		this.remove(got);
		return got;
	}

	/**
	 * Provides an iterable reversed view of `this` {@link Queue}.
	 * 
	 * @returns {Each<any>} An iterable over the queue's elements in reverse order.
	 */
	reverse() {
		throw new Error('Abstract method: reverse() must be implemented by subclass.');
	}
	
	/**
	 * Selects and keeps the first `n` items of the queue, removing all other items.
	 * 
	 * @param {number} n - Number of items to keep in the queue
	 * @param {boolean} [first=true] - If true, selects items from the start; if false, from the end.
	 * @returns {Array<any>} An array containing the discarded items removed from the queue.
	 * 
	 */
	select(n, first = true) {
		if (n < 0) n = 0;
		const m = this.n() - n;
		const got = new Array(m < 0 ? 0 : m).fill(undefined);

		let i = first ? got.length - 1 : 0;
		const inc = first ? -1 : 1;
		
		while (this.n() > n) {
			const next = this.poll(!first);
			got[i] = next;
			i += inc;
		}
		
		return got;
	}

}