package de.duehl.swing.ui.tabs.bars.editors;

import java.awt.Component;

import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import de.duehl.basics.io.FileHelper;
import de.duehl.swing.ui.highlightingeditor.HighlightingEditor;
import de.duehl.swing.ui.tabs.Tabulator;
import de.duehl.swing.ui.tabs.bars.generic.TabBar;
import de.duehl.swing.ui.tabs.close.CloseButtonReaktor;
import de.duehl.swing.ui.tabs.elements.TabElements;
import de.duehl.swing.ui.tabs.elements.TabElementsWithEditor;

/**
 * Diese Klasse stellt die Basis für ein Reiterelement dar, welches eine Reihe von Editoren
 * aufnimmt. Dabei wird in jeden Reiter oben ein eigenes Tabulator-Objekt eingefügt, das anzeigen
 * kann, ob der Inhalt des Reiters geändert wurde oder unverändert ist.
 *
 * @version 1.01     2021-03-30
 * @author Christian Dühl
 */

public abstract class TabBarWithEditorsBase {

    /** Gibt an, ob der Button zum Löschen angezeigt werden soll. */
    private boolean showCloseButton;

    /** Die intern verwendete normale Tabulator-Leiste. */
    private TabBar<Component> tabBar;

    /** Legt fest, ob der Button zum Löschen angezeigt werden soll. */
    protected void setShowCloseButton(boolean showCloseButton) {
        this.showCloseButton = showCloseButton;
    }

    /** Gibt an, ob der Button zum Löschen angezeigt werden soll. */
    protected boolean isShowCloseButton() {
        return showCloseButton;
    }

    /** Getter für die intern verwendete normale Tabulator-Leiste. */
    protected TabBar<Component> getTabBar() {
        return tabBar;
    }

    /** Setter für die intern verwendete normale Tabulator-Leiste. */
    protected void setTabBar(TabBar<Component> tabBar) {
        this.tabBar = tabBar;
    }

    protected void createAndAddChangeListener() {
        tabBar.addChangeListener(createChangeListener());
    }

    /** Führt dazu, dass nach einem Reiterwechsel wieder der Editor den Fokus bekommt. */
    private ChangeListener createChangeListener() {
        return new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent changeEvent) {
                reactOnTabChange();
            }
        };
    }

    private void reactOnTabChange() {
        /* Da beim Growing ... eventuell gar kein Editor zurückkommt, lieber testen: */
        TabElements<Component> tabElements = tabBar.getSelectedTabElements();
        if (null != tabElements
                && tabElements instanceof TabElementsWithEditor tabElementsPlus) {
            HighlightingEditor editor = tabElementsPlus.getEditor();
            SwingUtilities.invokeLater(() -> editor.requestFocusInWindow());
        }
    }

    /**
     * Fügt einen Tabulator hinzu.
     *
     * @param editor
     *            Der Editor im Reiter.
     * @return Die erzeugten Elemente des Tabulators.
     */
    public TabElementsWithEditor addTab(HighlightingEditor editor) {
        TabElementsWithEditor tabElements = createNewTabElements(editor);
        tabBar.addTab(tabElements);
        return tabElements;
    }

    private TabElementsWithEditor createNewTabElements(HighlightingEditor editor) {
        String filename = editor.getFilename();
        String barename = FileHelper.getBareName(filename);

        String title = barename;
        Tabulator tabulator = createTabulator(title);
        return new TabElementsWithEditor(title, tabulator, editor);
    }

    private Tabulator createTabulator(String title) {
        String identifier = "Title: " + title;
        if (showCloseButton) {
            return new Tabulator(identifier, title, createCloseReaktor(title), showCloseButton);
        }
        else {
            return new Tabulator(identifier, title, showCloseButton);
        }
    }

    private CloseButtonReaktor createCloseReaktor(String title) {
        return new CloseButtonReaktor() {
            @Override
            public void closeButtonPressed(String tabUserOrGroupIdentifier) {
                removeTab(title);
            }
        };
    }

    /** Entfernt den Reiter mit dem angegebenen Namen. */
    public void removeTab(String title) {
        tabBar.removeTab(title);
    }

    /** Getter für die Komponente zum Einfügen in die grafische Oberfläche. */
    public Component getComponent() {
        return tabBar.getComponent();
    }

    /** Validiert die Reiter. */
    public void validate() {
        tabBar.validate();
    }

    /** Beendet in allen Editoren die Timer, die auf Benutzereingaben warten. */
    public void cancelTimer() {
        for (TabElements<Component> tabElementWC : tabBar.getTabElementsList()) {
            TabElementsWithEditor tabElement = (TabElementsWithEditor) tabElementWC;
            HighlightingEditor editor = tabElement.getEditor();
            editor.cancelTimer();
        }
    }

    /** Legt den Fokus auf den angezeigten Editor. */
    public void focusSelectedEditor() {
        reactOnTabChange();
    }

    /** Wählt den anzuzeigenden Tab über den Editor aus. */
    public void select(HighlightingEditor editor) {
        for (TabElements<Component> tabElementWC : tabBar.getTabElementsList()) {
            TabElementsWithEditor tabElement = (TabElementsWithEditor) tabElementWC;
            if (editor.equals(tabElement.getEditor())) {
                tabBar.select(tabElementWC);
            }
        }
    }

}
