package de.duehl.basics.io.textfile.dictionary;

/*
 * Copyright 2025 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.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;

import de.duehl.basics.collections.CollectionsHelper;
import de.duehl.basics.text.Text;

/**
 * Diese Klasse stellt ein Wörterbucheintrag eines Wörterbuches dar.
 *
 * Ein Wörterbuch besteht aus einer Liste von Wörterbucheinträgen, welche jeweils einen
 * Hauptwort (z.B. eine deutsche Vokabel) und eine Reihe von alternativen Worten (z.B.
 * englische Übersetzungen) enthalten. Die Alternativen können auch leer sein, der Hauptwort
 * muss vorhanden und nicht leer sein.
 *
 * @version 1.01     2025-07-10
 * @author Christian Dühl
 */

public class DictionaryEntry implements Iterable<String> {

    /** Die Wörter dieses Wörterbucheintrags (Hauptwort und Alternativen). */
    private final List<String> words;

    /**
     * Konstruktor.
     *
     * @param mainWord
     *            Das Hauptwort des Wörterbucheintrags.
     */
    public DictionaryEntry(String mainWord) {
        if (mainWord.isEmpty()) {
            throw new IllegalArgumentException("Die Hauptwort darf nicht leer sein.");
        }
        words = new ArrayList<>();
        words.add(mainWord);
    }

    /**
     *
     * @param words Die Wörter dieses Wörterbucheintrags (Hauptwort und Alternativen).
     */
    public DictionaryEntry(List<String> words) {
        if (words.isEmpty()) {
            throw new IllegalArgumentException("Die Liste darf nicht leer sein, sie muss "
                    + "mindestens ein Element, nämlich das Hauptwort enthalten!");
        }
        if (words.get(0).isEmpty()) {
            throw new IllegalArgumentException("Die Hauptwort darf nicht leer sein.");
        }
        this.words = CollectionsHelper.copyList(words);
    }

    /** Copy-Konstruktor. */
    public DictionaryEntry(DictionaryEntry that) {
        this.words = CollectionsHelper.copyList(that.words);
    }

    /** Fügt eine Alternative hinzu. */
    public void addAlternative(String alternative) {
        if (!words.contains(alternative)) {
            words.add(alternative);
        }
    }

    /** Fügt Alternativen hinzu. */
    public void addAlternatives(List<String> alternatives) {
        for (String alternative : alternatives) {
            addAlternative(alternative);
        }
    }

    @Override
    public Iterator<String> iterator() {
        return words.iterator();
    }

    /** Getter für das Hauptwort des Eintrags (ist stets nicht leer). */
    public String getMainWord() {
        return words.get(0);
    }

    /** Getter für die Alternativen (kann leer sein). */
    public List<String> getAlternatives() {
        return CollectionsHelper.sublist(words, 1);
    }

    /**
     * Gibt eine Liste mit dem Hauptwort und den Alternativen zurück.
     *
     * Nach Möglichkeit lieber getMainWord() und getAlternatives() nutzen.
     *
     * Zum Aufbau eines Hashes etc. kann es aber sinnvoll sein!
     */
    public List<String> getAsFlatList() {
        return CollectionsHelper.copyList(words);
    }

    /** Prüft, ob der übergebene Begriff als Hauptwort oder Alternative bereits enthalten ist. */
    public boolean contains(String mainWordOrAlternative) {
        return words.contains(mainWordOrAlternative);
    }

    /** Prüft ob der übergebene Text ein Hauptwort oder eine der Alternativen enthält. */
    public boolean textContainsMainWordOrAlternative(String text) {
        for (String word : words) {
            if (text.contains(word)) {
                return true;
            }
        }

        return false;
    }

    /** Gibt die Anzahl der Worte (Hauptwort + Alternativen) zurück. */
    public int size() {
        return words.size();
    }

    /** Sortiert die Alternativen alphabetisch. */
    public void sortAlternatives() {
        String mainWord = getMainWord();
        List<String> alternatives = getAlternatives();
        words.clear();
        words.add(mainWord);
        Collections.sort(alternatives);
        words.addAll(alternatives);
    }

    /**
     * Sortiert die Alternativen absteigend nach der Länge. Bei gleicher Länge wird alphabetisch
     * sortiert.
     */
    public void sortAllAlternativesByLengthDescanding() {
        String mainWord = getMainWord();
        List<String> alternatives = getAlternatives();
        words.clear();
        words.add(mainWord);
        CollectionsHelper.sortStringListByLengthDescanding(alternatives);
        words.addAll(alternatives);
    }

    /**
     * Gibt eine Beschreibung zur Anzeige in Fehlermeldungen oder Debug-Ausgaben zurück.
     *
     * @param indent
     *            Die Einrücktiefe.
     * @return Beschreibung des Wörterbucheintrags.
     */
    public String createDescription(int indent) {
        String indentation1 = Text.multipleString(" ", indent);
        String indentation2 = Text.multipleString(" ", indent + 4);

        StringBuilder builder = new StringBuilder();
        builder.append(indentation1).append(getMainWord()).append("\n");
        for (String alternative : getAlternatives()) {
            builder.append(indentation2).append(alternative).append("\n");
        }
        return builder.toString();
    }

    @Override
    public int hashCode() {
        return Objects.hash(words);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        DictionaryEntry other = (DictionaryEntry) obj;
        return Objects.equals(words, other.words);
    }

    @Override
    public String toString() {
        return "DictionaryEntry [words=" + words + "]";
    }

}
