public class DoublyLinkedList {

        private Node head;
        private Node tail;
        private int size;

        public DoublyLinkedList() {
                head = new Node(null);
                tail = new Node(null);
                head.setPrev(null);
                head.setNext(tail);
                tail.setPrev(head);
                tail.setNext(null);
                size = 0;
        }

        private class Node {

                private Object item;
                private Node prev;
                private Node next;

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

                Node(Object item, Node prev, Node next) {
                        this.item = item;
                        setPrev(prev);
                        setNext(next);
                }

                void setPrev(Node prev) {
                        this.prev = prev;
                }
                void setNext(Node next) {
                        this.next = next;
                }
                Node getPrev() {
                        return prev;
                }
                Node getNext() {
                        return next;
                }
                Object getItem() {
                        return item;
                }
        }

        private Node get(int index) {
                Node current = head.getNext();
                for (int i = 0; i < index; i++) {
                        current = current.getNext();
                }
                return current;
        }

        public Object remove(int index) throws IndexOutOfBoundsException {
                if(index<0 || index >= size)
                        throw new IndexOutOfBoundsException ("List index out of bounds on remove");
                Node result = get(index);
                result.getNext().setPrev(result.getPrev());
                result.getPrev().setNext(result.getNext());
                size--;
                return result.getItem();
        }

        public void add(int index, Object item) throws IndexOutOfBoundsException {
                if (index<0 || index>size)
                        throw new IndexOutOfBoundsException ("List index out of bounds on add");
                Node current = get(index);
                Node temp = new Node(item);
                temp.setPrev(current);
                temp.setNext(current.getNext());
                current.getNext().setPrev(temp);
                current.setNext(temp);
                size++;
        }

        public void addHead(Object item) {
                Node current = head;
                Node temp = new Node(item);
                temp.setPrev(current);
                temp.setNext(current.getNext());
                current.getNext().setPrev(temp);
                current.setNext(temp);
                size++;
        }

        public void addTail(Object item) {
                Node current = tail.getPrev();
                Node temp = new Node(item);
                temp.setPrev(current);
                temp.setNext(current.getNext());
                current.getNext().setPrev(temp);
                current.setNext(temp);
                size++;
        }


        public int size() {
                return size;
        }

        public boolean isEmpty() {
                return size == 0;
        }

        public String toString() {
                StringBuffer result = new StringBuffer();
                result.append("(head) - ");
                for (Node current = head.getNext(); current != tail; current=current.getNext())
                        result.append(current.getItem() + " - ");
                result.append("(tail)");
                return result.toString();
        }


        public static void main(String argv[]) {
                DoublyLinkedList list = new DoublyLinkedList();
                System.out.println(list);
                list.addHead(new Integer(1));
                list.addHead(new Integer(2));
                list.addTail(new Integer(9));
                list.addHead(new Integer(3));
                list.addTail(new Integer(11));
                list.add(2, new Integer(0));
                System.out.println(list);
                list.remove(list.size() - 1);
                System.out.println(list);
                list.remove(0);
                System.out.println(list);
        }


}