package de.duehl.vocabulary.japanese.ui.dialog.table.vocable;

import java.awt.Color;
import java.util.List;

import javax.swing.table.AbstractTableModel;

import de.duehl.basics.datetime.date.ImmutualDate;
import de.duehl.basics.text.Text;
import de.duehl.vocabulary.japanese.common.color.VocableColors;
import de.duehl.vocabulary.japanese.common.data.InternalAdditionalVocableData;
import de.duehl.vocabulary.japanese.common.data.TranslationDirection;
import de.duehl.vocabulary.japanese.common.persistence.Options;
import de.duehl.vocabulary.japanese.data.FumikoDataStructures;
import de.duehl.vocabulary.japanese.data.OwnList;
import de.duehl.vocabulary.japanese.data.Vocable;
import de.duehl.vocabulary.japanese.logic.internal.InternalDataRequester;
import de.duehl.vocabulary.japanese.logic.ownlists.OwnLists;
import de.duehl.vocabulary.japanese.ui.dialog.table.TableHelper;

/**
 * Diese Klasse ist ein eigenes Tabellenmodell für die Ansicht der Vokabeln. Es hält die Daten der
 * Tabelle in Form einer Liste von Vocable-Objekten vor und weiß diese anzuzeigen.
 *
 * @version 1.01     2025-11-20
 * @author Christian Dühl
 */

public class VocableTableModel extends AbstractTableModel {

    private static final int NUMBER_OF_COLUMNS_WITHOUT_NUMBER_OF_LISTS_COLUMN = 18;

    private static final long serialVersionUID = 1L;


    /** Die Liste mit den Vokabeln der Tabelle. */
    private final List<Vocable> vocables;

    /** Die Datenstrukturen des Vokabeltrainers. */
    private final FumikoDataStructures dataStructures;

    /** Gibt an, ob von Japanisch nach Deutsch übersetzt wird. Falls nicht ist es andersherum. */
    private final boolean translationJapaneseToGerman;

    /** Die Richtung, in die übersetzt wird (Japanisch - Deutsch oder Deutsch - Japanisch). */
    private final TranslationDirection translationDirection;

    /**
     * Konstruktor.
     *
     * @param vocables
     *            Die Liste mit den Vokabeln der Tabelle.
     * @param dataStructures
     *            Die Datenstrukturen des Vokabeltrainers.
     */
    public VocableTableModel(List<Vocable> vocables,
            FumikoDataStructures dataStructures) {
        super();
        this.vocables = vocables;
        this.dataStructures = dataStructures;

        Options options = dataStructures.getOptions();
        translationDirection = options.getTranslationDirection();
        if (translationDirection == TranslationDirection.JAPANESE_TO_GERMAN) {
            translationJapaneseToGerman = true;
        }
        else if (translationDirection == TranslationDirection.GERMAN_TO_JAPANESE){
            translationJapaneseToGerman = false;
        }
        else {
            throw new RuntimeException("Unbekannte Abfragerichtung " + translationDirection);
        }
    }

    /** Ermittelt die Zeilenzahl. */
    @Override
    public int getRowCount() {
        return vocables.size();
    }

    /** Ermittelt die Spaltenzahl. */
    @Override
    public int getColumnCount() {
        int columnCount = NUMBER_OF_COLUMNS_WITHOUT_NUMBER_OF_LISTS_COLUMN;
        Options options = dataStructures.getOptions();
        if (options.isShowNumberOfListsInLister()) {
            ++columnCount;
        }
        return columnCount;
    }

    /**
     * Gibt an, ob die Zelle bearbeitbar ist. Dies muss für die Buttons der Fall sein.
     *
     * @param rowIndex
     *            Zeilenindex (die erste hat die 0)
     * @param columnIndex
     *            Spaltenindex (die erste hat die 0)
     */
    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        return columnIndex == 6 || columnIndex == 17;
    }

    /**
     * Ermittelt den Tabelleninhalt der angegebenen Zelle.
     *
     * Die Tabelle enthält die folgenden Spalten:
     *     - laufende Nummer
     *     - kana
     *     - kanji
     *     - romaji
     *     - pronunciation
     *     - translation(s)
     *     - Button zum Abspielen der MP3-Datei
     *     - comment
     *     - Suchbegriffe
     *     - Wortarten
     *     - Beschreibung des Vokabulars aus dem die Vokabel stammt
     *     - testCount (data)
     *     - correctTestCount (data)
     *     - firstSeenDate (data)
     *     - lastTestDate (data)
     *     - lastCorrectTestDate (data)
     *     - lastTenTestResults (data)
     *     - Button zum Betrachten der Vokabel mit allen internen Daten
     *
     * @param rowIndex
     *            Zeilenindex (die erste hat die 0)
     * @param columnIndex
     *            Spaltenindex (die erste hat die 0)
     */
    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        Vocable vocable = vocables.get(rowIndex);
        InternalDataRequester requester = dataStructures.getInternalDataRequester();
        InternalAdditionalVocableData data = requester.getInternalDataForVocable(vocable);
        switch (columnIndex) {
            case 0:
                return rowIndex + 1;
            case 1:
                return vocable.getKana();
            case 2:
                return vocable.getKanji();
            case 3:
                return vocable.getRomaji();
            case 4:
                return vocable.getPronunciation();
            case 5:
                return Text.join(", ", vocable.getTranslations());
            case 6:
                return "abspielen";
            case 7:
                return vocable.getComment();
            case 8:
                return Text.joinWithCommaAndBlank(vocable.getSearchWords());
            case 9:
                return Text.joinWithCommaAndBlank(vocable.getPartsOfSpeech());
            case 10:
                return vocable.getVocabularyDescription();
            case 11:
                if (translationJapaneseToGerman) {
                    return data.getJapaneseToGermanTestCount();
                }
                else {
                    return data.getGermanToJapaneseTestCount();
                }
            case 12:
                if (translationJapaneseToGerman) {
                    return data.getCorrectJapaneseToGermanTestCount();
                }
                else {
                    return data.getCorrectGermanToJapaneseTestCount();
                }
            case 13:
                return data.getFirstSeenDate();
            case 14:
                if (translationJapaneseToGerman) {
                    return TableHelper.dateOrEmpty(data.getLastJapaneseToGermanTestDate(),
                            data.getJapaneseToGermanTestCount());
                }
                else {
                    return TableHelper.dateOrEmpty(data.getLastGermanToJapaneseTestDate(),
                            data.getGermanToJapaneseTestCount());
                }
            case 15:
                if (translationJapaneseToGerman) {
                    return TableHelper.dateOrEmpty(data.getLastCorrectJapaneseToGermanTestDate(),
                            data.getCorrectJapaneseToGermanTestCount());
                }
                else {
                    return TableHelper.dateOrEmpty(data.getLastCorrectGermanToJapaneseTestDate(),
                            data.getCorrectGermanToJapaneseTestCount());
                }
            case 16:
                if (translationJapaneseToGerman) {
                    return TableHelper.createMonospaceHtml(
                            data.getLastTenJapaneseToGermanTestResultsAsStorageString());
                }
                else {
                    return TableHelper.createMonospaceHtml(
                            data.getLastTenGermanToJapaneseTestResultsAsStorageString());
                }
            case 17:
                return " ";
            case 18:
                Options options = dataStructures.getOptions();
                if (options.isShowNumberOfListsInLister()) {
                    return createNumberOfTablesAndLernlistText(vocable);
                }
                else {
                    return " ";
                }
            default:
                throw new RuntimeException("Unzuläsiger Spaltenindex '" + columnIndex + "'.");
        }
    }

    private String createNumberOfTablesAndLernlistText(Vocable vocable) {
        OwnLists ownLists = dataStructures.getOwnLists();
        List<OwnList> ownListsWithVocable = ownLists .getOwnListsWithVocable(vocable);
        int lernlistCount = 0;
        for (OwnList ownList : ownListsWithVocable) {
            if (ownList.isLernliste()) {
                ++lernlistCount;
            }
        }
        String lernlistText;
        if (lernlistCount == 0) {
            lernlistText = "";
        }
        else if (lernlistCount == 1) {
            lernlistText = "L";
        }
        else {
            lernlistText = "L!";
        }

        return Integer.toString(ownListsWithVocable.size()) + lernlistText;
    }

    @Override
    public Class<?> getColumnClass(int column) {
        switch (column) {
            case 0:
            case 11:
            case 12:
                return Integer.class;
            case 1:
            case 2:
            case 3:
            case 4:
            case 5:
                // 6 ist der Button zum Abspielen
            case 7:
            case 8:
            case 9:
                // 17 ist der Button für die Interna
                return String.class;
            case 13:
            case 14:
            case 15:
                return ImmutualDate.class;
            default:
                return String.class;
        }
    }

    /**
     * Erzeugt die Vordergrundfarbe für die Zeile mit dem übergebenen Zeilenindex.
     *
     * @param rowIndex
     *            Zeilenindex (die erste hat die 0)
     * @return Farbwert für den Vordergrund.
     */
    public Color determineRowForegroundColor(int rowIndex) {
        Vocable vocable = vocables.get(rowIndex);
        InternalDataRequester requester = dataStructures.getInternalDataRequester();
        InternalAdditionalVocableData data = requester.getInternalDataForVocable(vocable);
        Options options = dataStructures.getOptions();
        VocableColors vocableColors = new VocableColors(options);
        return vocableColors.determineForegroundColor(data, true, translationDirection);
    }

    /**
     * Erzeugt die Hintergrundfarbe für die Zeile mit dem übergebenen Zeilenindex.
     *
     * @param rowIndex
     *            Zeilenindex (die erste hat die 0)
     * @return Farbwert für den Hintergrund.
     */
    public Color determineRowBackgroundColor(int rowIndex) {
        Vocable vocable = vocables.get(rowIndex);
        InternalDataRequester requester = dataStructures.getInternalDataRequester();
        InternalAdditionalVocableData data = requester.getInternalDataForVocable(vocable);
        Options options = dataStructures.getOptions();
        VocableColors vocableColors = new VocableColors(options);
        return vocableColors.determineBackgroundColor(data, true, translationDirection);
    }

}
