package de.duehl.swing.ui.components.selections.base;

/*
 * Copyright 2017 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.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

import de.duehl.basics.text.Text;
import de.duehl.swing.ui.GuiTools;
import de.duehl.swing.ui.colors.Colorizer;
import de.duehl.swing.ui.components.elements.TextFieldWithChangeButtonAndTitle;
import de.duehl.swing.ui.layout.VerticalLayout;

/**
 * Diese Klasse stellt die abstrakte Basis für eine Auswahl mehrerer Dateien oder Verzeichnisse,
 * etwa in einem Optionendialog dar.
 *
 * @version 1.01     2017-03-31
 * @author Christian Dühl
 */

public abstract class MultipleFileOrPathSelection {

    /** Überschrift, Textfeld und Änderungs-Schalter. */
    private final TextFieldWithChangeButtonAndTitle elements;

    /** Panel in dem alles dargestellt wird. */
    private final JPanel filesOrDirsPanel;

    /** Panel in dem die Jars dargestellt werden. */
    private final JPanel listPanel;

    /** Liste mit den Namen der externen Jars. */
    private final List<String> fileOrDirNames;

    /** Überschrift ganz oben über dem Rahmen. */
    private final String frameTitle;

    /**
     * Konstruktor.
     *
     * @param title
     *            Überschrift für die Wahl dieser Datei oder dieses Verzeichnisses.
     * @param frameTitle
     *            Überschrift ganz oben über dem Rahmen.
     */
    public MultipleFileOrPathSelection(String title, String frameTitle) {
        this.frameTitle = frameTitle;

        elements = new TextFieldWithChangeButtonAndTitle(title);
        elements.addReturnKeyClickButtonListener();
        elements.addButtonActionListener(createActionListener());
        elements.setButtonText("hinzufügen");

        fileOrDirNames = new ArrayList<>();

        listPanel = createListPanel();
        filesOrDirsPanel = createFilesOrDirsPanel();
    }

    private ActionListener createActionListener() {
        return new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                addFileOrDir();
            }
        };
    }

    /** Wird aufgerufen, wenn der Button zum Hinzufügen eines Pfades gedrückt wird. */
    private void addFileOrDir() {
        String fileOrDir = openPath(elements.getText());
        if (!fileOrDir.isEmpty()) {
            elements.setText("");
            fileOrDir = Text.nicePath(fileOrDir);
            addFileOrDirSubPanel(fileOrDir);
            filesOrDirsPanel.revalidate();
        }
    }

    /**
     * Der Benutzer wählt die Datei oder das Verzeichnis aus.
     *
     * @param startDir
     *            Startverzeichnis.
     * @return Ausgewählte Benutzereingabe oder null bei Abbruch durch den Benutzer.
     */
    abstract protected String openPath(String startDir);

    /** Fügt für die externen Jars des Projekts Unterpanel hinzu. */
    public void addInitialFileOrDirs(List<String> fileOrDirs) {
        for (String fileOrDir : fileOrDirs) {
            addFileOrDirSubPanel(fileOrDir);
        }
    }

    /**
     * Fügt eine Datei oder ein Verzeichnis zum Panel der Dateien oder Verzeichnisse hinzu.
     *
     * @param fileOrDir
     *            Datei oder ein Verzeichnis.
     */
    private void addFileOrDirSubPanel(String fileOrDir) {
        JPanel subPanel = new JPanel();
        subPanel.setLayout(new BorderLayout());

        subPanel.add(createNameOfFileOrDir(fileOrDir), BorderLayout.CENTER);
        subPanel.add(createRemoveButton(fileOrDir, subPanel), BorderLayout.EAST);

        listPanel.add(subPanel);
    }

    private JLabel createNameOfFileOrDir(String fileOrDir) {
        fileOrDirNames.add(fileOrDir);
        JLabel fileOrDirLabel = new JLabel(fileOrDir);
        fileOrDirLabel.setBorder(new EmptyBorder(0, 20, 0, 2));
        return fileOrDirLabel;
    }

    private JButton createRemoveButton(String fileOrDir, JPanel subPanel) {
        JButton button = new JButton("entfernen");
        //button.setPreferredSize(BUTTON_DIMENSION); wenn nötig, müssten dafür ein paar
        // Klimmzüge her...
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                fileOrDirNames.remove(fileOrDir);
                listPanel.remove(subPanel);
                filesOrDirsPanel.revalidate();
                filesOrDirsPanel.repaint();
                listPanel.revalidate();
                listPanel.repaint();
            }
        });
        return button;
    }

    /** Erzeugt den Panel mit den Dateien oder Verzeichnissen. */
    private JPanel createListPanel() {
        JPanel panel = new JPanel();
        panel.setLayout(new VerticalLayout(3, VerticalLayout.BOTH));

        return panel;
    }

    /** Erzeugt den Panel mit allem. */
    private JPanel createFilesOrDirsPanel() {
        JPanel panel = new JPanel();
        GuiTools.createTitle(frameTitle, panel);
        panel.setLayout(new BorderLayout());

        panel.add(elements.getPanel(), BorderLayout.NORTH);
        panel.add(listPanel, BorderLayout.CENTER);

        return panel;
    }

    /** Getter für den Panel mit diesem Element. */
    public Component getPanel() {
        return filesOrDirsPanel;
    }

    /** Färbt alle Komponenten mit dem übergebenen Colorizer ein. */
    public void colorize(Colorizer colorizer) {
        elements.colorize(colorizer);
        colorizer.setColors(listPanel);
        colorizer.setColors(filesOrDirsPanel);
        /*
         * TODO: Um die anderen Objekte passend zu färben, braucht man den Colorizer aber
         * eigentlich bei jeder Erzeugung ... vielleicht hier doch ein Colorizer im Konstruktor?
         * Aber das mache ich erst, wenn man dieses Objekt wirklich in einem der alten Projekte mit
         * Colorizer verwenden will.
         */
    }

    /** Getter für den (getrimmten) Text des Textfeldes. */
    public String getText() {
        return elements.getText();
    }

    /** Setzt den Text des Textfeldes. */
    public void setText(String text) {
        elements.setText(text);
    }

    /** Getter für die Liste mit den Namen der Dateien oder Verzeichnisse. */
    public List<String> getFileOrDirNames() {
        return fileOrDirNames;
    }

    /** Setzt die bevorzugt Größe des Buttons. */
    public void setButtonPreferredSize(Dimension buttonDimension) {
        elements.setButtonPreferredSize(buttonDimension);
    }

}
