package de.duehl.swing.ui.highlightingeditor.userinput;

import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import de.duehl.basics.debug.DebugHelper;
import de.duehl.swing.ui.highlightingeditor.multiplereactor.ChangeReactor;
import de.duehl.swing.ui.timer.WaitingUserInputTimerOperator;

/**
 * Diese Klasse stellt im bearbeitbaren Editors mit Syntax-Highlighting den Teil dar, der bei
 * Benutzereingaben auf deren Ende wartet, bevor das Syntax-Highlighting durchgeführt wird.
 *
 * @version 1.01     2017-12-19
 * @author Christian Dühl
 */

public class ReactAfterUserInput extends WaitingUserInputTimerOperator implements ChangeReactor {

    private final static boolean DEBUG = false;

    /** Der zugehörige Editor. */
    private final EditorForReactAfterUserInput editor;

    /** Gibt an, ob bei Änderungen am Dokument das Syntax-Highlighting durchgeführt werden soll. */
    private boolean reactOnChanges;

    /**
     * Konstruktor.
     *
     * @param millisecondsBeforeAction
     *            Anzahl der Millisekunden vor Durchführung der Aufgabe.
     * @param editor
     *            Der zugehörige Editor.
     */
    public ReactAfterUserInput(long millisecondsBeforeAction, EditorForReactAfterUserInput editor) {
        super(millisecondsBeforeAction);
        this.editor = editor;
        editor.addDocumentListener(createWaitingDocumentListener());
        doNotReactOnChanges();
    }

    /**
     * Gibt an, dass bei Änderungen am Dokument das Syntax-Highlighting durchgeführt werden soll.
     */
    @Override
    public void reactOnChanges() {
        reactOnChanges = true;
    }

    /**
     * Gibt an, dass bei Änderungen am Dokument kein Syntax-Highlighting durchgeführt werden soll.
     */
    @Override
    public void doNotReactOnChanges() {
        reactOnChanges = false;
    }

    /**
     * Erzeugt einen DocumentListener, der nach der Beendigung von Benutzereingaben die
     * Syntax-Hervorhebung durchführt.
     */
    private DocumentListener createWaitingDocumentListener() {
        return new DocumentListener() {
            @Override
            public void changedUpdate(DocumentEvent e) {
                warnAboutUserInput();
            }
            @Override
            public void removeUpdate(DocumentEvent e) {
                warnAboutUserInput();
            }
            @Override
            public void insertUpdate(DocumentEvent e) {
                warnAboutUserInput();
            }
            private void warnAboutUserInput() {
                if (reactOnChanges) {
                    reactOnDocumentChanges();
                }
            }
        };
    }

    /**
     * Reagiert auf Änderungen am Dokument des Editors.
     *
     * Hier soll auch wirklich auf diese Änderungen reagiert werden.
     *
     * Zunächst einmal wollen wir den Reiter sofort rot haben. Das Syntax-Highlighting soll aber
     * erst später durchgeführt werden.
     *
     * Daher verwenden wir einen Timer, der beim ersten User-Input startet aber bei weiterem
     * User-Input innerhalb einer gewissen Zeit wieder auf 0 gesetzt wird, damit nicht sofort,
     * sondern erst nach einer gewissen Zeit der Inaktivität die erneute Darstellung
     * (Syntax-Highlighting) durchführt wird.
     */
    private void reactOnDocumentChanges() {
        say("Usereingabe erkannt!");
        SwingUtilities.invokeLater(() -> editor.signChangedState());

        startTimer();
    }

    /**
     * Erzeugt für den ChangeListener ein Runnable, das im EDT die Syntax-Hervorhebung durchführt.
     *
     * @see createWaitingDocumentListener()
     */
    @Override
    protected Runnable createRunnable() {
        return new Runnable() {
            @Override
            public void run() {
                say("    -> SyntaxHighlightung nach Usereingabe!");
                SwingUtilities.invokeLater(() -> editor.reactAfterUserInput());
            }
        };
    }

    private void say(String message) {
        if (DEBUG) {
            DebugHelper.sayWithClassAndMethodAndTime(message);
        }
    }

}
