import java.util.AbstractQueue;
import java.util.Iterator;
import java.util.NoSuchElementException;

public class ArrayQueue<E> extends AbstractQueue<E> {

    private static final int INITIAL_CAPACITY = 10; // Taille initiale du tableau
    private E[] elements; // Tableau contenant les éléments
    private int head;     // Index de la tête de la file
    private int tail;     // Index de la queue de la file
    private int size;     // Nombre d'éléments dans la file

    @SuppressWarnings("unchecked")
    public ArrayQueue() {
        elements = (E[]) new Object[INITIAL_CAPACITY];
        head = 0;
        tail = 0;
        size = 0;
    }

    @Override
    public boolean offer(E e) {
        if (e == null) {
            throw new NullPointerException("Les éléments null ne sont pas autorisés.");
        }
        if (size == elements.length) {
            redimensionner();
        }
        elements[tail] = e;
        tail = (tail + 1) % elements.length;
        size++;
        return true;
    }

    @Override
    public E poll() {
        if (size == 0) {
            return null;
        }
        E element = elements[head];
        elements[head] = null; // Libération de la référence pour éviter les fuites mémoire
        head = (head + 1) % elements.length;
        size--;
        return element;
    }

    @Override
    public E peek() {
        return (size == 0) ? null : elements[head];
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            private int index = head;
            private int remaining = size;

            @Override
            public boolean hasNext() {
                return remaining > 0;
            }

            @Override
            public E next() {
                if (!hasNext()) {
                    throw new NoSuchElementException();
                }
                E element = elements[index];
                index = (index + 1) % elements.length;
                remaining--;
                return element;
            }
        };
    }

    // Méthode privée pour redimensionner le tableau lorsqu'il est plein
    @SuppressWarnings("unchecked")
    private void redimensionner() {
        int newCapacity = elements.length * 2;
        E[] newElements = (E[]) new Object[newCapacity];
        for (int i = 0; i < size; i++) {
            newElements[i] = elements[(head + i) % elements.length];
        }
        elements = newElements;
        head = 0;
        tail = size;
    }
}
