package lab13;

public class List {
 
    private Node frontNode;
    private Node rearNode;
    private int itemCount;
    
    public List () {
        frontNode = rearNode = null;
        itemCount = 0;
    }

    public void add (int index, Object value)
            throws IndexOutOfBoundsException {

        if (index < 0 || index > itemCount) {
            throw new IndexOutOfBoundsException("Index out of range");
        }
        
        if (itemCount == 0) {  // Adding to empty list
            frontNode = rearNode = new Node (value, null);
        }
        else if (index == 0) { // Adding to front of nonempty list
            frontNode = new Node (value, frontNode);
        }
        else if (index == itemCount) {  // Adding to rear of nonempty list
            rearNode = (rearNode.next = new Node (value, null));
        }
        else {  // Inserting new node within existing list
            Node curNode = frontNode;
            Node preNode = null;
            for (int i = 0; i < index; i++) {
                preNode = curNode;
                curNode = curNode.next;
            }
            preNode.next = new Node (value, curNode);
        }
        itemCount++;
    }

    public Object set (int index, Object value)
            throws IndexOutOfBoundsException {
        if (index < 0 || index >= itemCount) {
            throw new IndexOutOfBoundsException("Index out of range");
        }
        Node curNode = frontNode;
        for (int i = 0; i < index; i++) {
            curNode = curNode.next;
        }
        Object oldValue = curNode.value;
        curNode.value = value;
        return oldValue;
    }
  
    public Object remove (int index) throws IndexOutOfBoundsException {
        if (index < 0 || index >= itemCount) {
            throw new IndexOutOfBoundsException("Index out of range");
        }

        Object removeValue = null;
        
        if (itemCount == 1) {  // Removing one and only value in list
            removeValue = frontNode.value;
            frontNode = rearNode = null;
        }
        else if (index == 0) { // Longer list, but removing from front
            removeValue = frontNode.value;
            frontNode = frontNode.next;
        }
        else {      // Need to count into list to find value at index
            Node curNode = frontNode;
            Node preNode = null;
            for (int i = 0; i < index; i++) {
                preNode = curNode;
                curNode = curNode.next;
            }
            removeValue = curNode.value;
            preNode.next = curNode.next;
            if (preNode.next == null) {   // What if removing last one?
                rearNode = preNode;
            }
        }
        itemCount--;
        return removeValue;
    }

    public Object get (int index) throws IndexOutOfBoundsException {
        if (index < 0 || index >= itemCount) {
            throw new IndexOutOfBoundsException("Index out of range");
        }
        Node curNode = frontNode;
        for (int i = 0; i < index; i++) {
            curNode = curNode.next;
        }
        return curNode.value;
    }

    public void add (Object value) {
        Node newNode = new Node (value, null);
        if (itemCount == 0) {
            frontNode = rearNode = newNode;
        }
        else {
            rearNode.next = newNode;
            rearNode = newNode;
        }
        itemCount++;
    }
  
    public boolean isEmpty () {
        return (itemCount == 0);
    }

    public int size () {
        return itemCount;
    }
  
    public void removeAll () {
        frontNode = rearNode = null;
        itemCount = 0;
    }
      
    private class Node {
        Object value;
        Node next;
        
        Node (Object value, Node next) {
            this.value = value;
            this.next = next;
        }
    }
}
