package enumeration;
/**
 * Kyle Wayne Kelly
 * A circular linked list.
 */
public class LinkedList implements List {

    public LinkedList() {
    }

    /**
     * Add a node after the current Node.
     */
    private void add(Node node) {
        if(currentNode!=null) {
            if(currentNode.previousNode()==null) {
                currentNode.setPreviousNode(node);
                node.setNextNode(currentNode);
            } else {
                Node next = currentNode.nextNode();
                next.setPreviousNode(node);
                node.setNextNode(next);
            }
            currentNode.setNextNode(node);
            node.setPreviousNode(currentNode);
        } else {
            currentNode = node;
        }
        length = length + 1;
    }

    /**
     * Sets the current node to the next node.
     */
    private void nextNode() {
        if(currentNode!=null&&currentNode.nextNode()!=null) {
            currentNode = currentNode.nextNode();
        }
    }

    /**
     * Remove an object from the list along with the associated 
     * Node.
     */
    private void removeObjectAndNode(Object object) {
        Object originalObject = currentNodeValue();
        if(currentNode!=null) {
            nextNode();
            while(!currentNodeValue().equals(originalObject) &&
                  !currentNodeValue().equals(object)) {
                nextNode();
            }
            if(currentNodeValue().equals(object)) {
                if(currentNode.nextNode()!=null) {
                    currentNode.nextNode().setPreviousNode
                        (currentNode.previousNode());
                    currentNode.previousNode().setNextNode
                        (currentNode.nextNode());
                    if(currentNode.previousNode()!=currentNode) {
                        currentNode = currentNode.previousNode();
                    }
                } else {
                    currentNode = null;
                }
                length = length - 1;
            }
        }
    }
                    

    /**
     * Returns the current Nodes value.  If the list contains no nodes,
     * then this returns null.
     */
    private Object currentNodeValue() {
        if(currentNode!=null) {
            return currentNode.getNodeElement();
        } else {
            return null;
        }
    }
    
    /**
     * Cycles to the previous node.
     */
    private void previousNode() {
        if(currentNode!=null) {
            currentNode = currentNode.previousNode();
        }
    }

    /**
     * Removes all Nodes.
     */
    private void clear() {
        length=0;
        currentNode = null;
    }

    /**
     * Returns the length of this list.
     */
    private int length() {
        return length;
    }

    /**
     * Returns whether the value of this Node is equal 
     * (by the current objects equals() method)
     * to the given Object.
     */
    public boolean equals(Object object) {
        return currentNodeValue().equals(object);
    }

    /**
     * Add an Object after the current Object.
     */
    public void add(Object object) {
        LinkedList.Node node = new LinkedList.Node(object);
        add(node);
    }

    /**
     * Move forward through the list.
     */
    public void next() {
        nextNode();
    }

    /**
     * Move backward through the list.
     */
    public void previous() {
        previousNode();
    }

    /**
     * Get the current object.
     */
    public Object current() {
        return currentNodeValue();
    }

    /**
     * Remove the given object.
     */
    public void remove(Object object) {
        removeObjectAndNode(object);
    }

    private int length;
    private LinkedList.Node currentNode;

    /**
     * Kyle Wayne Kelly
     * Used to hold objects in a LinkedList.
     */
    public class Node {
        
        /**
         * A Node with the value given.
         */
        public Node(Object value) {
            this.object = value;
        }

        /**
         * Returns the next Node.  Returns null if no Node is
         * next.
         */
        public Node nextNode() {
            return next;
        }
        
        /**
         * Returns the previous Node.  Returns null if this is the first
         * Node.
         */
        public Node previousNode() {
            return previous;
        }
        
        /**
         * Sets the next Node.
         */
        public void setNextNode(Node n) {
            next = n;
        }
        /**
         * Sets the previous Node.
         */
        public void setPreviousNode(Node n) {
            previous = n;
        }

        /**
         * Put an Object in this Node.
         */
        public void setNodeElement(Object object) {
            this.object = object;
        }

        /**
         * Gets the Object located at this node.
         */
        public Object getNodeElement() {
            return object;
        }
        
        private Object object;
        private Node next, previous;
    }   
}







