package de.duehl.swing.ui.dialogs.lists;

import java.awt.BorderLayout;
import java.awt.Component;

/*
 * Copyright 2021 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.Dimension;
import java.awt.EventQueue;
import java.awt.Image;
import java.awt.Point;

import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

import de.duehl.swing.ui.GuiTools;
import de.duehl.swing.ui.dialogs.base.ModalDialogBase;
import de.duehl.swing.ui.dialogs.lists.logic.LogicalEditableList;
import de.duehl.swing.ui.dialogs.lists.logic.LogicalEditableListElement;
import de.duehl.swing.ui.dialogs.lists.ui.EditableListElement;
import de.duehl.swing.ui.dialogs.lists.ui.UiElementListModifier;
import de.duehl.swing.ui.layout.VerticalLayout;

/**
 * Diese Klasse stellt die gemeinsame Basis für Dialoge dar, die mit einer Liste von anzuzeigenden
 * Elementen arbeiten.
 *
 * @version 1.02     2021-11-30
 * @author Christian Dühl
 */

abstract class EditableListDialogBase<Element extends LogicalEditableListElement>
        extends ModalDialogBase implements UiElementListModifier<Element> {

    /** Liste mit den logischen Elementen, welche dargestellt werden. */
    protected final LogicalEditableList<Element> logicalList;

    /** Panel mit der grafischen Auflistung der Elemente. */
    private final JPanel elementsPanel;

    /**
     * Gibt an, ob das Update zur Initialisierung beim Aufbau des Dialogs stattfindet, oder später
     * nach echten, inhaltlichen Änderungen.
     */
    private boolean initialUpdate;

    /** Gibt an, ob während des Dialogs Daten verändert wurden. */
    private boolean dataChanged;

    /**
     * Konstruktor.
     *
     * @param dialogDimension
     *            Größe des Dialogfensters.
     * @param parentLocation
     *            Position des Rahmens der Oberfläche, vor der dieser Dialog erzeugt wird.
     * @param programImage
     *            Icon für das Programm.
     * @param dialogTitle
     *            Titel des Dialogs.
     * @param logicalList
     *            Liste mit den logischen Elementen, welche dargestellt werden
     */
    public EditableListDialogBase(Dimension dialogDimension, Point parentLocation,
            Image programImage, String dialogTitle, LogicalEditableList<Element> logicalList) {
        super(parentLocation, programImage, dialogTitle);
        setMinimumSize(dialogDimension);

        this.logicalList = logicalList;

        elementsPanel = new JPanel();
        elementsPanel.setLayout(new BorderLayout());
        GuiTools.createTitle(elementsPanel);

        initialUpdate = true;
        dataChanged = false;
        updateElementsPanel();
    }

    @Override
    public final void updateElementsPanel() {
        EventQueue.invokeLater(() -> updateElementsPanelInEDT());
    }

    private void updateElementsPanelInEDT() {
        elementsPanel.removeAll();

        elementsPanel.add(createRealElementsPart(), BorderLayout.CENTER);

        elementsPanel.revalidate();
        repaint();

        if (initialUpdate) {
            initialUpdate = false;
        }
        else {
            dataChanged = true;
        }
    }

    private Component createRealElementsPart() {
        JPanel panel = new JPanel();
        panel.setLayout(new VerticalLayout(0, VerticalLayout.BOTH));

        for (Element element : logicalList) {
            panel.add(createRealElementPart(element));
        }

        JScrollPane scroll = new JScrollPane(panel);
        GuiTools.setVerticalScrollBarUnitIncrement(scroll, 30);
        return scroll;
    }

    /** Erzeugt die Darstellung für das übergebene Element. */
    protected abstract Component createRealElementPart(Element element);

    protected final JPanel getElementsPanel() {
        return elementsPanel;
    }

    /** Baut die Gui auf. */
    @Override
    protected final void populateDialog() {
        add(createMainPart(), BorderLayout.CENTER);
        add(createFooterButtonsPart(),  BorderLayout.SOUTH);
    }

    /** Erzeugt den Hauptbereich des Dialogs. */
    protected abstract Component createMainPart();

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

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

        return panel;
    }

    private JButton createQuitButton() {
        JButton button = new JButton("Beenden");
        button.setFocusable(false);
        button.addActionListener(e -> closeDialog());
        return button;
    }

    @Override
    public final void removeElementFromList(Element element) {
        logicalList.remove(element);
        updateElementsPanel();
    }

    /**
     * Gibt die Komponente des Verwaltungsdialogs an, um vor dieser weitere Dialoge positionieren
     * zu können.
     */
    @Override
    public final Component getComponent() {
        return getDialog();
    }

    /** Getter für die Liste mit den logischen Elementen, welche dargestellt werden. */
    protected final LogicalEditableList<Element> getLogicalList() {
        return logicalList;
    }

    /** Erzeugt aus dem übergebenen logischen Element ein Ui-Element, welches dieses darstellt. */
    protected abstract EditableListElement<Element> createUiElement(Element element);

    /** Gibt an, ob während des Dialogs Daten verändert wurden. */
    public final boolean isDataChanged() {
        return dataChanged;
    }

}
