
/**
 * Eine Queue basierend auf einer verketteten Liste
 * 
 * @author Rainer Helfrich
 * @version Oktober 2020
 */
public class LinkedQueue<T> extends Queue<T>
{
    /**
     * Der vorderste Wert der Queue
     */
    private Listenknoten<T> first;
    
    /**
     * Der hinterste Wert der Queue
     */
    private Listenknoten<T> last;
    
    /**
     * Erzeugt eine neue, leere Queue
     */
    public LinkedQueue()
    {
        first = null;
        last = null;
    }
    
    /**
     * Gibt das vorderste Element der Queue zurück (falls sie nicht leer ist)
     * @return Das vorderste Element
     */
    public T front()
    {
        if (first != null)
        {
            return first.daten;
        }
        return null;
    }
    
    /**
     * Entfernt das vorderste Element aus der Queue (falls sie nicht leer ist) und gibt es zurück
     * @return Das bisherige vorderste Element
     */
    public T dequeue()
    {
        T w = null;
        if (first != null)
        {
            w = first.daten;
            first = first.nachfolger;
            if (first == null)
            {
                last = null;
            }
        }
        return w;
    }
    
    /**
     * Fügt ein neues Element hinten in der Schlange ein
     * @param x Das neue Element
     */
    public void enqueue(T x)
    {
        if (first == null)
        {
            first = new Listenknoten(x, null);
            last = first;
        }
        else
        {
            last.nachfolger = new Listenknoten(x, null);
            last = last.nachfolger;
        }
    }
    
    /**
     * Gibt zurück, ob die Queue leer ist
     * @return true, wenn die Queue leer ist; false sonst
     */
    public boolean isEmpty()
    {
        return first == null && last == null;
    }
    
    /**
     * Ein Listenknoten, wie er bei den verketteten Listen verwendet wurde.
     * Diesmal allerdings als innere Klasse
     */
    private class Listenknoten<T>
    {
        /**
         * Der Datenwert des Listenknotens
         */ 
        public T daten;
        /**
         * Der Nachfolger des Listenknotens
         */
        public Listenknoten<T> nachfolger;

        /**
         * Erzeugt einen neuen Listenknoten
         * 
         * @param daten Der Datenwert des Knotens
         * @param nachfolger Der Nachfolger des Knotens
         */ 
        public Listenknoten(T daten, Listenknoten<T> nachfolger)
        {
            this.daten = daten;
            this.nachfolger = nachfolger;
        }
    }
    
    /**
     * Gibt die Queue in String-Form aus.
     * @return Die String-Repräsentation der Queue
     */
    @Override
    public String toString()
    {
        StringBuilder b = new StringBuilder();
        Listenknoten k = first;
        while(k != null)
        {
            if (b.length() > 0)
            {
                b.append(", ");
            }
            b.append(k.daten);
            k = k.nachfolger;
        }
        return "< " + b.toString() + " <";
    }
}
    