package de.duehl.basics.collections;

/*
 * Copyright 2020 Christian Dühl. All rights reserved.
 *
 * This program is free software. You can redistribute it and/or
 * modify it under the same terms as perl:
 *
 * general:  http://dev.perl.org/licenses/
 * GPL:      http://dev.perl.org/licenses/gpl1.html
 * artistic: http://dev.perl.org/licenses/artistic.html
 */

import java.util.ArrayList;
import java.util.List;

import de.duehl.basics.exceptions.EmptyQueueException;

/**
 * Eine Klasse für eine Warteschlange von Dingen.
 *
 * Was sich zuerst anstellt, wird auch zuerst verarbeitet.
 *
 * Implementiert wird hier so, dass der Kopf der Warteschlange, also das Objekt das als nächstes
 * verarbeitet wird,  bei Index 0 liegt.
 *
 * @version 1.01     2020-01-09
 * @author Christian Dühl
 */

public class Queue<E> {

    /** Liste mit den angestellten Dingen. */
    private final List<E> queueElements;

    /** Konstruktor, erzeugt eine leere Warteschlange. */
    public Queue() {
        queueElements = new ArrayList<>();
    }

    /** Prüft, ob die Warteschlange leer ist. */
    public boolean isEmpty() {
        return queueElements.isEmpty();
    }

    /** Prüft, ob die Warteschlange Elemente enthält, also nicht leer ist. */
    public boolean hasElements() {
        return !isEmpty();
    }

    /** Leert die Warteschlange. */
    public void clear() {
        queueElements.clear();
    }

    /**
     * Stellt etwas hinten an die Warteschlange an.
     *
     * @param element
     *            Anzustellendes Ding.
     */
    public void queue(E element) {
        queueElements.add(element);
    }

    /**
     * Nimmt das vorderste Ding aus der Warteschlange und gibt es zurück.
     *
     * @return Vorderstes Ding aus der Warteschlange.
     * @throws EmptyQueueException
     *             Falls die Warteschlange vorher bereits leer war.
     */
    public E take() {
        if (isEmpty()) {
            throw new EmptyQueueException("Die Warteschlange ist leer!");
        }
        else {
            return queueElements.remove(0);
        }
    }

    /** Gibt die Anzahl der Elemente zurück, die in der Warteschlange anstehen. */
    public int size() {
        return queueElements.size();
    }

    /** Gibt eine flache Kopie der Liste der Elemente auf dem Warteschlange zurück. */
    public List<E> getElementsAsList() {
        List<E> list = new ArrayList<>();
        list.addAll(queueElements);
        return list;
    }

    /**
     * Entnimmt alle Elemente der übergebenen Warteschlange und fügt sie der eigenen Warteschlange
     * hinzu.
     */
    public void takeAllElementsFrom(Queue<E> that) {
        while (that.hasElements()) {
            queue(that.take());
        }
    }

    /** Erzeugt eine Stringdarstellung der Warteschlange zu Debugzwecken. */
    @Override
    public String toString() {
        return "Queue [queueElements=" + queueElements + "]";
    }

}
