public class CircularQueueArray<T> {
	
	private T[] queue;  
	private int maxSize; // Size of Circular Queue
	private int frontIndex, rearIndex;
	private int length = 0;
	  
	//constructor, Time O(1), Space O(1)
	@SuppressWarnings("unchecked")
	public CircularQueueArray(int size) {
		maxSize = size;
	    frontIndex = -1;
	    rearIndex = -1;
	    queue = (T[])new Object[maxSize];
	}

	//Add at the rear, Time O(1), Space O(1)
	public void enqueue(T value) {
	    if (isFull()) {
	    	System.out.println("Queue is full, cannot enqueue "+ value);
	    	return;
	    } 
	    if (frontIndex == -1) //empty
	    	frontIndex = 0;
	    rearIndex = (rearIndex + 1) % maxSize;
	    queue[rearIndex] = value;
	    length++;	    
	}

	//Remove from the front, Time O(1), Space O(1)
	public T dequeue() {
	    if (isEmpty()) {
	    	System.out.println("Queue is empty");
	    	return null;
	    } 
	    T  item = queue[frontIndex];
	    if (frontIndex == rearIndex) { //last one, reset
	    	frontIndex = -1;
	        rearIndex = -1;
	    }  else {
	        frontIndex = (frontIndex + 1) % maxSize;
	    }
	    length--;
	    return (item);
	}
	
	//Return front value, Time O(1), Space O(1)
	public T peek() {
	    if (isEmpty()) {
	    	System.out.println("Queue is empty");
	    	return null;
	    } 
	    return queue[frontIndex];
	}
	
	//Print all, Time O(n), Space O(1), n is number of items in queue
	public void print() {
		if (isEmpty()) {
	    	System.out.println("Queue is empty");
	    	return;
	    } 
	    int i;
	    for (i = frontIndex; i != rearIndex; i = (i+1) % maxSize)
	    	System.out.print(queue[i] + " ");
	    System.out.println(queue[i]);
	}
	  
	//return number of items in queue, Time O(1), Space O(1)
	public int size() {
		return length;
	}
	  
	// Check full, Time O(1), Space O(1)
	private boolean isFull() {
		return (rearIndex + 1) % maxSize == frontIndex;
	}

	//Check empty, Time O(1), Space O(1)
	private boolean isEmpty() {
	    return frontIndex == -1;
	}

    public static void main(String args[]) {
    	//Initialize, enqueue, size
    	CircularQueueArray<Integer> queue = new CircularQueueArray<>(5); 
	    queue.enqueue(10);
	    queue.enqueue(20);
	    queue.enqueue(30);
	    queue.enqueue(80);
	    queue.enqueue(54);
	    queue.enqueue(60);
		queue.print();
	    System.out.println("size: " + queue.size());  
	    System.out.println("peek: " + queue.peek());
	    //Dequeue 
        queue.dequeue();  
        queue.dequeue(); 

        queue.print();
	    System.out.println("size: " + queue.size()); 
	    System.out.println("peek: " + queue.peek());
      
        //Enqueue again
	    queue.enqueue(70);
		queue.print();
	    System.out.println("size: " + queue.size());
	    System.out.println("peek: " + queue.peek());   
    }
}
