package queue;

/**
 * @author Doschennikov Nikita (me@fymio.us)
 */
public class LinkedQueue extends AbstractQueue {

    private Node head;
    private Node tail;

    private static class Node {

        Object value;
        Node next;
        Node prev;

        Node(Object value) {
            this.value = value;
        }
    }

    public LinkedQueue() {
        head = null;
        tail = null;
    }

    @Override
    public void enqueue(Object element) {
        assert element != null : "Element must not be null";
        Node node = new Node(element);
        if (tail == null) {
            head = tail = node;
        } else {
            node.prev = tail;
            tail.next = node;
            tail = node;
        }
        size++;
    }

    @Override
    public void push(Object element) {
        assert element != null : "Element must not be null";
        Node node = new Node(element);
        if (head == null) {
            head = tail = node;
        } else {
            node.next = head;
            head.prev = node;
            head = node;
        }
        size++;
    }

    @Override
    public Object element() {
        assert size > 0 : "Queue is empty";
        return head.value;
    }

    @Override
    public Object peek() {
        assert size > 0 : "Queue is empty";
        return tail.value;
    }

    @Override
    public Object dequeue() {
        assert size > 0 : "Queue is empty";
        Object result = head.value;
        head = head.next;
        if (head != null) {
            head.prev = null;
        } else {
            tail = null;
        }
        size--;
        return result;
    }

    @Override
    public Object remove() {
        assert size > 0 : "Queue is empty";
        Object result = tail.value;
        tail = tail.prev;
        if (tail != null) {
            tail.next = null;
        } else {
            head = null;
        }
        size--;
        return result;
    }

    @Override
    protected Object get(int i) {
        Node cur = head;
        for (int j = 0; j < i; j++) {
            cur = cur.next;
        }
        return cur.value;
    }

    @Override
    protected void clearImpl() {
        head = null;
        tail = null;
    }

    @Override
    protected AbstractQueue createEmpty() {
        return new LinkedQueue();
    }
}
