package de.duehl.vocabulary.japanese.ui.tabs;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.JTabbedPane;

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.data.Vocabulary;
import de.duehl.vocabulary.japanese.logic.VocabularyTrainerLogic;
import de.duehl.vocabulary.japanese.tools.VocabularyTools;
import de.duehl.vocabulary.japanese.ui.VocabularyTrainerGui;
import de.duehl.vocabulary.japanese.ui.components.bars.VocabularyBar;
import de.duehl.vocabulary.japanese.ui.data.FumikoUiObjects;

/**
 * Diese Klasse stellt Panel mit den Reitern für die Kategorien (entweder die der Vokabularien oder
 * die der eigenen Listen) dar.
 *
 * @version 1.01     2025-11-20
 * @author Christian Dühl
 */

public class CategoryTabs {

    /** Die Kategorien die hier dargestellt werden. */
    private final List<String> categories;

    /** Die Liste der Vokabularien. */
    private final List<? extends Vocabulary> vocabularies;

    /** Die Logik des Vokabel-Trainers. */
    private final VocabularyTrainerLogic logic;

    /** Die grafische Oberfläche des Vokabel-Trainers. */
    private final VocabularyTrainerGui gui;

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

    /** Die häufig verwendeten Funktionen der grafischen Oberfläche des Vokabeltrainers. */
    private final FumikoUiObjects uiObjects;

    /** Der Panel mit den Reitern für die Kategorien. */
    private final JTabbedPane categoryTabs;

    /** Das Verzeichnis der Listen von Vokabularien nach der Kategorie. */
    private final Map<String, List<Vocabulary>> vocabulariesByCategoryMap;

    /** Die Liste der erzeugten SubCategoryTabs. */
    private final List<SubCategoryTabs> subCategoryTabsList;

    /**
     * Konstruktor.
     *
     * @param categories
     *            Die Kategorien die hier dargestellt werden.
     * @param vocabularies
     *            Die Liste der Vokabularien.
     * @param logic
     *            Die Logik des Vokabel-Trainers.
     * @param gui
     *            Die grafische Oberfläche des Vokabel-Trainers.
     * @param dataStructures
     *            Die Datenstrukturen des Vokabeltrainers..
     * @param uiObjects
     *            Die häufig verwendeten Funktionen der grafischen Oberfläche des Vokabeltrainers.
     */
    public CategoryTabs(List<String> categories, List<? extends Vocabulary> vocabularies,
            VocabularyTrainerLogic logic, VocabularyTrainerGui gui,
            FumikoDataStructures dataStructures, FumikoUiObjects uiObjects) {
        this.categories = categories;
        this.vocabularies = vocabularies;
        this.logic = logic;
        this.gui = gui;
        this.dataStructures = dataStructures;
        this.uiObjects = uiObjects;

        vocabulariesByCategoryMap = createVocabulariesByCategoryMap();
        subCategoryTabsList = new ArrayList<>();

        categoryTabs = new JTabbedPane();

        populateCategoryTabs();
    }

    private Map<String, List<Vocabulary>> createVocabulariesByCategoryMap() {
        Map<String, List<Vocabulary>> vocybularyListByCategory = new HashMap<>();

        for (Vocabulary vocabulary : vocabularies) {
            String category = vocabulary.getCategory();
            if (!vocybularyListByCategory.containsKey(category)) {
                vocybularyListByCategory.put(category, new ArrayList<>());
            }
            List<Vocabulary> list = vocybularyListByCategory.get(category);
            list.add(vocabulary);
        }

        return vocybularyListByCategory;
    }

    private void populateCategoryTabs() {
        for (String category : categories) {
            populateForCategory(category);
        }
    }

    private void populateForCategory(String category) {
        if (!vocabulariesByCategoryMap.containsKey(category)) {
            throw new RuntimeException("Zur Kategorie '" + category + "' wurde keine Liste "
                    + "an Vokabularien gefunden.");
        }

        List<Vocabulary> vocabulariesOfCategory = vocabulariesByCategoryMap.get(category);

        List<String> subCategoriesOfCategory = VocabularyTools.determineSubCategoriesOfCategory(
                vocabulariesOfCategory, category);

        SubCategoryTabs subCategoryTabs = new SubCategoryTabs(subCategoriesOfCategory,
                vocabulariesOfCategory, logic, gui, dataStructures, uiObjects);
        categoryTabs.add(category, subCategoryTabs.getSubCategoryTabs());
        subCategoryTabsList.add(subCategoryTabs);
    }

    /**
     * Hier werden die persistent gespeicherten zuletzt aktiven Tabs sowohl bei den Vokabularien
     * als auch bei den eigenen Listen wieder angezeigt.
     *
     * Das Gegenstück zu dieser Methode ist storeShownTabIndices().
     */
    public void showTabsWeViewedLastTime(String lastShownTabIndexType) {
        Options options = dataStructures.getOptions();
        int lastShownCategoryTabIndex;
        if (lastShownTabIndexType.equals(MainTabs.VOCABULARY_LAST_SHOWN_TAB_INDEX_TYPE)) {
            lastShownCategoryTabIndex = options.getLastShownVocabularyCategoryTabIndex();
        }
        else if (lastShownTabIndexType.equals(MainTabs.OWN_LIST_LAST_SHOWN_TAB_INDEX_TYPE)) {
            lastShownCategoryTabIndex = options.getLastShownOwnListCategoryTabIndex();
        }
        else {
            throw new RuntimeException(
                    "Unbekannter lastShownTabIndexType '" + lastShownTabIndexType + "'.");
        }

        if (lastShownCategoryTabIndex >= 0
                && lastShownCategoryTabIndex < categoryTabs.getTabCount()) {
            categoryTabs.setSelectedIndex(lastShownCategoryTabIndex);

            SubCategoryTabs subCategoryTabs = subCategoryTabsList.get(lastShownCategoryTabIndex);
            // Die Indizes passen überein.
            subCategoryTabs.showTabsWeViewedLastTime(lastShownTabIndexType);
        }
    }

    /**
     * Speichert die Indices des aktuell angezeigten Tabs in jeder Kategorie in den Optionen.
     *
     * Das Gegenstück zu dieser Methode ist showTabsWeViewedLastTime().
     */
    public void storeShownTabIndices(Options options, String lastShownTabIndexType) {
        int lastShownCategoryTabIndex = categoryTabs.getSelectedIndex();

        /*
         * Hat man keine eigenen Listen, so bekommt man hier den Index -1 und bei
         *     subCategoryTabsList.get(lastShownCategoryTabIndex)
         * wird dann eine Ausnahme geworfen. Also prüfe ich den Index:
         */
        if (lastShownCategoryTabIndex != -1) {
            if (lastShownTabIndexType.equals(MainTabs.VOCABULARY_LAST_SHOWN_TAB_INDEX_TYPE)) {
                options.setLastShownVocabularyCategoryTabIndex(lastShownCategoryTabIndex);
            }
            else if (lastShownTabIndexType.equals(MainTabs.OWN_LIST_LAST_SHOWN_TAB_INDEX_TYPE)) {
                options.setLastShownOwnListCategoryTabIndex(lastShownCategoryTabIndex);
            }
            else {
                throw new RuntimeException(
                        "Unbekannter lastShownTabIndexType '" + lastShownTabIndexType + "'.");
            }


            SubCategoryTabs subCategoryTabs = subCategoryTabsList.get(lastShownCategoryTabIndex);
            // Die Indizes passen überein.
            subCategoryTabs.storeShownTabIndices(options, lastShownTabIndexType);
        }
    }

    /** Ermittelt die Liste der Vokabeln aus den ausgewählten Vokabularien. */
    public List<Vocable> collectVocablesOfSelectedVocabularies() {
        List<Vocable> vocables = new ArrayList<>();

        for (SubCategoryTabs subCategoryTabs : subCategoryTabsList) {
            vocables.addAll(subCategoryTabs.collectVocablesOfSelectedVocabularies());
        }

        return vocables;
    }

    /** Sortiert die angezeigten Vokabularien so, wie es in den Optionen eingetragen ist. */
    public void showVocabularyBarsInWantedOrder() {
        for (SubCategoryTabs subCategoryTabs : subCategoryTabsList) {
            subCategoryTabs.showVocabularyBarsInWantedOrder();
        }
    }

    /** Zeigt oder versteckt die Buttons zur individuellen Sortierung der Vokabularien. */
    public void showOrHideIndividualVocabularySortModeMoveButtons() {
        for (SubCategoryTabs subCategoryTabs : subCategoryTabsList) {
            subCategoryTabs.showOrHideIndividualVocabularySortModeMoveButtons();
        }
    }

    /**
     * Gibt die Vokabularien in der benutzerdefinierten Reihenfolge zurück.
     *
     * Wird nur aufgerufen, wenn die Vokabularien auch in der individuellen Sortierung angezeigt
     * werden.
     */
    public List<Vocabulary> getVocabulariesInIndividualOrder() {
        List<Vocabulary> list = new ArrayList<>();

        for (SubCategoryTabs subCategoryTabs : subCategoryTabsList) {
            list.addAll(subCategoryTabs.getVocabularyBarsInIndividualOrder());
        }

        return list;
    }

    /**
     * Gibt die OwnLists in der benutzerdefinierten Reihenfolge zurück.
     *
     * Wird nur aufgerufen, wenn die Vokabularien auch in der individuellen Sortierung angezeigt
     * werden.
     */
    public List<OwnList> getOwnListsInIndividualOrder() {
        List<OwnList> list = new ArrayList<>();

        for (SubCategoryTabs subCategoryTabs : subCategoryTabsList) {
            list.addAll(subCategoryTabs.getOwnListsInIndividualOrder());
        }

        return list;
    }

    /** Ermittelt die auf dem aktuellen Reiter angezeigten VocabularyBars. */
    public List<VocabularyBar> determineBarsOfSelectedTab() {
        int selectedIndex = categoryTabs.getSelectedIndex();

        SubCategoryTabs subCategoryTabs = subCategoryTabsList.get(selectedIndex);
        // Die Indizes passen überein.

        return subCategoryTabs.determineBarsOfSelectedTab();
    }

    /**
     * Setzt die Vordergrundfarbe auf den nach den Optionen und ggf. dem Durchschnitt der
     * erfolgreichen Abfrage der Vokabeln aus dem Vokabular in allen Vokabularien richtig.
     */
    public void setCorrectForegroundColorOfVocabularyBars() {
        for (SubCategoryTabs subCategoryTabs : subCategoryTabsList) {
            subCategoryTabs.setCorrectForegroundColorOfVocabularyBars();
        }
    }

    /** Aktualisiert den angezeigten Text in allen Vokabularien je nach den Optionen. */
    public void setCorrectTextOfVocabularyBars() {
        for (SubCategoryTabs subCategoryTabs : subCategoryTabsList) {
            subCategoryTabs.setCorrectTextOfVocabularyBars();
        }
    }

    /**
     * Aktualisiert den angezeigten Text zum Prozent des Erfolges in allen Vokabularien je nach den
     * Optionen.
     */
    public void showOrHidePercentInVocabularyBarsLater() {
        for (SubCategoryTabs subCategoryTabs : subCategoryTabsList) {
            subCategoryTabs.showOrHidePercentInVocabularyBarsLater();
        }
    }

    /** Getter für den Panel mit den Reitern für die Kategorien. */
    public JTabbedPane getCategoryTabs() {
        return categoryTabs;
    }

    /**
     * Zeigt auf dem Übersetzen-Buttons aller Bars das richtige Icon für die Richtung der
     * Übersetzung an.
     */
    public void showTranslationDirectionOnBarButtons() {
        for (SubCategoryTabs subCategoryTabs : subCategoryTabsList) {
            subCategoryTabs.showTranslationDirectionOnBarButtons();
        }
    }

    /** Buttons zum Exportieren, Bearbeiten und Löschen von eigene Listen ein oder ausschalten. */
    public void toggleShowOwnListButtons() {
        for (SubCategoryTabs subCategoryTabs : subCategoryTabsList) {
            subCategoryTabs.toggleShowOwnListButtons();
        }
    }

    /** Zeigt die normalen Button zum Abfragen und betrachten der Vokabularien an. */
    public void showTestViewListSheetButtons() {
        for (SubCategoryTabs subCategoryTabs : subCategoryTabsList) {
            subCategoryTabs.showTestViewListSheetButtons();
        }
    }

    /** Zeigt bei eigenen Listen die Buttons zum Löschen, Bearbeiten und Exportieren an. */
    public void showOwnListExtraButtons() {
        for (SubCategoryTabs subCategoryTabs : subCategoryTabsList) {
            subCategoryTabs.showOwnListExtraButtons();
        }
    }

}
