package de.duehl.swing.ui.lights;

/*
 * Copyright 2025 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.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;

import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;

import de.duehl.basics.datetime.time.watch.StopWatch;
import de.duehl.swing.ui.colors.ColorTool;
import de.duehl.swing.ui.colors.NamedColorListFabric;
import de.duehl.swing.ui.lights.data.CheckLightMode;
import de.duehl.swing.ui.panel.painted.CirclePanel;

/**
 * Diese Klasse stellt ein Element dar, welches mit kleinen Ampelgrafiken den Fortschritt z.B.
 * des Ergebnisses eine Prüfung anzeigen kann. Dabei werden vier Zustände unterschieden:
 *
 *     1) noch nicht getestet / unbearbeitet (schwarze Ampel)
 *     2) erfolgreich getestet / bearbeitet (grüne Ampel)
 *     3) es traten Warnungen auf (gelbe Ampel)
 *     4) es traten Fehlern auf (rote Ampel)
 *
 * @version 1.01     2025-11-23
 * @author Christian Dühl
 */

public class CheckLight {

    /** Die Größe der einzelnen Ampellichter. */
    private static final Dimension LIGHT_DIMENSION = new Dimension(50, 50);

    private static final String NOT_STARTED_LIGHT_COLOR = NamedColorListFabric.DARKGRAY;
    private static final String BLACK_LIGHT_COLOR = NamedColorListFabric.BLACK;
    private static final String GREEN_LIGHT_COLOR = NamedColorListFabric.GREEN; // DARKGREEN
    private static final String YELLOW_LIGHT_COLOR = NamedColorListFabric.YELLOW;
    private static final String RED_LIGHT_COLOR = NamedColorListFabric.RED;

    /**
     * Die Art der Darstellung:
     *
     *    a) eine einzelne Ampel, die die drei Zustände annehmen kann
     *    b) zwei Ampeln, eine schwarz/grün, die andere schwarz/rot
     *    c) drei Ampeln, eine schwarz/grün, die zweite schwarz/gelb und die dritte schwarz/rot
     */
    private final CheckLightMode mode;

    /** Die Beschreibung der Prüfung bzw. des Schrittes. */
    private final String checkDescription;

    /** Der Panel auf dem das / die Lichter dargestellt werden. */
    private final JPanel panel;

    /* Die Ampel-Segmente für die Darstellung der Ampel: */
    private final CirclePanel singleLight;
    private final CirclePanel greenLight;
    private final CirclePanel yellowLight;
    private final CirclePanel redLight;

    /** Die Darstellung der Beschreibung. */
    private final JLabel descriptionLabel;

    /** Die Darstellung der Laufzeit. */
    private final JLabel runtimeLabel;

    /** Misst die Laufzeit der Prüfung / des Schritts. */
    private final StopWatch checkWatch;

    /**
     * Konstruktor.
     *
     * @param mode
     *            Die Art der Darstellung
     * @param checkDescription
     *            Die Beschreibung der Prüfung bzw. des Schrittes.
     */
    public CheckLight(CheckLightMode mode, String checkDescription) {
        this.mode = mode;
        this.checkDescription = checkDescription;

        checkWatch = new StopWatch();

        panel = new JPanel();

        singleLight = new CirclePanel();
        greenLight = new CirclePanel();
        yellowLight = new CirclePanel();
        redLight = new CirclePanel();

        descriptionLabel = new JLabel();
        runtimeLabel = new JLabel();

        init();
        createGui();
    }

    private void init() {
        initPanel();
        initLabel();
        initLights();
    }

    private void initPanel() {
        panel.setLayout(new BorderLayout());
    }

    private void initLabel() {
        setNotStartedColor();

        descriptionLabel.setText(checkDescription);
        descriptionLabel.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));

        runtimeLabel.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
    }

    private void initLights() {
        singleLight.setPreferredSize(LIGHT_DIMENSION);
        greenLight.setPreferredSize(LIGHT_DIMENSION);
        yellowLight.setPreferredSize(LIGHT_DIMENSION);
        redLight.setPreferredSize(LIGHT_DIMENSION);
    }

    private void createGui() {
        panel.add(createLightsPart(), BorderLayout.WEST);
        panel.add(createDescriptionAndRuntimePart(), BorderLayout.CENTER);
    }

    private Component createLightsPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(1, 0, 1, 1));

        switch (mode) {
            case ONE:
                panel.add(singleLight);
                break;
            case TWO:
                panel.add(greenLight);
                panel.add(redLight);
                break;
            case THREE:
                panel.add(greenLight);
                panel.add(yellowLight);
                panel.add(redLight);
                break;
            default:
                throw new RuntimeException("Unbekannter Modus " + mode + ".");
        }
        //panel.add(label);

        return panel;
    }

    private Component createDescriptionAndRuntimePart() {
        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(0, 1, 0, 0));

        panel.add(descriptionLabel);
        panel.add(runtimeLabel);

        return panel;
    }

    /** Getter für den Panel, auf dem das / die Lichter dargestellt werden. */
    public Component getPanel() {
        return panel;
    }


    /** Setzt das Licht auf 'Nicht gestartet'. */
    public void setNotStartedColor() {
        singleLight.setSymbolColor(ColorTool.getColorByName(NOT_STARTED_LIGHT_COLOR));
        greenLight.setSymbolColor(ColorTool.getColorByName(NOT_STARTED_LIGHT_COLOR));
        yellowLight.setSymbolColor(ColorTool.getColorByName(NOT_STARTED_LIGHT_COLOR));
        redLight.setSymbolColor(ColorTool.getColorByName(NOT_STARTED_LIGHT_COLOR));
        checkWatch.start();
    }

    /** Setzt das Licht auf 'Schwarz'. */
    public void setBlack() {
        singleLight.setSymbolColor(ColorTool.getColorByName(BLACK_LIGHT_COLOR));
        greenLight.setSymbolColor(ColorTool.getColorByName(BLACK_LIGHT_COLOR));
        yellowLight.setSymbolColor(ColorTool.getColorByName(BLACK_LIGHT_COLOR));
        redLight.setSymbolColor(ColorTool.getColorByName(BLACK_LIGHT_COLOR));
        checkWatch.start();
    }

    /** Setzt das Licht auf 'Grün'. */
    public void setGreen() {
        singleLight.setSymbolColor(ColorTool.getColorByName(GREEN_LIGHT_COLOR));
        greenLight.setSymbolColor(ColorTool.getColorByName(GREEN_LIGHT_COLOR));
        yellowLight.setSymbolColor(ColorTool.getColorByName(BLACK_LIGHT_COLOR));
        redLight.setSymbolColor(ColorTool.getColorByName(BLACK_LIGHT_COLOR));
        setRuntime();
    }

    /** Setzt das Licht auf 'Gelb'. */
    public void setYellow() {
        if (mode == CheckLightMode.TWO) {
            throw new RuntimeException("Bei der Darstellung mit einer Ampel ohne Gelbphase kann "
                    + "sie nicht auf Gelb gesetzt werden.");
        }

        singleLight.setSymbolColor(ColorTool.getColorByName(YELLOW_LIGHT_COLOR));
        greenLight.setSymbolColor(ColorTool.getColorByName(BLACK_LIGHT_COLOR));
        yellowLight.setSymbolColor(ColorTool.getColorByName(YELLOW_LIGHT_COLOR));
        redLight.setSymbolColor(ColorTool.getColorByName(BLACK_LIGHT_COLOR));
        setRuntime();
    }

    /** Setzt das Licht auf 'Rot'. */
    public void setRed() {
        singleLight.setSymbolColor(ColorTool.getColorByName(RED_LIGHT_COLOR));
        greenLight.setSymbolColor(ColorTool.getColorByName(BLACK_LIGHT_COLOR));
        yellowLight.setSymbolColor(ColorTool.getColorByName(BLACK_LIGHT_COLOR));
        redLight.setSymbolColor(ColorTool.getColorByName(RED_LIGHT_COLOR));
        setRuntime();
    }

    private void setRuntime() {
        checkWatch.stop();
        runtimeLabel.setText("Laufzeit: " + checkWatch.getTime());
    }

    /** Gibt die gemessene Laufzeit der Prüfung / des Schritts. */
    public String getRuntime() {
        if (null != checkWatch && checkWatch.isStopped()) {
            return checkWatch.getTime();
        }
        else {
            throw new RuntimeException("Der Schritt war noch nicht fertig.");
        }
    }
}
