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

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.Hiragana;
import de.duehl.vocabulary.japanese.data.symbol.KanaSubType;
import de.duehl.vocabulary.japanese.logic.symbol.kana.test.data.HiraganaForTestSelectionMethod;

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

public class HiraganaTestParameterChooser extends ModalDialogBase {

    private static final int MIN_WIDTH = 500;


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

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

    /* Gui-Elemente: */

    private final JCheckBox useOriginalHiraganaOrderCheckBox;

    private final JRadioButton fiveHiraganaRadioButton;
    private final JRadioButton tenHiraganaRadioButton;
    private final JRadioButton fifteenHiraganaRadioButton;
    private final JRadioButton twenytHiraganaRadioButton;
    private final JRadioButton thirtyHiraganaRadioButton;
    private final JRadioButton fiftyHiraganaRadioButton;
    private final JRadioButton allHiraganaRadioButton;
    private final JRadioButton notTenTimesGoodTestedHiraganaRadioButton;
    private final JRadioButton lastThirtyHiraganaRadioButton;
    private final JRadioButton lastTwentyHiraganaRadioButton;
    private final JRadioButton lastFifteenHiraganaRadioButton;
    private final JRadioButton lastTenHiraganaRadioButton;
    private final JRadioButton lastFiveHiraganaRadioButton;

    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 Hiragana. */
    private int numberOfHiraganaToTest;

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

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

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

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

        this.notTenTimesGoodTestedHiraganaList = notTenTimesGoodTestedHiraganaList;

        useOriginalHiraganaOrderCheckBox = new JCheckBox("in Originalreihenfolge");

        fiveHiraganaRadioButton = new JRadioButton("5 Hiragana");
        tenHiraganaRadioButton = new JRadioButton("10 Hiragana");
        fifteenHiraganaRadioButton = new JRadioButton("15 Hiragana");
        twenytHiraganaRadioButton = new JRadioButton("20 Hiragana");
        thirtyHiraganaRadioButton = new JRadioButton("30 Hiragana");
        fiftyHiraganaRadioButton = new JRadioButton("50 Hiragana");
        allHiraganaRadioButton = new JRadioButton("Alle Hiragana ("
                + NumberString.taupu(Hiragana.getNumberOfKnownHiragana()) + ")");
        notTenTimesGoodTestedHiraganaRadioButton = new JRadioButton(
                "nicht zuletzt zehn mal richtig abgefragte Hiragana");
        lastThirtyHiraganaRadioButton = new JRadioButton("die letzten 30 Hiragana");
        lastTwentyHiraganaRadioButton = new JRadioButton("die letzten 20 Hiragana");
        lastFifteenHiraganaRadioButton = new JRadioButton("die letzten 15 Hiragana");
        lastTenHiraganaRadioButton = new JRadioButton("die letzten 10 Hiragana");
        lastFiveHiraganaRadioButton = new JRadioButton("die letzten 5 Hiragana");

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

        okButton = new JButton();

        selectionMethod = HiraganaForTestSelectionMethod.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(fiveHiraganaRadioButton);
        group.add(tenHiraganaRadioButton);
        group.add(fifteenHiraganaRadioButton);
        group.add(twenytHiraganaRadioButton);
        group.add(thirtyHiraganaRadioButton);
        group.add(fiftyHiraganaRadioButton);
        group.add(allHiraganaRadioButton);
        group.add(notTenTimesGoodTestedHiraganaRadioButton);
        group.add(lastThirtyHiraganaRadioButton);
        group.add(lastTwentyHiraganaRadioButton);
        group.add(lastFifteenHiraganaRadioButton);
        group.add(lastTenHiraganaRadioButton);
        group.add(lastFiveHiraganaRadioButton);

        allHiraganaRadioButton.setSelected(true);
    }

    private void initCheckBoxes() {
        useOriginalHiraganaOrderCheckBox.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<Hiragana> hiraganaListWithSubtypes = createHiraganaListWithSelecetdSubtypes();

        int numberOfAllHiragana = hiraganaListWithSubtypes.size();
        allHiraganaRadioButton.setText("Alle Hiragana (" + NumberString.taupu(numberOfAllHiragana) + ")");

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

        handleRadioButton(fiveHiraganaRadioButton, 5, numberOfAllHiragana);
        handleRadioButton(tenHiraganaRadioButton, 10, numberOfAllHiragana);
        handleRadioButton(fifteenHiraganaRadioButton, 15, numberOfAllHiragana);
        handleRadioButton(twenytHiraganaRadioButton, 20, numberOfAllHiragana);
        handleRadioButton(thirtyHiraganaRadioButton, 30, numberOfAllHiragana);
        handleRadioButton(fiftyHiraganaRadioButton, 50, numberOfAllHiragana);
        handleRadioButton(lastThirtyHiraganaRadioButton, 30, numberOfAllHiragana);
        handleRadioButton(lastTwentyHiraganaRadioButton, 20, numberOfAllHiragana);
        handleRadioButton(lastFifteenHiraganaRadioButton, 15, numberOfAllHiragana);
        handleRadioButton(lastTenHiraganaRadioButton, 10, numberOfAllHiragana);
        handleRadioButton(lastFiveHiraganaRadioButton, 5, numberOfAllHiragana);
    }

    private void handleRadioButton(JRadioButton hiraganaRadioButton, int numberOnRadioButton,
            int numberOfAllHiragana) {
        hiraganaRadioButton.setEnabled(numberOfAllHiragana >= numberOnRadioButton);
        if (numberOfAllHiragana < numberOnRadioButton && hiraganaRadioButton.isSelected()) {
            hiraganaRadioButton.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(createHiraganaSubTypeSelectionPart(), BorderLayout.NORTH);
        panel.add(createNumberOfHiraganaPart(), BorderLayout.CENTER);
        panel.add(createSortHiraganaPart(), BorderLayout.SOUTH);

        return panel;
    }

    private Component createHiraganaSubTypeSelectionPart() {
        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 createNumberOfHiraganaPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new VerticalLayout(0, VerticalLayout.BOTH));
        //panel.setLayout(new GridLayout(1, 0, 0, 0));

        panel.add(createNumberOfRandomSelectedHiraganaPart());
        panel.add(createNumberOfLastXHiraganaPart());
        panel.add(createNumberOfAllHiraganaPart());
        panel.add(createNumberOfNotTenTimesGoodTestedHiraganaPart());
        panel.add(createDummyMinWidthLabelPart());

        return panel;
    }

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

        panel.add(fiveHiraganaRadioButton);
        panel.add(tenHiraganaRadioButton);
        panel.add(fifteenHiraganaRadioButton);
        panel.add(twenytHiraganaRadioButton);
        panel.add(thirtyHiraganaRadioButton);
        panel.add(fiftyHiraganaRadioButton);

        return panel;
    }

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

        panel.add(lastThirtyHiraganaRadioButton);
        panel.add(lastTwentyHiraganaRadioButton);
        panel.add(lastFifteenHiraganaRadioButton);
        panel.add(lastTenHiraganaRadioButton);
        panel.add(lastFiveHiraganaRadioButton);

        return panel;
    }

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

        panel.add(allHiraganaRadioButton);

        return panel;
    }

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

        panel.add(notTenTimesGoodTestedHiraganaRadioButton);

        return panel;
    }

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

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

        panel.add(useOriginalHiraganaOrderCheckBox, 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<Hiragana> createHiraganaListWithSelecetdSubtypes() {
        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<Hiragana> hiraganaListWithSubtypes = new ArrayList<>();
        for (Hiragana hiragana : Hiragana.values()) {
            KanaSubType type = hiragana.getSubType();
            if (selectedSubTypes.contains(type)) {
                hiraganaListWithSubtypes.add(hiragana);
            }
        }

        return hiraganaListWithSubtypes;
    }

    private void apply() {
        hiraganaList = createHiraganaListWithSelecetdSubtypes();

        if (fiveHiraganaRadioButton.isSelected()) {
            numberOfHiraganaToTest = 5;
            selectionMethod = HiraganaForTestSelectionMethod.RANDOM_BY_NUMBER;
        }
        else if (tenHiraganaRadioButton.isSelected()) {
            numberOfHiraganaToTest = 10;
            selectionMethod = HiraganaForTestSelectionMethod.RANDOM_BY_NUMBER;
        }
        else if (fifteenHiraganaRadioButton.isSelected()) {
            numberOfHiraganaToTest = 15;
            selectionMethod = HiraganaForTestSelectionMethod.RANDOM_BY_NUMBER;
        }
        else if (twenytHiraganaRadioButton.isSelected()) {
            numberOfHiraganaToTest = 20;
            selectionMethod = HiraganaForTestSelectionMethod.RANDOM_BY_NUMBER;
        }
        else if (thirtyHiraganaRadioButton.isSelected()) {
            numberOfHiraganaToTest = 30;
            selectionMethod = HiraganaForTestSelectionMethod.RANDOM_BY_NUMBER;
        }
        else if (fiftyHiraganaRadioButton.isSelected()) {
            numberOfHiraganaToTest = 50;
            selectionMethod = HiraganaForTestSelectionMethod.RANDOM_BY_NUMBER;
        }
        else if (allHiraganaRadioButton.isSelected()) {
            numberOfHiraganaToTest = Hiragana.getNumberOfKnownHiragana(); // eigentlich unnötig
            selectionMethod = HiraganaForTestSelectionMethod.ALL;
        }
        else if (notTenTimesGoodTestedHiraganaRadioButton.isSelected()) {
            numberOfHiraganaToTest = notTenTimesGoodTestedHiraganaList.size();
            selectionMethod = HiraganaForTestSelectionMethod.NOT_TEN_TIMES_GOOD_TESTED;
        }
        else if (lastThirtyHiraganaRadioButton.isSelected()) {
            numberOfHiraganaToTest = 30;
            selectionMethod = HiraganaForTestSelectionMethod.LAST_N;
        }
        else if (lastTwentyHiraganaRadioButton.isSelected()) {
            numberOfHiraganaToTest = 20;
            selectionMethod = HiraganaForTestSelectionMethod.LAST_N;
        }
        else if (lastFifteenHiraganaRadioButton.isSelected()) {
            numberOfHiraganaToTest = 15;
            selectionMethod = HiraganaForTestSelectionMethod.LAST_N;
        }
        else if (lastTenHiraganaRadioButton.isSelected()) {
            numberOfHiraganaToTest = 10;
            selectionMethod = HiraganaForTestSelectionMethod.LAST_N;
        }
        else if (lastFiveHiraganaRadioButton.isSelected()) {
            numberOfHiraganaToTest = 5;
            selectionMethod = HiraganaForTestSelectionMethod.LAST_N;
        }
        else {
            numberOfHiraganaToTest = -1;
            selectionMethod = HiraganaForTestSelectionMethod.UNKNOWN;

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

        useOriginalHiraganaOrder = useOriginalHiraganaOrderCheckBox.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 Hiragana, aus denen ausgewählt wird. */
    public List<Hiragana> getHiraganaList() {
        return hiraganaList;
    }

    /** Getter für die Anzahl der abzufragenden Hiragana. */
    public int getNumberOfHiraganaToTest() {
        return numberOfHiraganaToTest;
    }

    /** Gibt an ob die abzufragenden Hiragana in der originalen Reihenfolge belassen werden sollen. */
    public boolean isUseOriginalHiraganaOrder() {
        return useOriginalHiraganaOrder;
    }

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

}
