package de.duehl.swing.ui.elements.progress;

/*
 * Copyright 2024 Christian Dühl. All rights reserved.
 *
 * This program is free software. You can redistribute it and/or
 * modify it under the same terms as perl:
 *
 * general:  http://dev.perl.org/licenses/
 * GPL:      http://dev.perl.org/licenses/gpl1.html
 * artistic: http://dev.perl.org/licenses/artistic.html
 */

import java.awt.Component;

import javax.swing.SwingUtilities;

import de.duehl.swing.ui.GuiTools;

/**
 * Diese Klasse stellt eine vereinfachte Handhabung für den Fortschrittsbalken zusammen mit ein
 * paar Angaben zum Fortschritt dar.
 *
 * Es wird erwartet, dass der eigentliche Task in einem eigenen Thread abläuft, um die Gui nicht
 * einfrieren zu lassen, daher wird hier mit invokeLater() gearbeitet.
 *
 * Anwendung siehe de.heinsundpartner.hr.cleanup.cluster7.ui.dialogs.ProgressDialog:        <pre>
 *
 *      moveProgressPanel = new StandardColoredProgressPanel()
 *              .setProgressTitle("Fortschritt beim Verschieben von INS- und "
 *                      + "ZH-Banz-Verzeichnissen auf den Cluster1:")
 *              .setCountPrefix("Anzahl verschobener Verzeichnisse: ")
 *              .setTimerPrefix("Laufzeit: ")
 *              .setActualElementPrefix("Verschiebe: ")
 *              .setActualElementPrefixBeforeStart("Noch nichts verschoben.")
 *              .setActualElementWhenDone("Alle INS- und ZH-Banz-Verzeichnisse wurden vom CLuster7 "
 *                      + "verschoben.")
 *              .createProgressPanel();
 *
 * später dann:
 *
 *      panel.add(moveProgressPanel.getComponent());
 *
 * ...
 *
 *      moveProgressPanel.initNumberOfTasksToDo(numberOfDirectoriesToMove);
 *
 * ...
 *
 *      moveProgressPanel.startingWithTask();
 *
 * ...
 *
 *      moveProgressPanel.aboutToExceuteOneTaskSoon(description);
 *
 * ...
 *
 *      moveProgressPanel.oneTaskDone(description);
 *      if (moveProgressPanel.isAllDone()) {
 *          closeDialog();
 *      }
 *                                                                                           </pre>
 *
 * Aufgerufen wird dies wiederum von de.heinsundpartner.hr.cleanup.cluster7.logic.Cluster7Cleaner.
 *
 * Eine einfachere Demo befindet sich in
 * de.duehl.swing.ui.start.progress.StandardColoredProgressPanelDemo
 *
 * @version 1.01     2024-11-20
 * @author Christian Dühl
 */

public class StandardColoredProgressPanel {

    private static final boolean DEBUG = false;


    /** Der Titel über dem Fortschrittsbalken, beispielsweise "Fortschritt des Importierens:". */
    private String progressTitle;

    /** Der Text vor dem Zähler, beispielsweise "Anzahl importierter XML-Dateien: ". */
    private String countPrefix;

    /** Der Text vor der Stoppuhr, beispielsweise "Laufzeit: ". */
    private String timerPrefix;

    /** Der Text in der Beschreibung des aktuellen Schrittes, beispielsweise "füge ein: ". */
    private String actualElementPrefix;

    /**
     * Der Text in der Beschreibung des aktuellen Schrittes vor Start der Ausführung, beispielsweise
     * "noch nichts in die DB geschrieben".
     */
    private String actualElementPrefixBeforeStart;

    /**
     * Der Text in der Beschreibung des aktuellen Schrittes nach Abarbeitung aller Schritte,
     * beispielsweise "Alle Daten wurden in die Datenbank geschrieben."
     */
    private String actualElementWhenDone;

    /** Der Panel mit der Fortschrittsanzeige für die Bearbeitung. */
    private ColoredProgressPanel progressPanel;

    /** Die Anzahl der auszuführenden Schritte. */
    private int numberOfTasksToDo;

    /** Die Anzahl der bereits ausgeführten Schritte. */
    private int numberOfTasksDone;

    /** Konstruktor. */
    public StandardColoredProgressPanel() {
        progressTitle = "";
        countPrefix = "";
        timerPrefix = "";
        actualElementPrefix = "";
        actualElementPrefixBeforeStart = "";
        actualElementWhenDone = "";

        numberOfTasksToDo = -1; // setzen über initNumberOfTasksToDo()!
        numberOfTasksDone = 0;  // bitte mit startingWithTask() initialisieren!
    }


    /**
     * Setter für den Titel über dem Fortschrittsbalken, beispielsweise "Fortschritt des
     * Importierens:".
     */
    public StandardColoredProgressPanel setProgressTitle(String progressTitle) {
        checkProgressBarIsNull("setProgressTitle()");
        this.progressTitle = progressTitle;
        return this;
    }

    /** Setter für den Text vor dem Zähler, beispielsweise "Anzahl importierter XML-Dateien: ". */
    public StandardColoredProgressPanel setCountPrefix(String countPrefix) {
        checkProgressBarIsNull("setCountPrefix()");
        this.countPrefix = countPrefix;
        return this;
    }

    /** Setter für den Text vor der Stoppuhr, beispielsweise "Laufzeit: ". */
    public StandardColoredProgressPanel setTimerPrefix(String timerPrefix) {
        checkProgressBarIsNull("setTimerPrefix()");
        this.timerPrefix = timerPrefix;
        return this;
    }

    /**
     * Setter für den Text in der Beschreibung des aktuellen Schrittes, beispielsweise
     * "füge ein: ".
     */
    public StandardColoredProgressPanel setActualElementPrefix(String actualElementPrefix) {
        checkProgressBarIsNull("setActualElementPrefix()");
        this.actualElementPrefix = actualElementPrefix;
        return this;
    }

    /**
     * Setter für den Text in der Beschreibung des aktuellen Schrittes vor Start der Ausführung,
     * beispielsweise "noch nichts in die DB geschrieben".
     */
    public StandardColoredProgressPanel setActualElementPrefixBeforeStart(
            String actualElementPrefixBeforeStart) {
        checkProgressBarIsNull("setActualElementPrefixBeforeStart()");
        this.actualElementPrefixBeforeStart = actualElementPrefixBeforeStart;
        return this;
    }

    /**
     * Setter für den Text in der Beschreibung des aktuellen Schrittes nach Abarbeitung aller
     * Schritte, beispielsweise "Alle Daten wurden in die Datenbank geschrieben."
     */
    public StandardColoredProgressPanel setActualElementWhenDone(String actualElementWhenDone) {
        checkProgressBarIsNull("setActualElementWhenDone()");
        this.actualElementWhenDone = actualElementWhenDone;
        return this;
    }

    private void checkProgressBarIsNull(String caller) {
        if (null != progressPanel) {
            throw new RuntimeException(
                    caller + " darf nur vor createProgressPanel() aufgerufen werden!");
        }
    }

    /** Erzeugt den ProgressPanel. Muss als letztes nach den Settern stehen. */
    public StandardColoredProgressPanel createProgressPanel() {
        progressPanel = new ColoredProgressPanel(
                progressTitle,
                countPrefix,
                timerPrefix,
                actualElementPrefix,
                actualElementPrefixBeforeStart,
                actualElementWhenDone);
        progressPanel.stopStopWatch();
        GuiTools.createTitle(progressPanel);

        return this;
    }

    private void checkProgressBarIsInitialized(String caller) {
        if (null == progressPanel) {
            throw new RuntimeException(
                    caller + " darf erst nach createProgressPanel() aufgerufen werden!");
        }
    }

    /** Initialisiert die Anzahl der auszuführenden Schritte. Erst nach der Erzeugung aufrufen! */
    public void initNumberOfTasksToDo(int numberOfTasksToDo) {
        SwingUtilities.invokeLater(() -> initNumberOfTasksToDoInEdt(numberOfTasksToDo));
    }

    private void initNumberOfTasksToDoInEdt(int numberOfTasksToDo) {
        this.numberOfTasksToDo = numberOfTasksToDo;
        say("initNumberOfTasksToDoInEdt: numberOfTasksToDo = " + numberOfTasksToDo);
        checkProgressBarIsInitialized("initNumberOfTasksToDo()");
        progressPanel.updateProgress(numberOfTasksToDo, numberOfTasksDone, "noch nicht angefangen");
    }


    /** Getter für die Komponente zum Einbau in der Gui. */
    public Component getComponent() {
        checkProgressBarIsInitialized("getComponent()");
        return progressPanel;
    }

    /** Informiert darüber, dass mit der Arbeit als ganzer begonnen wird. */
    public void startingWithTask() {
        SwingUtilities.invokeLater(() -> startingWithTaskInEdt());
    }

    private void startingWithTaskInEdt() {
        checkProgressBarIsInitialized("startingWithTask()");
        numberOfTasksDone = 0;
        updateProgress(actualElementPrefixBeforeStart);
        say("updateProgress: START");
        progressPanel.startStopWatch();
    }

    /** Informiert darüber, dass ein Task nun ausgeführt wird. */
    public void aboutToExceuteOneTaskSoon(String description) {
        SwingUtilities.invokeLater(() -> aboutToExceuteOneTaskSoonInEdt(description));
    }

    private void aboutToExceuteOneTaskSoonInEdt(String description) {
        checkProgressBarIsInitialized("aboutToExceuteOneTaskSoon()");
        updateProgress(description);
    }

    /** Informiert darüber, dass ein Task ausgeführt wurde. */
    public void oneTaskDone(String description) {
        SwingUtilities.invokeLater(() -> oneTaskDoneInEdt(description));
    }

    private void oneTaskDoneInEdt(String description) {
        checkProgressBarIsInitialized("oneTaskDone()");
        ++numberOfTasksDone;
        say("oneTaskDoneInEdt: numberOfTasksDone = " + numberOfTasksDone);
        updateProgress(description);
    }

    private void updateProgress(String description) {
        checkProgressBarIsInitialized("updateProgress()");
        progressPanel.updateProgress(numberOfTasksToDo, numberOfTasksDone, description);
        say("updateProgress: numberOfTasksToDo = " + numberOfTasksToDo + ", numberOfTasksDone = "
                + numberOfTasksDone);
        //SystemTools.sleep(10); // Sonst beendet sich seltsamer Weise ohne Debugausgaben manchmal
                               // der Thread mit der Stoppuhr nicht.
//        if (isAllDone()) {
//            say("updateProgress: STOP");
//            progressPanel.stopStopWatch();
//        }
    }

//    /** Gibt an, ob alle Schritte fertig sind. */
//    private boolean isAllDone() {
//        return numberOfTasksDone == numberOfTasksToDo;
//    }

    /** Hält die Stoppuhr an, falls die noch läuft. */
    public void quit() {
        SwingUtilities.invokeLater(() -> quitInEdt());
    }

    private void quitInEdt() {
        progressPanel.stopStopWatch();
    }

    private static void say(String message) {
        if (DEBUG) {
            System.out.println(message);
        }
    }

}
