package basictype;
import java.util.Iterator;

public class LinkedQueue<T> extends Queue<T> {
  private class Link {
    T element;
    Link next;
    
    Link(T element, Link next) {
      this.element = element;
      this.next = next;
    }
  }
  
  private Link first;
  private Link last;
  private int size;
  
  public LinkedQueue() {
    this.size = 0;
    this.first = null;
    this.last = null;
  }
  
  @Override
  public void enqueue(T item) {
    Link previousLast = this.last;
    this.last = new Link(item, null);
    if (previousLast == null) {
      this.first = this.last;
    } else {
      previousLast.next = this.last;
    }
    this.size++;
  }
  
  @Override
  public T dequeue() {
    T result = null;
    if (this.first != null) {
      result = this.first.element;
      this.first = this.first.next;
      if (this.first == null) {
        this.last = null;
      }
      this.size--;
      return result;
    } else {
      throw new RuntimeException("Error: dequeue on empty queue.");
    }
  }
  
  @Override
  public int size() {
    return this.size;
  }
  
  @Override
  public Iterator<T> iterator() {
    return new LinkedQueueIterator();
  }

  private class LinkedQueueIterator implements Iterator <T> {
    private Link currentLink = LinkedQueue.this.first;
    
    @Override
    public boolean hasNext() {
      return this.currentLink != null ;
    }
    
    @Override
    public T next() {
      T result = this.currentLink.element;
      this.currentLink = this.currentLink.next;
      return result;
    }

    @Override
    public void remove() {
      // Don't do anything, removing items from a queue is for dequeue() only!
    }
  }
  
  
  private static final String[] defaultArgs = {
    "un", "deux", "trois", "quatre", "cinq",
    "six", "sept", "huit", "neuf", "dix",
    "onze", "douze", "treize", "quatorze", "quinze"
  };

  public static void main(String[] args) {
    String[] items = args;
    if (items.length == 0) { // No arguments -> use default sample of items
      items = defaultArgs;
    }
    Queue<String> q = new LinkedQueue<String>();
    for(String arg: items) {
      q.enqueue(arg);
    }
    
    System.out.println("# Iterate");
    System.out.println(q);
    
    System.out.println("# Dequeue");
    while (q.size() > 0) {
      System.out.println(q.dequeue());
    }
  }

}
