package de.duehl.vocabulary.japanese.ui.dialog.vocables.single;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.List;

import javax.swing.Action;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

import de.duehl.swing.logic.LongTimeProcessInformer;
import de.duehl.swing.ui.GuiTools;
import de.duehl.swing.ui.dialogs.base.NonModalFrameDialogBase;
import de.duehl.swing.ui.elements.navigator.list.ListNavigator;
import de.duehl.swing.ui.key.BindKeysOnRootPane;
import de.duehl.swing.ui.layout.VerticalLayout;
import de.duehl.vocabulary.japanese.common.data.InternalAdditionalVocableData;
import de.duehl.vocabulary.japanese.common.data.VocablesShuffleType;
import de.duehl.vocabulary.japanese.common.persistence.Options;
import de.duehl.vocabulary.japanese.data.FumikoDataStructures;
import de.duehl.vocabulary.japanese.data.Vocable;
import de.duehl.vocabulary.japanese.logic.internal.InternalDataRequester;
import de.duehl.vocabulary.japanese.tools.VocableListShuffler;
import de.duehl.vocabulary.japanese.ui.components.VocableViewer;
import de.duehl.vocabulary.japanese.ui.components.button.OtherViewButtonPanel;
import de.duehl.vocabulary.japanese.ui.components.button.ViewButtonPressedReactor;
import de.duehl.vocabulary.japanese.ui.data.FumikoUiObjects;
import de.duehl.vocabulary.japanese.ui.dialog.vocables.detail.VocableWithInternaViewer;
import de.duehl.vocabulary.japanese.ui.dialog.vocables.detail.addtolist.VocableToOwnListAdderWithChangingVocableGui;
import de.duehl.vocabulary.japanese.ui.dialog.vocables.detail.findlists.ListsWithVocableFinderWithChangingVocableGui;
import de.duehl.vocabulary.japanese.ui.dialog.vocables.detail.related.VerbsAndAdjectivesFinderWithChangingVocableGui;
import de.duehl.vocabulary.japanese.ui.tools.VocabularyTrainerUiTools;

/**
 * Diese Klasse zeigt alle Vokabeln eines Vokabulars an.
 *
 * @version 1.01     2025-12-04
 * @author Christian Dühl
 */

public class SingleVocableVocabularyViewerDialog extends NonModalFrameDialogBase
        implements ViewButtonPressedReactor {

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

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

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

    /** Der Navigator für die Vokabeln. */
    private final ListNavigator<Vocable> navigator;

    /** Zeigt eine Vokabel in der sogenannten Einzeldarstellung an. */
    private final VocableViewer vocableViewer;

    /**
     * Zeigt drei Buttons an, mit denen man eine Menge von Vokabeln in Form einer
     * Einzeldarstellung, in Form einer Liste und in Form eines Vokabelblattes anzeigen lassen
     * kann.
     */
    private final OtherViewButtonPanel otherViewPanel;

    /** Der Button mit dem man das Einfärben des Hintergrunds ein- und ausschaltet. */
    private final JButton backgroundChangingButton;

    /**
     * Kann einen Button anlegen, um zur angezeigten Vokabel alle eigenen Listen anzuzeigen, welche
     * die Vokabel enthalten.
     */
    private final ListsWithVocableFinderWithChangingVocableGui listsWithVocableFinderGui;

    /** Kann einen Button anlegen, um die angezeigte Vokabel zu einer eigenen Liste hinzuzufügen. */
    private final VocableToOwnListAdderWithChangingVocableGui vocableToOwnListAdderGui;

    /**
     * Kann Buttons anlegen, um zur angezeigten Vokabel gehörige Verb- und Adjektivformen zu
     * finden.
     */
    private final VerbsAndAdjectivesFinderWithChangingVocableGui verbsAndAdjectivesFinderGui;

    /** Gibt an, ob der Dialog aus der einfachen Suche geöffnet wurde. */
    private boolean openedFromSimpleSearch;

    /**
     * Konstruktor.
     *
     * @param vocables
     *            Die Liste mit den abzufragenden Vokabeln.
     * @param description
     *            Die Beschreibung der Menge von Vokabeln.
     * @param dataStructures
     *            Die Datenstrukturen des Vokabeltrainers.
     * @param uiObjects
     *            Die häufig verwendeten Funktionen der grafischen Oberfläche des Vokabeltrainers.
     */
    public SingleVocableVocabularyViewerDialog(List<Vocable> vocables, String description,
            FumikoDataStructures dataStructures, FumikoUiObjects uiObjects) {
        super(uiObjects.getGuiLocation(), uiObjects.getProgramImage(),
                createDialogTitle(vocables, description, dataStructures));
        addEscapeBehaviour();

        this.vocables = vocables;
        this.dataStructures = dataStructures;
        this.uiObjects = uiObjects;

        Options options = dataStructures.getOptions();
        vocableViewer = new VocableViewer(options);
        navigator = new ListNavigator<>();

        otherViewPanel = new OtherViewButtonPanel(vocables, (ViewButtonPressedReactor) this,
                description, dataStructures, uiObjects, uiObjects.getInformer());
        otherViewPanel.disableEinzeldarstellungButton();

        backgroundChangingButton = new JButton();

        listsWithVocableFinderGui = new ListsWithVocableFinderWithChangingVocableGui(dataStructures,
                getWindowAsComponent());
        vocableToOwnListAdderGui = new VocableToOwnListAdderWithChangingVocableGui(dataStructures,
                uiObjects, getLocation());
        verbsAndAdjectivesFinderGui = new VerbsAndAdjectivesFinderWithChangingVocableGui(
                dataStructures, uiObjects, getLocation(), (LongTimeProcessInformer) this);

        openedFromSimpleSearch = false;

        init();
        fillDialog();
    }

    private static String createDialogTitle(List<Vocable> vocables, String description,
            FumikoDataStructures dataStructures) {
        return VocabularyTrainerUiTools.generateTitleWithVocabularyTestSuccesss(
                vocables, description, dataStructures);
    }

    private void init() {
        initNavigator();
        initKeyBindings();
        initBackgroundChangingButton();
    }

    private void initNavigator() {
        navigator.setShowMethod(vocable -> showVocable(vocable));
        navigator.setDataList(determineVocablesToUse());
    }

    private void showVocable(Vocable vocable) {
        InternalDataRequester requester = dataStructures.getInternalDataRequester();
        InternalAdditionalVocableData data = requester.getInternalDataForVocable(vocable);
        vocableViewer.showVocable(vocable, data);

        listsWithVocableFinderGui.setVocable(vocable);
        vocableToOwnListAdderGui.setVocable(vocable);
        verbsAndAdjectivesFinderGui.setVocable(vocable);

        pack();
    }

    private List<Vocable> determineVocablesToUse() {
        Options options = dataStructures.getOptions();
        if (options.isUseTestOrderForViewingVocables()) {
            VocablesShuffleType type = options.getVocablesShuffleType();
            VocableListShuffler shuffler = new VocableListShuffler(vocables, type, dataStructures);
            shuffler.shuffle();
            return shuffler.getVocables();
        }
        else {
            return vocables;
        }
    }

    private void initKeyBindings() {
        setKeyBindingPageUp(() -> navigator.doClickOnPreviousButton());
        setKeyBindingPageDown(() -> navigator.doClickOnNextButton());

        // bringt es alles nicht ... Hmmmm....
        setKeyBindingLeft(() -> navigator.doClickOnPreviousButton());
        setKeyBindingRight(() -> navigator.doClickOnNextButton());
        setKeyBindingCtrlLeft(() -> navigator.doClickOnPreviousButton());
        setKeyBindingCtrlRight(() -> navigator.doClickOnNextButton());
        setKeyBindingAltLeft(() -> navigator.doClickOnPreviousButton());
        setKeyBindingAltRight(() -> navigator.doClickOnNextButton());

        setKeyBindingF1(() -> navigator.doClickOnPreviousButton());
        setKeyBindingF2(() -> navigator.doClickOnNextButton());
    }

    private void initBackgroundChangingButton() {
        setBackgroundChangingButtonTitle();
        backgroundChangingButton.addActionListener(e -> toggleBackground());
    }

    private void setBackgroundChangingButtonTitle() {
        Options options = dataStructures.getOptions();
        String buttonText = ""
                + "Hintergrund "
                + (options.isColorVocableDependingOnLastSuccessWhenViewingVocable()
                        ? "aus"
                        : "ein")
                + "schalten";
        backgroundChangingButton.setText(buttonText);
    }

    private void toggleBackground() {
        Options options = dataStructures.getOptions();
        boolean onOrOff = options.isColorVocableDependingOnLastSuccessWhenViewingVocable();
        onOrOff = !onOrOff;
        options.setColorVocableDependingOnLastSuccessWhenViewingVocable(onOrOff);
        setBackgroundChangingButtonTitle();

        Vocable vocable = navigator.getActualDataSet();
        showVocable(vocable);
    }

    /** Baut die Gui auf. */
    @Override
    protected void populateDialog() {
        add(createCenterPart(), BorderLayout.CENTER);
        add(createButtonsPart(),  BorderLayout.SOUTH);

        keybindingsForDetailDialog();
        keybindingsForPlaySound();

        /* Versuche die Lücke unter der Einzeldarstellung zu vermeiden: */
        pack();
        SwingUtilities.invokeLater(() -> {
            navigator.doClickOnFirstButton();
            pack();
        });
    }

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

        panel.add(createCenteredNavigatorPanel(), BorderLayout.NORTH);
        panel.add(createVocabularyPart(), BorderLayout.CENTER);

        return panel;
    }

    private Component createCenteredNavigatorPanel() {
        JComponent centeredNavigation = GuiTools.center(navigator.getPanel());
        //GuiTools.createTitle(centeredNavigation);
        return centeredNavigation;
    }

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

        panel.add(vocableViewer.getPanel(), BorderLayout.CENTER);
        panel.add(createHorizontalButtonsPart(), BorderLayout.SOUTH);

        return panel;
    }

    private Component createHorizontalButtonsPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new VerticalLayout(0, VerticalLayout.BOTH));

        Options options = dataStructures.getOptions();
        if (options.isShowDetailBottomButonsInTranslationEvaluationToo()) {
            listsWithVocableFinderGui.appendButtonToPanel(panel);
            vocableToOwnListAdderGui.appendButtonToPanel(panel);
            verbsAndAdjectivesFinderGui.appendButtonsToPanel(panel);
        }
        if (options.isShowDetailsButtonInEinzeldarstellung()) {
            panel.add(createDetailsButton());
        }

        return panel;
    }

    private Component createDetailsButton() {
        JButton button = new JButton("Details anzeigen");
        button.addActionListener(e -> showDetails());
        return button;
    }

    private void showDetails() {
        if (openedFromSimpleSearch) {
            Options options = dataStructures.getOptions();
            if (options.isCloseSingleViewWhenOpeningDetailsAfterSimpleSearch()) {
                closeDialog();
            }
        }

        Vocable vocable = navigator.getActualDataSet();
        VocableWithInternaViewer viewer = new VocableWithInternaViewer(vocable, dataStructures,
                uiObjects, getLocation());
        viewer.setVisible(true);
    }

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


        panel.add(backgroundChangingButton, BorderLayout.WEST);
        panel.add(GuiTools.centerHorizontal(otherViewPanel.getPanel()), BorderLayout.CENTER);
        panel.add(createQuitButton(), BorderLayout.EAST);

        return panel;
    }

    private Component createQuitButton() {
        JButton button = new JButton("Beenden");
        button.addActionListener(e -> quit());
        return button;
    }

    private void quit() {
        closeDialog();
    }

    private void keybindingsForDetailDialog() {
        KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_D, InputEvent.CTRL_DOWN_MASK);
        String actionMapKey = "Strg-D";
        Action action = BindKeysOnRootPane.runnableToAction(() -> showDetails());

        JRootPane rootPane = getRootPane();
        InputMap inputMap = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        inputMap.put(keyStroke, actionMapKey);
        rootPane.getActionMap().put(actionMapKey, action);
    }

    private void keybindingsForPlaySound() {
        KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_F9, 0);
        String actionMapKey = "F9";
        Action action = BindKeysOnRootPane.runnableToAction(() -> vocableViewer.playMp3());

        JRootPane rootPane = getRootPane();
        InputMap inputMap = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        inputMap.put(keyStroke, actionMapKey);
        rootPane.getActionMap().put(actionMapKey, action);
    }

    /** Wird aufgerufen, wenn die Vokabeln in einer anderen Ansicht angezeigt werden. */
    @Override
    public void otherViewOpened() {
        closeDialog();
    }

    /** Wird aufgerufen, wenn der Dialog aus der einfachen Suche geöffnet wird. */
    public void setOpenedFromSimpleSearch() {
        openedFromSimpleSearch = true;
    }

}
