package de.duehl.vocabulary.japanese.ui.dialog.kana.katakanatest;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Point;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.SwingUtilities;

import de.duehl.basics.text.NumberString;
import de.duehl.swing.ui.GuiTools;
import de.duehl.swing.ui.dialogs.base.ModalDialogBase;
import de.duehl.swing.ui.layout.VerticalLayout;
import de.duehl.vocabulary.japanese.data.symbol.Katakana;
import de.duehl.vocabulary.japanese.data.symbol.KanaSubType;
import de.duehl.vocabulary.japanese.logic.symbol.kana.test.data.KatakanaForTestSelectionMethod;

/**
 * Diese Klasse lässt den Benutzer auswählen, ob einige oder alle Katakana und ob die Katakana in
 * der originalen Reihenfolge oder zufällig sortiert abgefragt werden sollen.
 *
 * @version 1.01     2025-02-02
 * @author Christian Dühl
 */

public class KatakanaTestParameterChooser extends ModalDialogBase {

    private static final int MIN_WIDTH = 500;


    /** Die Liste der nicht zuletzt zehn mal richtig abgefragten Katakana. */
    private final List<Katakana> notTenTimesGoodTestedKatakanaList;

    /** Gibt an, ob der Benutzer den Dialog mit OK beendet hat. */
    private boolean applied;

    /* Gui-Elemente: */

    private final JCheckBox useOriginalKatakanaOrderCheckBox;

    private final JRadioButton fiveKatakanaRadioButton;
    private final JRadioButton tenKatakanaRadioButton;
    private final JRadioButton fifteenKatakanaRadioButton;
    private final JRadioButton twenytKatakanaRadioButton;
    private final JRadioButton thirtyKatakanaRadioButton;
    private final JRadioButton fiftyKatakanaRadioButton;
    private final JRadioButton allKatakanaRadioButton;
    private final JRadioButton notTenTimesGoodTestedKatakanaRadioButton;
    private final JRadioButton lastThirtyKatakanaRadioButton;
    private final JRadioButton lastTwentyKatakanaRadioButton;
    private final JRadioButton lastFifteenKatakanaRadioButton;
    private final JRadioButton lastTenKatakanaRadioButton;
    private final JRadioButton lastFiveKatakanaRadioButton;

    private final List<JCheckBox> subTypCheckboxes;
    private final Map<JCheckBox, KanaSubType> subTypeCheckBoxToType;

    /** Der Button zum positiven Abschicken des Dialogs. */
    private final JButton okButton;

    /** Die Anzahl der abzufragenden Katakana. */
    private int numberOfKatakanaToTest;

    /** Gibt an ob die abzufragenden Katakana in der originalen Reihenfolge belassen werden sollen. */
    private boolean useOriginalKatakanaOrder;

    /** Die Art wie Katakana für die Abfrage ausgewählt werden. */
    private KatakanaForTestSelectionMethod selectionMethod;

    /** Die Liste an Katakana, aus denen ausgewählt wird. */
    private List<Katakana> katakanaList;

    /**
     * Konstruktor.
     *
     * @param options
     *            Die Programmoptionen.
     * @param notTenTimesGoodTestedKatakanaList
     *            Die Liste der nicht zuletzt zehn mal richtig abgefragten Katakana.
     * @param parentLocation
     *            Position des Rahmens der Oberfläche, vor der dieser Dialog erzeugt wird.
     * @param programImage
     *            Anzuzeigendes ProgrammIcon.
     */
    public KatakanaTestParameterChooser(List<Katakana> notTenTimesGoodTestedKatakanaList,
            Point parentLocation, Image programImage) {
        super(parentLocation, programImage, "Die Parameter für den Katakana-Test auswählen");

        this.notTenTimesGoodTestedKatakanaList = notTenTimesGoodTestedKatakanaList;

        useOriginalKatakanaOrderCheckBox = new JCheckBox("in Originalreihenfolge");

        fiveKatakanaRadioButton = new JRadioButton("5 Katakana");
        tenKatakanaRadioButton = new JRadioButton("10 Katakana");
        fifteenKatakanaRadioButton = new JRadioButton("15 Katakana");
        twenytKatakanaRadioButton = new JRadioButton("20 Katakana");
        thirtyKatakanaRadioButton = new JRadioButton("30 Katakana");
        fiftyKatakanaRadioButton = new JRadioButton("50 Katakana");
        allKatakanaRadioButton = new JRadioButton("Alle Katakana ("
                + NumberString.taupu(Katakana.getNumberOfKnownKatakana()) + ")");
        notTenTimesGoodTestedKatakanaRadioButton = new JRadioButton(
                "nicht zuletzt zehn mal richtig abgefragte Katakana");
        lastThirtyKatakanaRadioButton = new JRadioButton("die letzten 30 Katakana");
        lastTwentyKatakanaRadioButton = new JRadioButton("die letzten 20 Katakana");
        lastFifteenKatakanaRadioButton = new JRadioButton("die letzten 15 Katakana");
        lastTenKatakanaRadioButton = new JRadioButton("die letzten 10 Katakana");
        lastFiveKatakanaRadioButton = new JRadioButton("die letzten 5 Katakana");

        subTypCheckboxes = new ArrayList<>();
        subTypeCheckBoxToType = new HashMap<>();

        okButton = new JButton();

        selectionMethod = KatakanaForTestSelectionMethod.UNKNOWN;
        applied = false;

        init();
        fillDialog();
    }

    private void init() {
        initRadioButtons();
        initCheckBoxes();
        initSubTypeCheckBoxes();
        addSubTypeCheckBoxesActionListener();
        subTypesSelectionChanged(); // da nicht alle ausgewählt sind!
    }

    private void initRadioButtons() {
        ButtonGroup group = new ButtonGroup();

        group.add(fiveKatakanaRadioButton);
        group.add(tenKatakanaRadioButton);
        group.add(fifteenKatakanaRadioButton);
        group.add(twenytKatakanaRadioButton);
        group.add(thirtyKatakanaRadioButton);
        group.add(fiftyKatakanaRadioButton);
        group.add(allKatakanaRadioButton);
        group.add(notTenTimesGoodTestedKatakanaRadioButton);
        group.add(lastThirtyKatakanaRadioButton);
        group.add(lastTwentyKatakanaRadioButton);
        group.add(lastFifteenKatakanaRadioButton);
        group.add(lastTenKatakanaRadioButton);
        group.add(lastFiveKatakanaRadioButton);

        allKatakanaRadioButton.setSelected(true);
    }

    private void initCheckBoxes() {
        useOriginalKatakanaOrderCheckBox.setSelected(false);
    }

    private void initSubTypeCheckBoxes() {
        for (KanaSubType type : KanaSubType.values()) {
            JCheckBox subTypeCheckBox = new JCheckBox(type.getDescription());
            subTypeCheckBox.setSelected(type == KanaSubType.STANDARD
                    || type == KanaSubType.WITH_DAKUTEN
                    || type == KanaSubType.WITH_HANDAKUTEN
                    || type == KanaSubType.COMPOUND
                    || type == KanaSubType.COMPOUND_WITH_DAKUTEN
                    || type == KanaSubType.COMPOUND_WITH_HANDAKUTEN
                    );
            subTypCheckboxes.add(subTypeCheckBox);
            subTypeCheckBoxToType.put(subTypeCheckBox, type);
        }
    }

    private void addSubTypeCheckBoxesActionListener() {
        for (JCheckBox subTypeCheckBox : subTypCheckboxes) {
            subTypeCheckBox.addActionListener(e -> subTypesSelectionChanged());
        }
    }

    private void subTypesSelectionChanged() {
        // TODO Auto-generated method stub

        List<Katakana> katakanaListWithSubtypes = createKatakanaListWithSelecetdSubtypes();

        int numberOfAllKatakana = katakanaListWithSubtypes.size();
        allKatakanaRadioButton.setText("Alle Katakana (" + NumberString.taupu(numberOfAllKatakana) + ")");

        int numberOfNotTenTimesGoodTestedKanji = notTenTimesGoodTestedKatakanaList.size();
        notTenTimesGoodTestedKatakanaRadioButton.setText(
                "nicht zuletzt zehn mal richtig abgefragte Katakana" + " ("
                        + numberOfNotTenTimesGoodTestedKanji + ")");
        notTenTimesGoodTestedKatakanaRadioButton.setEnabled(
                !notTenTimesGoodTestedKatakanaList.isEmpty());
        // Berücksichtigt noch nicht ob die Katakana zur Unterart passen!
        // Das ist aber Absicht.

        handleRadioButton(fiveKatakanaRadioButton, 5, numberOfAllKatakana);
        handleRadioButton(tenKatakanaRadioButton, 10, numberOfAllKatakana);
        handleRadioButton(fifteenKatakanaRadioButton, 15, numberOfAllKatakana);
        handleRadioButton(twenytKatakanaRadioButton, 20, numberOfAllKatakana);
        handleRadioButton(thirtyKatakanaRadioButton, 30, numberOfAllKatakana);
        handleRadioButton(fiftyKatakanaRadioButton, 50, numberOfAllKatakana);
        handleRadioButton(lastThirtyKatakanaRadioButton, 30, numberOfAllKatakana);
        handleRadioButton(lastTwentyKatakanaRadioButton, 20, numberOfAllKatakana);
        handleRadioButton(lastFifteenKatakanaRadioButton, 15, numberOfAllKatakana);
        handleRadioButton(lastTenKatakanaRadioButton, 10, numberOfAllKatakana);
        handleRadioButton(lastFiveKatakanaRadioButton, 5, numberOfAllKatakana);
    }

    private void handleRadioButton(JRadioButton katakanaRadioButton, int numberOnRadioButton,
            int numberOfAllKatakana) {
        katakanaRadioButton.setEnabled(numberOfAllKatakana >= numberOnRadioButton);
        if (numberOfAllKatakana < numberOnRadioButton && katakanaRadioButton.isSelected()) {
            katakanaRadioButton.setSelected(false);
        }
    }

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

        SwingUtilities.invokeLater(() -> okButton.requestFocus());
    }

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

        panel.add(createKatakanaSubTypeSelectionPart(), BorderLayout.NORTH);
        panel.add(createNumberOfKatakanaPart(), BorderLayout.CENTER);
        panel.add(createSortKatakanaPart(), BorderLayout.SOUTH);

        return panel;
    }

    private Component createKatakanaSubTypeSelectionPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new VerticalLayout(0, VerticalLayout.BOTH));
        GuiTools.createTitle("Unterarten", panel);

        for (JCheckBox subTypeCheckBox : subTypCheckboxes) {
            panel.add(subTypeCheckBox);
        }

        return panel;
    }

    private Component createNumberOfKatakanaPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new VerticalLayout(0, VerticalLayout.BOTH));
        //panel.setLayout(new GridLayout(1, 0, 0, 0));

        panel.add(createNumberOfRandomSelectedKatakanaPart());
        panel.add(createNumberOfLastXKatakanaPart());
        panel.add(createNumberOfAllKatakanaPart());
        panel.add(createNumberOfNotTenTimesGoodTestedKatakanaPart());
        panel.add(createDummyMinWidthLabelPart());

        return panel;
    }

    private Component createNumberOfRandomSelectedKatakanaPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(0, 3, 5, 5));
        GuiTools.createTitle("Für die Abfrage der Katakana die folgende Anzahl zufällig ausgewähen",
                panel);

        panel.add(fiveKatakanaRadioButton);
        panel.add(tenKatakanaRadioButton);
        panel.add(fifteenKatakanaRadioButton);
        panel.add(twenytKatakanaRadioButton);
        panel.add(thirtyKatakanaRadioButton);
        panel.add(fiftyKatakanaRadioButton);

        return panel;
    }

    private Component createNumberOfLastXKatakanaPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(0, 3, 5, 5));
        GuiTools.createTitle("Für die Abfrage der Katakana die folgende Anzahl der zuletzt "
                + "hinzugefügten ausgewähen", panel);

        panel.add(lastThirtyKatakanaRadioButton);
        panel.add(lastTwentyKatakanaRadioButton);
        panel.add(lastFifteenKatakanaRadioButton);
        panel.add(lastTenKatakanaRadioButton);
        panel.add(lastFiveKatakanaRadioButton);

        return panel;
    }

    private Component createNumberOfAllKatakanaPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(0, 3, 5, 5));
        GuiTools.createTitle("Alle Katakana abfragen", panel);

        panel.add(allKatakanaRadioButton);

        return panel;
    }

    private Component createNumberOfNotTenTimesGoodTestedKatakanaPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(0, 3, 5, 5));
        GuiTools.createTitle("Nicht zehn mal richtig beantwortete Katakana abfragen", panel);

        panel.add(notTenTimesGoodTestedKatakanaRadioButton);

        return panel;
    }

    private Component createDummyMinWidthLabelPart() {
        JLabel label = new JLabel("");
        label.setPreferredSize(new Dimension(MIN_WIDTH, 0));
        return label;
    }

    private Component createSortKatakanaPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        GuiTools.createTitle("Sortierung", panel);

        panel.add(useOriginalKatakanaOrderCheckBox, BorderLayout.CENTER);

        return panel;
    }

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

        panel.add(createQuitButton(), BorderLayout.WEST);
        panel.add(createOkButton(), BorderLayout.EAST);

        return panel;
    }

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

    private void quit() {
        closeDialog();
    }

    private Component createOkButton() {
        okButton.setText("   Abfrage starten   ");
        GuiTools.biggerFont(okButton, 5);
        okButton.addActionListener(e -> apply());
        return okButton;
    }

    private List<Katakana> createKatakanaListWithSelecetdSubtypes() {
        List<KanaSubType> selectedSubTypes = new ArrayList<>();
        for (JCheckBox subTypeCheckBox : subTypCheckboxes) {
            if (subTypeCheckBox.isSelected()) {
                if (!subTypeCheckBoxToType.containsKey(subTypeCheckBox)) {
                    throw new RuntimeException("Zur subTypeCheckBox '" + subTypeCheckBox.getText()
                            + "' ist der Typ nicht bekannt!");
                }
                KanaSubType type = subTypeCheckBoxToType.get(subTypeCheckBox);
                if (!selectedSubTypes.contains(type)) {
                    selectedSubTypes.add(type);
                }
            }
        }

        List<Katakana> katakanaListWithSubtypes = new ArrayList<>();
        for (Katakana katakana : Katakana.values()) {
            KanaSubType type = katakana.getSubType();
            if (selectedSubTypes.contains(type)) {
                katakanaListWithSubtypes.add(katakana);
            }
        }

        return katakanaListWithSubtypes;
    }

    private void apply() {
        katakanaList = createKatakanaListWithSelecetdSubtypes();

        if (fiveKatakanaRadioButton.isSelected()) {
            numberOfKatakanaToTest = 5;
            selectionMethod = KatakanaForTestSelectionMethod.RANDOM_BY_NUMBER;
        }
        else if (tenKatakanaRadioButton.isSelected()) {
            numberOfKatakanaToTest = 10;
            selectionMethod = KatakanaForTestSelectionMethod.RANDOM_BY_NUMBER;
        }
        else if (fifteenKatakanaRadioButton.isSelected()) {
            numberOfKatakanaToTest = 15;
            selectionMethod = KatakanaForTestSelectionMethod.RANDOM_BY_NUMBER;
        }
        else if (twenytKatakanaRadioButton.isSelected()) {
            numberOfKatakanaToTest = 20;
            selectionMethod = KatakanaForTestSelectionMethod.RANDOM_BY_NUMBER;
        }
        else if (thirtyKatakanaRadioButton.isSelected()) {
            numberOfKatakanaToTest = 30;
            selectionMethod = KatakanaForTestSelectionMethod.RANDOM_BY_NUMBER;
        }
        else if (fiftyKatakanaRadioButton.isSelected()) {
            numberOfKatakanaToTest = 50;
            selectionMethod = KatakanaForTestSelectionMethod.RANDOM_BY_NUMBER;
        }
        else if (allKatakanaRadioButton.isSelected()) {
            numberOfKatakanaToTest = Katakana.getNumberOfKnownKatakana(); // eigentlich unnötig
            selectionMethod = KatakanaForTestSelectionMethod.ALL;
        }
        else if (notTenTimesGoodTestedKatakanaRadioButton.isSelected()) {
            numberOfKatakanaToTest = notTenTimesGoodTestedKatakanaList.size();
            selectionMethod = KatakanaForTestSelectionMethod.NOT_TEN_TIMES_GOOD_TESTED;
        }
        else if (lastThirtyKatakanaRadioButton.isSelected()) {
            numberOfKatakanaToTest = 30;
            selectionMethod = KatakanaForTestSelectionMethod.LAST_N;
        }
        else if (lastTwentyKatakanaRadioButton.isSelected()) {
            numberOfKatakanaToTest = 20;
            selectionMethod = KatakanaForTestSelectionMethod.LAST_N;
        }
        else if (lastFifteenKatakanaRadioButton.isSelected()) {
            numberOfKatakanaToTest = 15;
            selectionMethod = KatakanaForTestSelectionMethod.LAST_N;
        }
        else if (lastTenKatakanaRadioButton.isSelected()) {
            numberOfKatakanaToTest = 10;
            selectionMethod = KatakanaForTestSelectionMethod.LAST_N;
        }
        else if (lastFiveKatakanaRadioButton.isSelected()) {
            numberOfKatakanaToTest = 5;
            selectionMethod = KatakanaForTestSelectionMethod.LAST_N;
        }
        else {
            numberOfKatakanaToTest = -1;
            selectionMethod = KatakanaForTestSelectionMethod.UNKNOWN;

            String title = "Keine Anzahl an Katakana ausgewählt";
            String message = "Sie haben die Anzahl der abzufragenden Katakana nicht ausgewählt.";
            GuiTools.informUser(getWindowAsComponent(), title, message);
            return;
        }

        useOriginalKatakanaOrder = useOriginalKatakanaOrderCheckBox.isSelected();

        applied = true;
        quit();
    }

    /** Gibt an, ob der Benutzer den Dialog mit OK beendet hat. */
    public boolean isApplied() {
        return applied;
    }

    /** Die Getter für die an Katakana, aus denen ausgewählt wird. */
    public List<Katakana> getKatakanaList() {
        return katakanaList;
    }

    /** Getter für die Anzahl der abzufragenden Katakana. */
    public int getNumberOfKatakanaToTest() {
        return numberOfKatakanaToTest;
    }

    /** Gibt an ob die abzufragenden Katakana in der originalen Reihenfolge belassen werden sollen. */
    public boolean isUseOriginalKatakanaOrder() {
        return useOriginalKatakanaOrder;
    }

    /** Getter für die Art wie Katakana für die Abfrage ausgewählt werden. */
    public KatakanaForTestSelectionMethod getSelectionMethod() {
        return selectionMethod;
    }

}
