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

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;

import de.duehl.swing.ui.components.selections.SearchWordStringSelection;
import de.duehl.swing.ui.components.selections.data.SearchWordSelectionInputs;
import de.duehl.swing.ui.components.selections.tools.SelectionsHelper;
import de.duehl.swing.ui.layout.VerticalLayout;
import de.duehl.vocabulary.japanese.data.FumikoDataStructures;
import de.duehl.vocabulary.japanese.data.Vocable;
import de.duehl.vocabulary.japanese.data.Vocabulary;
import de.duehl.vocabulary.japanese.logic.ownlists.OwnLists;
import de.duehl.vocabulary.japanese.logic.sort.VocableSorter;
import de.duehl.vocabulary.japanese.tools.VocabularyTools;

/**
 * Diese Klasse stellt ein Element in Dialogen dar, mit dem eine Menge von Vokabeln gefiltert
 * werden kann.
 *
 * @version 1.01     2025-11-26
 * @author Christian Dühl
 */

public class VocableFilterPanel {

    private static final String ALL_CATEGORY = "Alle Kategorien";
    private static final String ALL_SUB_CATEGORY = "Alle Unterkategorien";
    private static final String ALL_SEARCH_WORDS = "Alle Suchbegriffe";
    private static final String ALL_PARTS_OF_SPEACH = "Alle Wortarten";
    private static final String ALL_VOCABULARIES = "Alle Vokabulare";


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

    /** Das Objekt das mit den gefilterten Vokabeln arbeitet (Anzeige, Statistik, ...). */
    private final FilteredVocablesReactor filteredVocablesReactor;

    /** Der Panel auf dem die Suchkriterien dargestellt werden. */
    private final JPanel panel;

    /** Die Combobox für die Kategorie. */
    private final JComboBox<String> categoryFilterComboBox;

    /** Die Combobox für die Unterkategorie. */
    private final JComboBox<String> subCategoryFilterComboBox;

    /** Die Combobox für das Vokabular. */
    private final JComboBox<String> vocabularyDescriptionFilterComboBox;

    /** Die Combobox für das Vokabular. */
    private final JComboBox<String> searchWordFilterComboBox;

    /** Die Combobox für das Vokabular. */
    private final JComboBox<String> partsOfSpeechFilterComboBox;

    /** Das Feld zum Eingeben von Suchbegriffen in den Kana der Vokabeln. */
    private final SearchWordStringSelection kanaSearchFilterStringSelection;

    /** Das Feld zum Eingeben von Suchbegriffen in den Kanji der Vokabeln. */
    private final SearchWordStringSelection kanjiSearchFilterStringSelection;

    /** Das Feld zum Eingeben von Suchbegriffen in den Romaji der Vokabeln. */
    private final SearchWordStringSelection romajiSearchFilterStringSelection;

    /** Das Feld zum Eingeben von Suchbegriffen in den Aussprachen der Vokabeln. */
    private final SearchWordStringSelection pronunciationSearchFilterStringSelection;

    /** Das Feld zum Eingeben von Suchbegriffen in den Übersetzungen der Vokabeln. */
    private final SearchWordStringSelection translationSearchFilterStringSelection;

    /** Das Feld zum Eingeben von Suchbegriffen in den Kommentaren der Vokabeln. */
    private final SearchWordStringSelection commentSearchFilterStringSelection;

    /** Das Feld zum Eingeben von Suchbegriffen in den Suchbegriffen der Vokabeln. */
    private final SearchWordStringSelection searchWordSearchFilterStringSelection;

    /** Das Feld zum Eingeben von Suchbegriffen in den Wortarten der Vokabeln. */
    private final SearchWordStringSelection partOfSpeechSearchFilterStringSelection;

    /** Das Feld zum Eingeben von Suchbegriffen in beliebigen Feldern der Vokabeln. */
    private final SearchWordStringSelection searchFilterStringSelection;

    /** Der Button um nach Vokabeln mit dem Suchbegriff zu suchen. */
    private final JButton searchButton;

    /** Der Button um die Feldinhalte und ComboBoxen zurückzusetzen. */
    private final JButton resetButton;

    /**
     * Gibt an, ob wirklich gefiltert wird. Wird ausgestellt beim Laden und beim Leeren der Felder.
     */
    private boolean filteringActive;

    /** Hier kann gewählt werden, ob die Combo-Boxen ausgewertet werden oder nicht. */
    private final JCheckBox comboBoxesAreActiveCheckBox;

    /**
     * Konstruktor.
     *
     * @param dataStructures
     *            Die Datenstrukturen des Vokabeltrainers.
     * @param filteredVocablesReactor
     *            Das Objekt das mit den gefilterten Vokabeln arbeitet (Anzeige, Statistik, ...).
     */
    public VocableFilterPanel(FumikoDataStructures dataStructures,
            FilteredVocablesReactor filteredVocablesReactor) {
        this.dataStructures = dataStructures;
        this.filteredVocablesReactor = filteredVocablesReactor;

        panel = new JPanel();

        categoryFilterComboBox = new JComboBox<>();
        subCategoryFilterComboBox = new JComboBox<>();
        searchWordFilterComboBox = new JComboBox<>();
        partsOfSpeechFilterComboBox = new JComboBox<>();
        vocabularyDescriptionFilterComboBox = new JComboBox<>();
        kanaSearchFilterStringSelection = new SearchWordStringSelection(
                "Suche in den Kana der Vokabeln");
        kanjiSearchFilterStringSelection = new SearchWordStringSelection(
                "Suche in den Kanji der Vokabeln");
        romajiSearchFilterStringSelection = new SearchWordStringSelection(
                "Suche in den Romaji der Vokabeln");
        pronunciationSearchFilterStringSelection = new SearchWordStringSelection(
                "Suche in den Aussprachen der Vokabeln");
        translationSearchFilterStringSelection = new SearchWordStringSelection(
                "Suche in den Übersetzungen der Vokabeln");
        commentSearchFilterStringSelection = new SearchWordStringSelection(
                "Suche in den Kommentaren der Vokabeln");
        searchWordSearchFilterStringSelection = new SearchWordStringSelection(
                "Suche in den Suchbegriffen der Vokabeln");
        partOfSpeechSearchFilterStringSelection = new SearchWordStringSelection(
                "Suche in den Wortarten der Vokabeln");
        searchFilterStringSelection = new SearchWordStringSelection(
                "Suche in beliebigen Daten der Vokabeln");
        searchButton = new JButton("filtern");
        resetButton = new JButton("Felder leeren");
        comboBoxesAreActiveCheckBox = new JCheckBox();

        filteringActive = true;

        init();
    }

    private void init() {
        initComboBoxes();
        fillComboBoxes();
        addComboboxesActionListeners();
        initSearchFields();
        initButtons();
        initCheckBoxes();
    }

    private void initComboBoxes() {
        categoryFilterComboBox.setAlignmentX(JLabel.CENTER);
        categoryFilterComboBox.setAlignmentY(JLabel.CENTER);
        ((JLabel) categoryFilterComboBox.getRenderer())
                .setHorizontalAlignment(SwingConstants.CENTER);

        subCategoryFilterComboBox.setAlignmentX(JLabel.CENTER);
        subCategoryFilterComboBox.setAlignmentY(JLabel.CENTER);
        ((JLabel) subCategoryFilterComboBox.getRenderer())
                .setHorizontalAlignment(SwingConstants.CENTER);

        searchWordFilterComboBox.setAlignmentX(JLabel.CENTER);
        searchWordFilterComboBox.setAlignmentY(JLabel.CENTER);
        ((JLabel) searchWordFilterComboBox.getRenderer())
                .setHorizontalAlignment(SwingConstants.CENTER);

        partsOfSpeechFilterComboBox.setAlignmentX(JLabel.CENTER);
        partsOfSpeechFilterComboBox.setAlignmentY(JLabel.CENTER);
        ((JLabel) partsOfSpeechFilterComboBox.getRenderer())
                .setHorizontalAlignment(SwingConstants.CENTER);

        vocabularyDescriptionFilterComboBox.setAlignmentX(JLabel.CENTER);
        vocabularyDescriptionFilterComboBox.setAlignmentY(JLabel.CENTER);
        ((JLabel) vocabularyDescriptionFilterComboBox.getRenderer())
                .setHorizontalAlignment(SwingConstants.CENTER);
    }

    private void fillComboBoxes() {
        fillCategoryComboBox();
        fillSubCategoryComboBox();
        fillSearchWordFilterComboBox();
        fillPartsOfSpeechFilterComboBox();
        fillVocabularyDescriptionComboBox();
    }

    private void fillCategoryComboBox() {
        categoryFilterComboBox.addItem(ALL_CATEGORY);

        for (String category : VocabularyTools.determineCategories(dataStructures.getVocabularies())) {
            categoryFilterComboBox.addItem(category);
        }
    }

    /** Befüllt die ComboBox mit der Unterkategorie abhängig von der Auswahl der Kategorie. */
    private void fillSubCategoryComboBox() {
        subCategoryFilterComboBox.removeAllItems();

        String selectedCategory = (String) categoryFilterComboBox.getSelectedItem();
        boolean allCategories = selectedCategory == null || selectedCategory.equals(ALL_CATEGORY);

        subCategoryFilterComboBox.addItem(ALL_SUB_CATEGORY);

        List<String> subCategories;
        if (allCategories) {
            subCategories = VocabularyTools.determineSubCategories(dataStructures.getVocabularies());
        }
        else {
            subCategories = VocabularyTools
                    .determineSubCategoriesOfCategory(dataStructures.getVocabularies(), selectedCategory);
        }

        for (String category : subCategories) {
            subCategoryFilterComboBox.addItem(category);
        }
    }

    private void fillSearchWordFilterComboBox() {
        searchWordFilterComboBox.addItem(ALL_SEARCH_WORDS);

        OwnLists ownLists = dataStructures.getOwnLists();
        for (String searchWord : ownLists.getSearchWords()) {
            searchWordFilterComboBox.addItem(searchWord);
        }
    }

    private void fillPartsOfSpeechFilterComboBox() {
        partsOfSpeechFilterComboBox.addItem(ALL_PARTS_OF_SPEACH);

        OwnLists ownLists = dataStructures.getOwnLists();
        for (String partOfSpeach : ownLists.getPartsOfSpeach()) {
            partsOfSpeechFilterComboBox.addItem(partOfSpeach);
        }
    }

    private void fillVocabularyDescriptionComboBox() {
        vocabularyDescriptionFilterComboBox.removeAllItems();

        vocabularyDescriptionFilterComboBox.addItem(ALL_VOCABULARIES);

        String selectedCategory = (String) categoryFilterComboBox.getSelectedItem();
        String selectedSubCategory = (String) subCategoryFilterComboBox.getSelectedItem();

        boolean allCategories = selectedCategory == null || selectedCategory.equals(ALL_CATEGORY);
        boolean allSubCategories = selectedSubCategory == null
                || selectedSubCategory.equals(ALL_SUB_CATEGORY);

        for (Vocabulary vocabulary : dataStructures.getVocabularies()) {
            String category = vocabulary.getCategory();
            String subCategory = vocabulary.getSubCategory();
            boolean categoryOk = allCategories || selectedCategory.equals(category);
            boolean subCategoryOk = allSubCategories || selectedSubCategory.equals(subCategory);
            if (categoryOk && subCategoryOk) {
                vocabularyDescriptionFilterComboBox.addItem(vocabulary.getDescription());
            }
        }
    }

    private void addComboboxesActionListeners() {
        categoryFilterComboBox.addActionListener(e -> categoryFilterChanged());
        subCategoryFilterComboBox.addActionListener(e -> subCategoryFilterChanged());
        searchWordFilterComboBox.addActionListener(e -> vocabularyFilterChanged());
        partsOfSpeechFilterComboBox.addActionListener(e -> vocabularyFilterChanged());
        vocabularyDescriptionFilterComboBox.addActionListener(e -> vocabularyFilterChanged());
    }

    private void categoryFilterChanged() {
        fillSubCategoryComboBox();
        fillVocabularyDescriptionComboBox();
        filterVocables();
    }

    private void subCategoryFilterChanged() {
        fillVocabularyDescriptionComboBox();
        filterVocables();
    }

    private void vocabularyFilterChanged() {
        filterVocables();
    }

    private void filterVocables() {
        if (filteringActive) {
            List<Vocable> filteredVocablesList = createFilteredVocablesList();
            sort(filteredVocablesList);
            filteredVocablesReactor.reactOnFilteredVocables(filteredVocablesList);
        }
    }

    /** Erzeugt eine Liste mit den Vokabeln, die zu den Suchkriterien passen. */
    public List<Vocable> createFilteredVocablesList() {
        List<Vocable> vocables = new ArrayList<>();

        String selectedCategory = (String) categoryFilterComboBox.getSelectedItem();
        String selectedSubCategory = (String) subCategoryFilterComboBox.getSelectedItem();
        String selectedSearchWord = (String) searchWordFilterComboBox.getSelectedItem();
        String selectedPartOfSpeech = (String) partsOfSpeechFilterComboBox.getSelectedItem();
        String selectedVocabularyDescription = (String) vocabularyDescriptionFilterComboBox
                .getSelectedItem();

        boolean allCategories = selectedCategory == null || selectedCategory.equals(ALL_CATEGORY);
        boolean allSubCategories = selectedSubCategory == null
                || selectedSubCategory.equals(ALL_SUB_CATEGORY);
        boolean allSearchWords = selectedSearchWord == null
                || selectedSearchWord.equals(ALL_SEARCH_WORDS);
        boolean allPartOfSpeech = selectedPartOfSpeech == null
                || selectedPartOfSpeech.equals(ALL_PARTS_OF_SPEACH);
        boolean allVocabularies = selectedVocabularyDescription == null
                || selectedVocabularyDescription.equals(ALL_VOCABULARIES);

        if (!comboBoxesAreActiveCheckBox.isSelected()) {
            allCategories = true;
            allSubCategories = true;
            allSearchWords = true;
            allPartOfSpeech = true;
            allVocabularies = true;
        }

        SearchWordSelectionInputs kanaInputs = kanaSearchFilterStringSelection.getInputs();
        SearchWordSelectionInputs kanjiInputs = kanjiSearchFilterStringSelection.getInputs();
        SearchWordSelectionInputs romajiInputs = romajiSearchFilterStringSelection.getInputs();
        SearchWordSelectionInputs pronunciationInputs =
                pronunciationSearchFilterStringSelection.getInputs();
        SearchWordSelectionInputs translationInputs =
                translationSearchFilterStringSelection.getInputs();
        SearchWordSelectionInputs commentInputs = commentSearchFilterStringSelection.getInputs();
        SearchWordSelectionInputs searchWordInputs =
                searchWordSearchFilterStringSelection.getInputs();
        SearchWordSelectionInputs partOfSpeechInputs =
                partOfSpeechSearchFilterStringSelection.getInputs();
        SearchWordSelectionInputs searchInputs = searchFilterStringSelection.getInputs();

        for (Vocabulary vocabulary : dataStructures.getVocabularies()) {
            String category = vocabulary.getCategory();
            String subCategory = vocabulary.getSubCategory();
            boolean categoryOk = allCategories || selectedCategory.equals(category);
            boolean subCategoryOk = allSubCategories || selectedSubCategory.equals(subCategory);

            if (categoryOk && subCategoryOk) {
                String description = vocabulary.getDescription();
                if (allVocabularies || selectedVocabularyDescription.equals(description)) {
                    for (Vocable vocable : vocabulary.getVocables()) {
                        /* DropDowns: */
                        List<String> searchWords = vocable.getSearchWords();
                        List<String> partsOfSpeach = vocable.getPartsOfSpeech();
                        boolean searchWordsOk = allSearchWords
                                || searchWords.contains(selectedSearchWord);
                        boolean subpartsOfSpeachOk = allPartOfSpeech
                                || partsOfSpeach.contains(selectedPartOfSpeech);

                        /* Suchfelder: */
                        boolean kanaSearchOk = kanaInputs.isTextEmpty()
                                || vocable.kanaContains(kanaInputs);
                        boolean kanjiSearchOk = kanjiInputs.isTextEmpty()
                                || vocable.kanjiContains(kanjiInputs);
                        boolean romajiSearchOk = romajiInputs.isTextEmpty()
                                || vocable.romajiContains(romajiInputs);
                        boolean pronunciationSearchOk = pronunciationInputs.isTextEmpty()
                                || vocable.pronunciationContains(pronunciationInputs);
                        boolean translationSearchOk = translationInputs.isTextEmpty()
                                || vocable.translationsContains(translationInputs);
                        boolean commentSearchOk = commentInputs.isTextEmpty()
                                || vocable.commentContains(commentInputs);
                        boolean searchWordSearchOk = searchWordInputs.isTextEmpty()
                                || vocable.searchWordsContains(searchWordInputs);
                        boolean partOfSpeechSearchOk = partOfSpeechInputs.isTextEmpty()
                                || vocable.partOfSpeechContains(partOfSpeechInputs);
                        boolean searchOk = searchInputs.isTextEmpty()
                                || vocable.contains(searchInputs);

                        if (searchWordsOk && subpartsOfSpeachOk && kanaSearchOk && kanjiSearchOk
                                && romajiSearchOk && pronunciationSearchOk && translationSearchOk
                                && commentSearchOk && searchWordSearchOk && partOfSpeechSearchOk
                                && searchOk) {
                            vocables.add(vocable);
                        }
                    }
                }
            }
        }

        return vocables;
    }

    private void sort(List<Vocable> filteredVocablesList) {
        String search = getRelevantSearchWord();
        if (!search.isBlank()) {
            VocableSorter sorter = new VocableSorter(filteredVocablesList, search);
            sorter.sort();
        }
    }

    private String getRelevantSearchWord() {
        SearchWordSelectionInputs kanaInputs = kanaSearchFilterStringSelection.getInputs();
        SearchWordSelectionInputs kanjiInputs = kanjiSearchFilterStringSelection.getInputs();
        SearchWordSelectionInputs romajiInputs = romajiSearchFilterStringSelection.getInputs();
        SearchWordSelectionInputs pronunciationInputs =
                pronunciationSearchFilterStringSelection.getInputs();
        SearchWordSelectionInputs translationInputs =
                translationSearchFilterStringSelection.getInputs();
        SearchWordSelectionInputs commentInputs = commentSearchFilterStringSelection.getInputs();
        SearchWordSelectionInputs searchWordInputs =
                searchWordSearchFilterStringSelection.getInputs();
        SearchWordSelectionInputs partOfSpeechInputs =
                partOfSpeechSearchFilterStringSelection.getInputs();
        SearchWordSelectionInputs searchInputs = searchFilterStringSelection.getInputs();

        if (!kanaInputs.isTextEmpty()) {
            return kanaInputs.getText();
        }
        if (!kanjiInputs.isTextEmpty()) {
            return kanjiInputs.getText();
        }
        if (!romajiInputs.isTextEmpty()) {
            return romajiInputs.getText();
        }
        if (!pronunciationInputs.isTextEmpty()) {
            return pronunciationInputs.getText();
        }
        if (!translationInputs.isTextEmpty()) {
            return translationInputs.getText();
        }
        if (!commentInputs.isTextEmpty()) {
            return commentInputs.getText();
        }
        if (!searchWordInputs.isTextEmpty()) {
            return searchWordInputs.getText();
        }
        if (!partOfSpeechInputs.isTextEmpty()) {
            return partOfSpeechInputs.getText();
        }
        if (!searchInputs.isTextEmpty()) {
            return searchInputs.getText();
        }

        return "";
    }

    private void initSearchFields() {
        initSearchWordStringSelection(kanaSearchFilterStringSelection);
        initSearchWordStringSelection(kanjiSearchFilterStringSelection);
        initSearchWordStringSelection(romajiSearchFilterStringSelection);
        initSearchWordStringSelection(pronunciationSearchFilterStringSelection);
        initSearchWordStringSelection(translationSearchFilterStringSelection);
        initSearchWordStringSelection(commentSearchFilterStringSelection);
        initSearchWordStringSelection(searchWordSearchFilterStringSelection);
        initSearchWordStringSelection(partOfSpeechSearchFilterStringSelection);
        initSearchWordStringSelection(searchFilterStringSelection);

        requestFocusInSearchFieldLater();
    }

    private void initSearchWordStringSelection(SearchWordStringSelection stringSelection) {
        stringSelection.addReturnListener(() -> searchButton.doClick());
        stringSelection.biggerText(5);
        SelectionsHelper.initSelectionAsEditor(stringSelection);
        stringSelection.setCheckboxesFocusable(false);
    }

    private void initButtons() {
        searchButton.addActionListener(e -> filterVocables());
        resetButton.addActionListener(e -> reset());
    }

    private void reset() {
        filteringActive = false;

        categoryFilterComboBox.setSelectedIndex(0);
        subCategoryFilterComboBox.setSelectedIndex(0);
        vocabularyDescriptionFilterComboBox.setSelectedIndex(0);
        searchWordFilterComboBox.setSelectedIndex(0);
        partsOfSpeechFilterComboBox.setSelectedIndex(0);

        SearchWordSelectionInputs emptyInputs = new SearchWordSelectionInputs();

        kanaSearchFilterStringSelection.loadInputs(emptyInputs);
        kanjiSearchFilterStringSelection.loadInputs(emptyInputs);
        romajiSearchFilterStringSelection.loadInputs(emptyInputs);
        pronunciationSearchFilterStringSelection.loadInputs(emptyInputs);
        translationSearchFilterStringSelection.loadInputs(emptyInputs);
        commentSearchFilterStringSelection.loadInputs(emptyInputs);
        searchWordSearchFilterStringSelection.loadInputs(emptyInputs);
        partOfSpeechSearchFilterStringSelection.loadInputs(emptyInputs);
        searchFilterStringSelection.loadInputs(emptyInputs);

        filteringActive = true;

        //searchButton.doClick();
        filterVocables();
        requestFocusInSearchFieldLater();
    }

    private void initCheckBoxes() {
        comboBoxesAreActiveCheckBox.addActionListener(e -> comboBoxesAreActiveCheckBoxChanged());
        comboBoxesAreActiveCheckBox.setSelected(true);
        String text = "<html>A<br>k<br>t<br>i<br>v</html";
        text = "";
        comboBoxesAreActiveCheckBox.setText(text);
        comboBoxesAreActiveCheckBox.setHorizontalTextPosition(JCheckBox.CENTER);
        comboBoxesAreActiveCheckBox.setVerticalTextPosition(JCheckBox.BOTTOM);
    }

    private void comboBoxesAreActiveCheckBoxChanged() {
        boolean enable = comboBoxesAreActiveCheckBox.isSelected();

        categoryFilterComboBox.setEnabled(enable);
        subCategoryFilterComboBox.setEnabled(enable);
        vocabularyDescriptionFilterComboBox.setEnabled(enable);
        searchWordFilterComboBox.setEnabled(enable);
        partsOfSpeechFilterComboBox.setEnabled(enable);

        filterVocables();
        //searchButton.doClick();
    }

    /** Arrangiert die Elemente passend für den Dialog zum Bearbeiten eigener Listen. */
    public void arrangeForListEditDialog() {
        panel.setLayout(new BorderLayout());

        panel.add(createSearchFilterSelectionsArrangedForListEditDialog(), BorderLayout.CENTER);
        panel.add(createCheckBoxComboboxesAndButtonArrangedForListEditDialog(), BorderLayout.SOUTH);
    }

    private Component createSearchFilterSelectionsArrangedForListEditDialog() {
        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(0, 3, 2, 2));

        /* Zeile 1: */
        panel.add(kanaSearchFilterStringSelection.getPanel());
        panel.add(kanjiSearchFilterStringSelection.getPanel());
        panel.add(romajiSearchFilterStringSelection.getPanel());

        /* Zeile 2: */
        panel.add(pronunciationSearchFilterStringSelection.getPanel());
        panel.add(translationSearchFilterStringSelection.getPanel());
        panel.add(commentSearchFilterStringSelection.getPanel());

        /* Zeile 3: */
        panel.add(searchWordSearchFilterStringSelection.getPanel());
        panel.add(partOfSpeechSearchFilterStringSelection.getPanel());
        panel.add(searchFilterStringSelection.getPanel());

        return panel;
    }

    private Component createCheckBoxComboboxesAndButtonArrangedForListEditDialog() {
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());

        panel.add(comboBoxesAreActiveCheckBox, BorderLayout.WEST);
        panel.add(createComboboxesAndButtonArrangedForListEditDialog(), BorderLayout.CENTER);

        return panel;
    }

    private Component createComboboxesAndButtonArrangedForListEditDialog() {
        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(0, 3, 2, 2));

        /* Zeile 4: */
        panel.add(categoryFilterComboBox);
        panel.add(searchWordFilterComboBox);
        panel.add(vocabularyDescriptionFilterComboBox);

        /* Zeile 5: */
        panel.add(subCategoryFilterComboBox);
        panel.add(partsOfSpeechFilterComboBox);
        panel.add(createButtonPartForListEditDialog());

        return panel;
    }

    private Component createButtonPartForListEditDialog() {
        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(0, 2, 1, 1));

        panel.add(resetButton);
        panel.add(searchButton);

        return panel;
    }

    /**
     * Arrangiert die Elemente passend für den Dialog zur erweiterten Suche.
     *
     * Hier wird die comboBoxesAreActiveCheckBox nicht angezeigt und ist immer ausgewählt.
     */
    public void arrangeForComplexVocableSearchDialog() {
        panel.setLayout(new VerticalLayout(3, VerticalLayout.BOTH));

        panel.add(categoryFilterComboBox);
        panel.add(subCategoryFilterComboBox);
        panel.add(vocabularyDescriptionFilterComboBox);
        panel.add(searchWordFilterComboBox);
        panel.add(partsOfSpeechFilterComboBox);
        panel.add(createVocableSearchFilterPartForComplexVocableSearchDialog());
    }

    private Component createVocableSearchFilterPartForComplexVocableSearchDialog() {
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());

        panel.add(createSearchFilterSelectionsPart(), BorderLayout.CENTER);
        panel.add(createButtonPart(), BorderLayout.SOUTH);

        return panel;
    }

    private Component createButtonPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new VerticalLayout(2, VerticalLayout.BOTH));

        panel.add(resetButton);
        panel.add(searchButton);

        return panel;
    }

    private Component createSearchFilterSelectionsPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new VerticalLayout(3, VerticalLayout.BOTH));

        panel.add(kanaSearchFilterStringSelection.getPanel());
        panel.add(kanjiSearchFilterStringSelection.getPanel());
        panel.add(romajiSearchFilterStringSelection.getPanel());
        panel.add(pronunciationSearchFilterStringSelection.getPanel());
        panel.add(translationSearchFilterStringSelection.getPanel());
        panel.add(commentSearchFilterStringSelection.getPanel());
        panel.add(searchWordSearchFilterStringSelection.getPanel());
        panel.add(partOfSpeechSearchFilterStringSelection.getPanel());
        panel.add(searchFilterStringSelection.getPanel());

        return panel;
    }

    /** Getter für den Panel auf dem die Suchkriterien dargestellt werden. */
    public JPanel getPanel() {
        return panel;
    }

    /** Setzt später den Focus auf das Eingabefeld für den Suchbegriff. */
    public void requestFocusInSearchFieldLater() {
        SwingUtilities.invokeLater(() -> searchFilterStringSelection.requestFocus());
    }

    /** Lädt die Suchparameter aus dem übergebenen Speicherobjekt. */
    public void loadInputs(VocableFilterInputs inputs) {
        filteringActive = false;

        categoryFilterComboBox.setSelectedIndex(inputs.getCategoryFilterComboBoxIndex());
        subCategoryFilterComboBox.setSelectedIndex(inputs.getSubCategoryFilterComboBoxIndex());
        vocabularyDescriptionFilterComboBox.setSelectedIndex(
                inputs.getVocabularyDescriptionFilterComboBoxIndex());
        searchWordFilterComboBox.setSelectedIndex(inputs.getSearchWordFilterComboBoxIndex());
        partsOfSpeechFilterComboBox.setSelectedIndex(inputs.getPartsOfSpeechFilterComboBoxIndex());

        kanaSearchFilterStringSelection.loadInputs(inputs.getKanaSearchFilterInputs());
        kanjiSearchFilterStringSelection.loadInputs(inputs.getKanjiSearchFilterInputs());
        romajiSearchFilterStringSelection.loadInputs(inputs.getRomajiSearchFilterInputs());
        pronunciationSearchFilterStringSelection.loadInputs(
                inputs.getPronunciationSearchFilterInputs());
        translationSearchFilterStringSelection.loadInputs(
                inputs.getTranslationSearchFilterInputs());
        commentSearchFilterStringSelection.loadInputs(inputs.getCommentSearchFilterInputs());
        searchWordSearchFilterStringSelection.loadInputs(inputs.getSearchWordSearchFilterInputs());
        partOfSpeechSearchFilterStringSelection.loadInputs(
                inputs.getPartOfSpeechSearchFilterInputs());
        searchFilterStringSelection.loadInputs(inputs.getSearchFilterInputs());

        filteringActive = true;

        searchButton.doClick();
    }

    /** Speichert die Suchparameter im übergebenen Speicherobjekt. */
    public void storeInputs(VocableFilterInputs inputs) {
        inputs.setCategoryFilterComboBoxIndex(categoryFilterComboBox.getSelectedIndex());
        inputs.setSubCategoryFilterComboBoxIndex(subCategoryFilterComboBox.getSelectedIndex());
        inputs.setVocabularyDescriptionFilterComboBoxIndex(
                vocabularyDescriptionFilterComboBox.getSelectedIndex());
        inputs.setSearchWordFilterComboBoxIndex(searchWordFilterComboBox.getSelectedIndex());
        inputs.setPartsOfSpeechFilterComboBoxIndex(partsOfSpeechFilterComboBox.getSelectedIndex());

        kanaSearchFilterStringSelection.storeInputs(inputs.getKanaSearchFilterInputs());
        kanjiSearchFilterStringSelection.storeInputs(inputs.getKanjiSearchFilterInputs());
        romajiSearchFilterStringSelection.storeInputs(inputs.getRomajiSearchFilterInputs());
        pronunciationSearchFilterStringSelection.storeInputs(
                inputs.getPronunciationSearchFilterInputs());
        translationSearchFilterStringSelection.storeInputs(
                inputs.getTranslationSearchFilterInputs());
        commentSearchFilterStringSelection.storeInputs(inputs.getCommentSearchFilterInputs());
        searchWordSearchFilterStringSelection.storeInputs(inputs.getSearchWordSearchFilterInputs());
        partOfSpeechSearchFilterStringSelection.storeInputs(
                inputs.getPartOfSpeechSearchFilterInputs());
        searchFilterStringSelection.storeInputs(inputs.getSearchFilterInputs());
    }

}
