/**
 * Task Queue for WaveletTree Construction
 * 
 * Uses parallel typed arrays to avoid object creation overhead
 * Stores: sequence, alphabetSize, alphabetMin, parentNodeIndex, isLeft
 */

export class TaskQueue {
  constructor(initialCapacity = 1024) {
    this.capacity = initialCapacity;
    this.length = 0;
    this.head = 0;
    this.tail = 0;
    
    // Parallel arrays for task data
    // Sequences are stored separately (arrays themselves)
    this.sequences = new Array(this.capacity);
    this.alphabetSizes = new Uint32Array(this.capacity);
    this.alphabetMins = new Uint32Array(this.capacity);
    this.isLefts = new Uint8Array(this.capacity);
    
    // Parent nodes array (for references) - stored at same index as queue position
    this.parentNodes = new Array(this.capacity);
  }

  /**
   * Enqueue a task
   * @param {Array} sequence - Sequence array
   * @param {number} alphabetSize - Alphabet size
   * @param {number} alphabetMin - Minimum alphabet value
   * @param {Object} parentNode - Parent node reference
   * @param {boolean} isLeft - Whether this is left child
   */
  enqueue(sequence, alphabetSize, alphabetMin, parentNode, isLeft) {
    // Grow if needed
    if (this.length >= this.capacity) {
      this._grow();
    }
    
    // Store task data in parallel arrays
    // Store parentNode directly in a separate array, indexed by queue position
    // This avoids the complexity of managing indices
    this.sequences[this.tail] = sequence;
    this.alphabetSizes[this.tail] = alphabetSize;
    this.alphabetMins[this.tail] = alphabetMin;
    this.isLefts[this.tail] = isLeft ? 1 : 0;
    this.parentNodes[this.tail] = parentNode; // Store directly at tail position
    
    this.tail = (this.tail + 1) % this.capacity;
    this.length++;
  }

  /**
   * Grow arrays when capacity exceeded
   */
  _grow() {
    const newCapacity = this.capacity * 2;
    
    // Grow typed arrays
    const newAlphabetSizes = new Uint32Array(newCapacity);
    const newAlphabetMins = new Uint32Array(newCapacity);
    const newIsLefts = new Uint8Array(newCapacity);
    
    // Grow regular arrays
    const newSequences = new Array(newCapacity);
    const newParentNodes = new Array(newCapacity);
    
    // Copy existing data
    let count = 0;
    let idx = this.head;
    while (count < this.length) {
      newAlphabetSizes[count] = this.alphabetSizes[idx];
      newAlphabetMins[count] = this.alphabetMins[idx];
      newIsLefts[count] = this.isLefts[idx];
      newSequences[count] = this.sequences[idx];
      newParentNodes[count] = this.parentNodes[idx];
      idx = (idx + 1) % this.capacity;
      count++;
    }
    
    // Update arrays
    this.sequences = newSequences;
    this.alphabetSizes = newAlphabetSizes;
    this.alphabetMins = newAlphabetMins;
    this.isLefts = newIsLefts;
    this.parentNodes = newParentNodes;
    this.capacity = newCapacity;
    this.head = 0;
    this.tail = this.length;
  }

  /**
   * Dequeue a task
   * @returns {Object|null} Task object or null if empty
   */
  dequeue() {
    if (this.length === 0) {
      return null;
    }
    
    const sequence = this.sequences[this.head];
    const alphabetSize = this.alphabetSizes[this.head];
    const alphabetMin = this.alphabetMins[this.head];
    const isLeft = this.isLefts[this.head] === 1;
    const parentNode = this.parentNodes[this.head];
    
    // Clear reference
    this.sequences[this.head] = null;
    this.parentNodes[this.head] = null;
    
    this.head = (this.head + 1) % this.capacity;
    this.length--;
    
    return {
      sequence,
      alphabetSize,
      alphabetMin,
      parentNode,
      isLeft
    };
  }

  /**
   * Check if queue is empty
   */
  isEmpty() {
    return this.length === 0;
  }

  /**
   * Get current queue length
   */
  size() {
    return this.length;
  }
}

