package liste;

/**
 * Klasse ListeRekursiv
 * 
 * @author Rainer Helfrich
 * @version Oktober 2020
 */
public class ListeRekursiv<T> extends Liste<T>
{
    /**
     * Erzeugt eine neue Liste
     */
    public ListeRekursiv()
    {
        anfang = null;  
    }

    /**
     * Gibt die Anzahl der Elemente der Liste zurück
     */
    public int laenge()
    {
        return laenge(anfang);
    }

    private int laenge(Listenknoten k)
    {
        if (k == null) {
            return 0;
        } 
        return 1 + laenge(k.nachfolger);
    }

    /**
     * Gibt den n-ten Wert (0-basierte Zählweise) der Liste zurück.
     * @param n Der Index des gewünschten Elements
     * @return Den n-ten Wert
     */
    public T getNtenWert(int n)
    {
        return getNtenWert(anfang, n);
    }

    private T getNtenWert(Listenknoten<T> k, int n)
    {
        if (n == 0) {
            if (k == null) {
                return null; 
            } 
            else {
                return k.daten;
            }
        } 
        return getNtenWert(k.nachfolger, n-1);
    }

    /**
     * Hängt einen neuen Wert hinten an die Liste an.
     * @param val Der anzuhängende Wert
     */
    public void anhaengen(T val)
    {
        if (anfang == null)
        {
            anfang = new Listenknoten(val, null);
        }
        else
        {
            anhaengen(anfang, val);
        }
    }

    private void anhaengen(Listenknoten<T> k, T val)
    {
        if (k == null) 
        {
            return;
        } 
        if (k.nachfolger == null) 
        {
            k.nachfolger = new Listenknoten(val, null);
        } 
        else
        {
            anhaengen(k.nachfolger, val);
        }
    }

    /**
     * Fügt einen neuen Wert an einer gewünschten Stelle in der Liste ein.
     * @param index Die Stelle, an der der neue Wert stehen soll (0 <= index <= laenge())
     * @param val Der einzufügende Wert
     */
    public void einfuegenBei(int index, T val)
    {
        if (index == 0) 
        {
            anfang = new Listenknoten(val, anfang);
        } 
        else
        {
            einfuegenBei(anfang, index, val);
        }
    }

    private void einfuegenBei(Listenknoten<T> k, int index, T val)
    {
        if (index == 1) 
        {
            k.nachfolger = new Listenknoten(val, k.nachfolger);
        } 
        else
        {
            einfuegenBei(k.nachfolger, index-1, val);
        }
    }

    /**
     * Gibt zurück, ob ein Wert sich in der Liste befindet
     * @param val Der zu suchende Wert
     * @return true, wenn der Wert enthalten ist; false sonst
     */
    public boolean enthaelt(T val)
    {
        return enthaelt(anfang, val);
    }

    private boolean enthaelt(Listenknoten<T> k, T val)
    {
        if (k == null) {
            return false;
        } 
        if (k.daten.equals(val)) {
            return true;
        } 
        return enthaelt(k.nachfolger, val);
    }

    /**
     * Entfernt das Element, das am gegebenen Index steht, aus der Liste.
     * @param index Die Stelle, von der der Wert entfernt werden soll.
     */
    public void entferneBei(int index)
    {
        if (anfang == null) {
            return;
        } 
        if (index == 0) {
            anfang = anfang.nachfolger;
        } 
        else
        {
            entferneBei(anfang, index);
        }
    }

    private void entferneBei(Listenknoten k, int index)
    {
        if (k != null && k.nachfolger != null) {
            if (index == 1) 
            {
                k.nachfolger = k.nachfolger.nachfolger;
            } 
            else 
            {
                entferneBei(k.nachfolger, index-1);  
            } 
        }
    }
    
    /**
     * Gibt die Liste in String-Form aus.
     * @return Die String-Repräsentation der Liste
     */
    @Override
    public String toString()
    {
        String ergebnis = "[ ";
        if (anfang != null)
        {
            ergebnis += anfang.daten + toString(anfang.nachfolger);
        }
        ergebnis += " ]";
        return ergebnis;
    }
    
    private String toString(Listenknoten k)
    {
        if (k == null)
        {
            return "";
        }
        return ", " + k.daten + toString(k.nachfolger);
    }
}