package de.duehl.vocabulary.japanese.ui.listcommander.list;

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

import de.duehl.twosidecommander.ui.list.ListDisplayer;
import de.duehl.twosidecommander.ui.list.data.ListElementMoveReactor;
import de.duehl.twosidecommander.ui.list.element.ListElementDisplayer;
import de.duehl.vocabulary.japanese.data.OwnList;
import de.duehl.vocabulary.japanese.data.Vocable;
import de.duehl.vocabulary.japanese.ui.listcommander.OwnListCommander;
import de.duehl.vocabulary.japanese.ui.listcommander.list.element.OwnListElementDisplayer;

/**
 * Diese Klasse stellt die abstrakte Basis für die grafische Oberfläche einer Liste des
 * Listen-Commanders dar, mit dem sich generisch zwischen zwei eigene Listen Vokabeln kopieren,
 * verschieben oder löschen lassen.
 *
 * @version 1.01     2025-08-15
 * @author Christian Dühl
 */

public class OwnListDisplayer extends ListDisplayer {

    /** Die dargestellte eigene Liste. */
    private OwnList ownList;

    /** Der List-Commander. */
    private final OwnListCommander commander;

    /**
     * Konstruktor.
     *
     * @param commander
     *            Der List-Commander.
     */
    public OwnListDisplayer(OwnListCommander commander) {
        this.commander = commander;
    }

    /** Setter für die dargestellte eigene Liste. */
    public void setOwnList(OwnList ownList) {
        this.ownList = ownList;
    }

    /**
     * Wird aufgerufen, wenn der Benutzer im Selector eine neue eigene Liste ausgewählt hat. Man
     * erzeugt aus dem Inhalt der eigenen Liste, also ihren Vokabeln, ListElementDisplayer-Objekte
     * und gibt diese zurück. Im Anschluss werden sie angezeigt.
     */
    @Override
    public List<ListElementDisplayer> createElementDisplyersToShow() {
        List<ListElementDisplayer> vocableDisplayers = new ArrayList<>();

        for (Vocable vocable : ownList.getVocables()) {
            OwnListElementDisplayer vocableDisplayer = new OwnListElementDisplayer(
                    (ListElementMoveReactor) this, commander, vocable);
            vocableDisplayers.add(vocableDisplayer);
        }

        return vocableDisplayers;
    }

    /** Prüft, ob das übergebene Element als neues Listenelement hinzugefügt werden kann. */
    @Override
    public boolean canAppend(ListElementDisplayer listElementDisplayer) {
        OwnListElementDisplayer newOwnListElementDisplayer =
                OwnListElementDisplayer.castListElementDisplayer(listElementDisplayer);
        Vocable newVocable = newOwnListElementDisplayer.getVocable();
        return !ownList.getVocables().contains(newVocable);
    }

    /** Fügt die übergebenen neuen Listenelemente am Ende hinzu. */
    @Override
    protected void appendImplmentation(List<ListElementDisplayer> newListElementDisplayers) {
        for (ListElementDisplayer newListElementDisplayer : newListElementDisplayers) {
            appendImplmentation(newListElementDisplayer);
        }
        commander.storeOwnLists();
    }

    private void appendImplmentation(ListElementDisplayer newListElementDisplayer) {
        OwnListElementDisplayer newOwnListElementDisplayer =
                OwnListElementDisplayer.castListElementDisplayer(newListElementDisplayer);
        Vocable newVocable = newOwnListElementDisplayer.getVocable();

        List<Vocable> vocables = ownList.getVocables();
        if (vocables.contains(newVocable)) {
            throw new RuntimeException("Kann die Vokabel nicht anhängen!\n" + "\t" + "Vokabel: "
                    + newVocable + "\n" + "\t" + "Liste  : " + ownList.getName() + "\n");
            /* Das wird vorher zwar mit der Methode canAppend() geprüft, aber sicher ist sicher! */
        }
        else {
            vocables.add(newVocable);
        }
    }

    /** Löscht die übergebenen Listenelemente aus der Liste. */
    @Override
    protected void removeImplmentation(List<ListElementDisplayer>  listElementDisplayersToDelete) {
        for (ListElementDisplayer listElementDisplayerToDelete : listElementDisplayersToDelete) {
            removeImplmentation(listElementDisplayerToDelete);
        }
        commander.storeOwnLists();
    }

    private void removeImplmentation(ListElementDisplayer listElementDisplayerToDelete) {
        OwnListElementDisplayer ownListElementDisplayerToDelete =
                OwnListElementDisplayer.castListElementDisplayer(listElementDisplayerToDelete);
        Vocable vocableToDelete = ownListElementDisplayerToDelete.getVocable();

        List<Vocable> vocables = ownList.getVocables();
        vocables.remove(vocableToDelete);
    }

    /** Erzeugt aus einem ListElementDisplayer einen OwnListDisplayer. */
    public final static OwnListDisplayer castListDisplayer(ListDisplayer listDisplayer) {
        return (OwnListDisplayer) listDisplayer;
    }

    /** Gibt eine Beschreibung der Liste zur Anzeige in Dialogen zurück. */
    @Override
    public String getListDescription() {
        return ownList.getName();
    }

    /** Der Getter für die dargestellte eigene Liste. */
    public OwnList getOwnList() {
        return ownList;
    }

    /** Verschiebt das Element in der Liste an die erste Stelle. */
    @Override
    protected void moveListElementToFirstInImplementation(ListElementDisplayer displayer) {
        OwnListElementDisplayer ownListElementDisplayer =
                OwnListElementDisplayer.castListElementDisplayer(displayer);
        Vocable vocable = ownListElementDisplayer.getVocable();

        List<Vocable> vocables = ownList.getVocables();
        int index = vocables.indexOf(vocable);
        vocables.remove(index);
        vocables.add(0, vocable);
        commander.storeOwnLists();
    }

    @Override
    protected void moveListElementUpInImplementation(ListElementDisplayer displayer) {
        OwnListElementDisplayer ownListElementDisplayer =
                OwnListElementDisplayer.castListElementDisplayer(displayer);
        Vocable vocable = ownListElementDisplayer.getVocable();

        List<Vocable> vocables = ownList.getVocables();
        int index = vocables.indexOf(vocable);
        vocables.remove(index);
        vocables.add(index - 1, vocable);
        commander.storeOwnLists();
    }

    @Override
    protected void moveListElementDownInImplementation(ListElementDisplayer displayer) {
        OwnListElementDisplayer ownListElementDisplayer =
                OwnListElementDisplayer.castListElementDisplayer(displayer);
        Vocable vocable = ownListElementDisplayer.getVocable();

        List<Vocable> vocables = ownList.getVocables();
        int index = vocables.indexOf(vocable);
        vocables.remove(index);
        vocables.add(index + 1, vocable);
        commander.storeOwnLists();
    }

    @Override
    protected void moveListElementToLastInImplementation(ListElementDisplayer displayer) {
        OwnListElementDisplayer ownListElementDisplayer =
                OwnListElementDisplayer.castListElementDisplayer(displayer);
        Vocable vocable = ownListElementDisplayer.getVocable();

        List<Vocable> vocables = ownList.getVocables();
        int index = vocables.indexOf(vocable);
        vocables.remove(index);
        vocables.add(vocable);
        commander.storeOwnLists();
    }

}
