package edu.caltech.cs2.datastructures;

import edu.caltech.cs2.interfaces.IFixedSizeQueue;

import java.util.Iterator;

public class CircularArrayFixedSizeQueue<E> implements IFixedSizeQueue<E> {


    private int front;
    private int back;
    private E[] arr;

    public CircularArrayFixedSizeQueue(int capacity) {
        this.arr = (E[]) new Object[capacity];
        this.front = 0;
        this.back = 0;
    }

    @Override
    public boolean isFull() {
        return size() == arr.length;
    }

    @Override
    public int capacity() {
        return arr.length;
    }

    @Override
    public boolean enqueue(E e) {
        if(isFull()) {
            return false;
        }
        arr[back] = e;
        back++;
        return true;
    }

    @Override
    public E dequeue() {
        if(size() == 0) {
            return null;
        }
        E e = arr[front];
        arr[front] = null;
        front++;
        return e;
    }

    @Override
    public E peek() {
        return arr[front];
    }

    @Override
    public int size() {
        return back - front;
    }

    @Override
    public Iterator<E> iterator() {
        return new CircularIterator();
    }

    @Override
    public String toString() {
        if (size() == 0) {
            return "[]";
        }

        String result = "[";
        for (int i = 0; i < this.size(); i++) {
            result += this.arr[i] + ", ";
        }

        result = result.substring(0, result.length() - 2);
        return result + "]";

    }

    private class CircularIterator implements Iterator<E> {

        private int currentIndex;

        public CircularIterator() {
            this.currentIndex = 0;
        }

        public boolean hasNext() {
            return this.currentIndex < (CircularArrayFixedSizeQueue.this).size();
        }

        public E next() {
            E element;
            if(this.currentIndex == (CircularArrayFixedSizeQueue.this).size()) {
                element = CircularArrayFixedSizeQueue.this.arr[0];
                this.currentIndex = 0;
            }
            else {
                element = (E) CircularArrayFixedSizeQueue.this.arr[this.currentIndex];
                this.currentIndex++;
            }
            return element;
        }
    }
}
