package de.duehl.vocabulary.japanese.ui.dialog.kanji.table;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Point;
import java.util.Comparator;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.table.TableRowSorter;

import de.duehl.basics.text.NumberString;
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.tables.ButtonColumn;
import de.duehl.vocabulary.japanese.common.persistence.Options;
import de.duehl.vocabulary.japanese.data.FumikoDataStructures;
import de.duehl.vocabulary.japanese.data.symbol.Kanji;
import de.duehl.vocabulary.japanese.ui.data.FumikoUiObjects;
import de.duehl.vocabulary.japanese.ui.dialog.kanji.detail.KanjiDetailFrame;
import de.duehl.vocabulary.japanese.ui.dialog.kanji.table.components.AllVocablesWithKanjiShower;
import de.duehl.vocabulary.japanese.ui.dialog.table.kanji.KanjiTableColumnModel;
import de.duehl.vocabulary.japanese.ui.dialog.table.kanji.KanjiTableModel;
import de.duehl.vocabulary.japanese.ui.dialog.table.kanji.KanjiTableRenderer;

import static de.duehl.vocabulary.japanese.ui.dialog.vocables.lister.VocabularyListerDialog.createLastTenTestResultsSorter;

/**
 * Diese Klasse zeigt die (bislang eingepflegten) Kanji in Form einer Liste an.
 *
 * @version 1.01     2026-01-01
 * @author Christian Dühl
 */

public class KanjiTableDialog extends NonModalFrameDialogBase {

    private static final Dimension DIALOG_DIMENSION = new Dimension(1500, 1000);

    private static final Color TABLE_FOREGROUND = new Color(0, 0, 255);
    private static final Color TABLE_BACKGROUND = new Color(240, 240, 255);

    private static final float DEFAULT_FONT_SIZE = 15f;


    /** Die Liste mit den bekannten Kanji. */
    private final List<Kanji> kanjiList;

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

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

    /** Die Oberfläche, welche diese Klasse aufruft, auf der man eine GlassPane anzeigen kann. */
    private final LongTimeProcessInformer informer;

    /** Die Tabelle. */
    private final JTable table;

    /** Das Modell der anzuzeigenden Tabelle. */
    private final KanjiTableModel tableModel;

    /** Der Renderer der Tabelle. */
    private final KanjiTableRenderer tableRenderer;

    /** Die ScrollPane um die Vokabeln. */
    private JScrollPane scrollPane;

    /** Button um die Schriftgröße der Tabelle zu erhöhen. */
    private final JButton increaseFontSizeButton;

    /** Button um die Schriftgröße der Tabelle zu verringern. */
    private final JButton standardFontSizeButton;

    /** Button um die Schriftgröße der Tabelle zu verringern. */
    private final JButton decreaseFontSizeButton;

    /**
     * Konstruktor für die Anzeige aller bekannten Kanji.
     *
     * @param dataStructures
     *            Die Datenstrukturen des Vokabeltrainers.
     * @param uiObjects
     *            Die häufig verwendeten Funktionen der grafischen Oberfläche des Vokabeltrainers.
     * @param informer
     *            Die Oberfläche, welche diese Klasse aufruft, auf der man eine GlassPane anzeigen
     *            kann.
     * @param parentLocation
     *            Position des Rahmens der Oberfläche, vor der dieser Dialog erzeugt wird.
     */
    public KanjiTableDialog(FumikoDataStructures dataStructures, FumikoUiObjects uiObjects,
            LongTimeProcessInformer informer, Point parentLocation) {
        this(Kanji.getAllKanjiAsList(), dataStructures, uiObjects, informer,
                createDialogTitle(Kanji.getNumberOfKnownKanji()), parentLocation);
    }

    /**
     * Konstruktor für eine bestimmte Kanji-Menge.
     *
     * @param kanjiList
     *            Die Liste mit den bekannten Kanji.
     * @param dataStructures
     *            Die Datenstrukturen des Vokabeltrainers.
     * @param uiObjects
     *            Die häufig verwendeten Funktionen der grafischen Oberfläche des Vokabeltrainers.
     * @param informer
     *            Die Oberfläche, welche diese Klasse aufruft, auf der man eine GlassPane anzeigen
     *            kann.
     * @param title
     *            Der Titel des Dialogs.
     * @param parentLocation
     *            Position des Rahmens der Oberfläche, vor der dieser Dialog erzeugt wird.
     */
    public KanjiTableDialog(List<Kanji> kanjiList, FumikoDataStructures dataStructures,
            FumikoUiObjects uiObjects, LongTimeProcessInformer informer, String title,
            Point parentLocation) {
        super(parentLocation, uiObjects.getProgramImage(), title, DIALOG_DIMENSION);
        addEscapeBehaviour();

        this.kanjiList = kanjiList;
        this.dataStructures = dataStructures;
        this.uiObjects = uiObjects;
        this.informer = informer;

        table = new JTable();
        tableModel = new KanjiTableModel(kanjiList, dataStructures);
        tableRenderer = new KanjiTableRenderer(TABLE_FOREGROUND, TABLE_BACKGROUND);
        increaseFontSizeButton = new JButton();
        standardFontSizeButton = new JButton();
        decreaseFontSizeButton = new JButton();

        init();
        fillDialog();
    }

    private static String createDialogTitle(int size) {
        return "Liste mit den " + NumberString.taupu(size)
                + " bislang erfassten Kanji.";
    }

    private void init() {
        initTable();
        initScrollPane();
    }

    private void initTable() {
        initTableModel();
        initTableColumnModel();
        initTableRenderer();
        setTableSelectionMode();
        setTableRowHight();
        switchReorderingOfTableColumnsOff();
        initTableButtonEditorAndRenderer();
        initTableSorter();
    }

    private void initTableModel() {
        table.setModel(tableModel);
    }

    private void initTableColumnModel() {
        table.setColumnModel(new KanjiTableColumnModel(dataStructures.getOptions()));
    }

    private void initTableRenderer() {
        tableRenderer.setFontSize(DEFAULT_FONT_SIZE);
        table.setDefaultRenderer(Object.class, tableRenderer);
    }

    private void setTableSelectionMode() {
        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        //table.getSelectionModel().addListSelectionListener(createSelectionListener());
    }

    private void setTableRowHight() {
        tableRenderer.initRowHeightOfTable(table);
    }

    private void switchReorderingOfTableColumnsOff() {
        table.getTableHeader().setReorderingAllowed(false); // verschieben der Spalten verhindern
    }

    private void initTableButtonEditorAndRenderer() {
        int firstButtonIndex = 9;
        Options options = dataStructures.getOptions();
        if (options.isShowKanjiNumberInMyHandwrittenKanjiNotebooks()) {
            ++firstButtonIndex;
        }
        new ButtonColumn(table, row -> reactOnShowKanjiVocablesButtonClick(row), firstButtonIndex);

        int secondButtonIndex = 16;
        if (options.isShowKanjiNumberInMyHandwrittenKanjiNotebooks()) {
            ++secondButtonIndex;
        }
        new ButtonColumn(table, row -> reactOnShowKanjiDetailsButtonClick(row), secondButtonIndex);
    }

    private void reactOnShowKanjiVocablesButtonClick(int row) {
        Kanji kanji = kanjiList.get(row);
        AllVocablesWithKanjiShower vocablesShower = new AllVocablesWithKanjiShower(
                dataStructures, uiObjects, getLocation(), informer);
        vocablesShower.showKanji(kanji);
    }

    private void reactOnShowKanjiDetailsButtonClick(int row) {
        Kanji kanji = kanjiList.get(row);
        KanjiDetailFrame dialog = new KanjiDetailFrame(kanji, dataStructures, uiObjects, informer,
                getParentLocation());
        dialog.setVisible(true);
    }

    private void initTableSorter() {
        TableRowSorter<KanjiTableModel> sorter = new TableRowSorter<>(tableModel);

        /*
         * Die letzten zehn Ergebnisse werden leider alphanumerisch sortiert, das ist nicht so
         * schön. Daher mache ich es so:
         */
        Comparator<String> lastTenTestResultsSorter = createLastTenTestResultsSorter();

        int indexOfLastTen = 15;
        Options options = dataStructures.getOptions();
        if (options.isShowKanjiNumberInMyHandwrittenKanjiNotebooks()) {
            ++indexOfLastTen;
        }
        sorter.setComparator(indexOfLastTen, lastTenTestResultsSorter);

        table.setRowSorter(sorter);
    }

    private void initScrollPane() {
        scrollPane = GuiTools.createScrollPane(table);
    }

    /** Baut die Gui auf. */
    @Override
    protected void populateDialog() {
        initElements();

        add(createCenterPart(), BorderLayout.CENTER);
        add(createButtonsPart(),  BorderLayout.SOUTH);

        GuiTools.scrollScrollbarToMinimumLater(scrollPane);
    }

    private void initElements() {
        initIncreaseFontSizeButton();
        initStandardFontSizeButton();
        initDecreaseFontSizeButton();
    }

    private void initIncreaseFontSizeButton() {
        increaseFontSizeButton.setText("+");
        increaseFontSizeButton.addActionListener(e -> increaseFontSize());
    }

    private void increaseFontSize() {
        tableRenderer.increaseFontSize();
        tableRenderer.initRowHeightOfTable(table);
        table.repaint();
    }

    private void initStandardFontSizeButton() {
        String text = "default size (" + NumberString.twoDecimalPlaces(DEFAULT_FONT_SIZE) + ")";
        standardFontSizeButton.setText(text);
        standardFontSizeButton.addActionListener(e -> standardFontSize());
    }

    private void standardFontSize() {
        tableRenderer.setFontSize(DEFAULT_FONT_SIZE);
        tableRenderer.initRowHeightOfTable(table);
        table.repaint();
    }

    private void initDecreaseFontSizeButton() {
        decreaseFontSizeButton.setText("-");
        decreaseFontSizeButton.addActionListener(e -> decreaseFontSize());
    }

    private void decreaseFontSize() {
        tableRenderer.decreaseFontSize();
        tableRenderer.initRowHeightOfTable(table);
        table.repaint();
    }

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

        panel.add(scrollPane, BorderLayout.CENTER);

        return panel;
    }

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

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

        return panel;
    }

    private Component createFontSizeAndColorButtonsPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 0));

        panel.add(createFontSizeButtonsPart());
        panel.add(createColorButtonsPart());

        return panel;
    }

    private Component createFontSizeButtonsPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 0));

        panel.add(decreaseFontSizeButton);
        panel.add(standardFontSizeButton);
        panel.add(increaseFontSizeButton);

        return panel;
    }

    private Component createColorButtonsPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 0));

        panel.add(createSwitchForegroundColorButton());
        panel.add(createSwitchBackgroundColorButton());

        return panel;
    }

    private Component createSwitchForegroundColorButton() {
        JButton button = new JButton("toggle Vordergrundfarbe");
        button.addActionListener(e -> toggleColorForegroundDependingOnLastSuccess());
        return button;
    }

    private void toggleColorForegroundDependingOnLastSuccess() {
        tableRenderer.toggleColorForegroundDependingOnLastSuccess();
        table.repaint();
    }

    private Component createSwitchBackgroundColorButton() {
        JButton button = new JButton("toggle Hintergrundfarbe");
        button.addActionListener(e -> toggleColorBackgroundDependingOnLastSuccess());
        return button;
    }

    private void toggleColorBackgroundDependingOnLastSuccess() {
        tableRenderer.toggleColorBackgroundDependingOnLastSuccess();
        table.repaint();
    }

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

    private void quit() {
        closeDialog();
    }

}
