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

/*
 * Copyright 2020 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 java.awt.Dimension;

import javax.swing.JLabel;
import javax.swing.JTextField;

import de.duehl.basics.logic.ErrorHandler;
import de.duehl.swing.ui.GuiTools;

/**
 * Diese Klasse stellt eine Navigation mit vier Schaltern dar, um zum ersten, zum vorigen, zum
 * nächsten und zum letzten Element zu gelangen. Außerdem wird die Nummer des aktuell angezeigten
 * Elements als bearbeitbares Feld und die Anzahl der Elemente als nicht bearbeitbares Feld
 * angezeigt.
 *
 * Der Benutzer muss nach der Objekterstellung noch fillNavigator() aufrufen!
 *
 * Lieber den ListNavigator benutzen!
 *
 * @version 1.02     2020-05-26
 * @author Christian Dühl
 */

public class NavigatorPanelWithDocumentPosition extends NavigatorPanel {

    private static final long serialVersionUID = 1L;

    private static final int NO_NUMBER_OF_ELEMENTS_DETECTED = -2;

    /** Behandelt auftretende Fehler. */
    private final ErrorHandler error;

    /** Das Feld mit der Nummer des aktuellen Datensatzes. */
    private final JTextField goToNumberOfElementsIndexField;

    /** Das Feld mit der gesamten Anzahl der Datensätze. */
    private final JTextField totalNumberOfElementsIndexField;

    /**
     * Objekt das auf eine vom Benutzer eingegebene Elementnummer zwischen 1 und der Maximalzahl
     * der Elemente reagiert.
     */
    private ReactOnUserElementNumberSelection reactOnUnserElementNumberSelection;

    /** Die aktuell angezeigte Elementnummer. */
    private int actualShownNumberOfElement;

    /** Anzahl aller Elemente. */
    private int totalNumberOfElements;

    /** Konstruktor mit Anzeige der Dokumentnummer und mit der Standard-Buttongröße. */
    public NavigatorPanelWithDocumentPosition(ErrorHandler error) {
        this(DEFAULT_BUTTON_SIZE, error);
    }

    /** Konstruktor mit Anzeige der Dokumentnummer und individueller Buttongröße. */
    public NavigatorPanelWithDocumentPosition(Dimension buttonSize, ErrorHandler error) {
        super(buttonSize);
        this.error = error;

        goToNumberOfElementsIndexField = new JTextField("", 4);
        totalNumberOfElementsIndexField = new JTextField("", 4);

        addFirstActionListener(e -> first());
        addPreviousActionListener(e -> previous());
        addNextActionListener(e -> next());
        addLastActionListener(e -> last());
    }

    private void first() {
        setActualShownNumberOfElement(1);
    }

    private void previous() {
        if (actualShownNumberOfElement > 1) {
            setActualShownNumberOfElement(actualShownNumberOfElement - 1);
        }
    }

    private void next() {
        if (actualShownNumberOfElement < totalNumberOfElements) {
            setActualShownNumberOfElement(actualShownNumberOfElement + 1);
        }
    }

    private void last() {
        setActualShownNumberOfElement(totalNumberOfElements);
    }

    @Override
    protected int calculatePreferredWidth() {
        int width = super.calculatePreferredWidth();

        int numberOfAdditionalHorizontalElements = 3;
        int estimatedFieldWidth = 50; // TODO
        int esitmatedSlashLabeWidth = 15; // TODO
        width += (numberOfAdditionalHorizontalElements + 1) * HORIZONTAL_GAP
                + 2 * estimatedFieldWidth
                + esitmatedSlashLabeWidth;
        /*
         * Die Gui-Elemente kann man ja leider erst nach der Größe fragen, wenn sie angezeigt sind.
         */

        return width;
    }

    @Override
    protected void addElements() {
        addLeftNavigationElements();
        addDocumentPositionElements();
        addRightNavigationElements();
    }

    private void addDocumentPositionElements() {
        add(goToNumberOfElementsIndexField);
        add(new JLabel("/"));
        add(totalNumberOfElementsIndexField);
    }

    @Override
    protected void initElelents() {
        super.initElelents();

        goToNumberOfElementsIndexField.addActionListener(e -> reactOnDocumentIndexInput());
        GuiTools.biggerFont(goToNumberOfElementsIndexField, 5);

        totalNumberOfElementsIndexField.setFocusable(false);
        totalNumberOfElementsIndexField.setEditable(false);
        GuiTools.biggerFont(totalNumberOfElementsIndexField, 5);

        setActualShownNumberOfElement(1);
    }

    /** Reagiert auf die Eingabe einer Datensatznummer durch den Benutzer (1-basiert). */
    private void reactOnDocumentIndexInput() {
        String numberString = goToNumberOfElementsIndexField.getText().trim();
        if (!numberString.isEmpty()) {
            int elementNumber = determineShownNumberOfElements(numberString);
            if (elementNumber != NO_NUMBER_OF_ELEMENTS_DETECTED) {
                reactOnUnserElementNumberSelection.reactOnUserElementNumberSelection(elementNumber);
                setActualShownNumberOfElement(elementNumber);
            }
        }
    }

    private int determineShownNumberOfElements(String numberString) {
        try {
            int number = Integer.parseInt(numberString);
            if (number > 0 && number <= totalNumberOfElements) {
                return number;
            }
            else {
                return NO_NUMBER_OF_ELEMENTS_DETECTED;
            }
        }
        catch (NumberFormatException nfe) {
            error.warning(numberString + " ist keine valide Nummer.");
            return NO_NUMBER_OF_ELEMENTS_DETECTED;
        }
    }

    /**
     * Setzt das Objekt, das auf eine vom Benutzer eingegebene Elementnummer zwischen 1 und der
     * Maximalzahl der Elemente reagiert.
     */
    public void setReactOnUserElementNumberSelection(ReactOnUserElementNumberSelection react) {
        reactOnUnserElementNumberSelection = react;
    }

    /** Setzt die Anzahl der Elemente. */
    public void setTotalNumberOfElements(int totalNumberOfElements) {
        this.totalNumberOfElements = totalNumberOfElements;
        totalNumberOfElementsIndexField.setText(Integer.toString(totalNumberOfElements));
    }

    /** Getter für die Anzahl der Elemente. */
    public int getTotalNumberOfElements() {
        return totalNumberOfElements;
    }

    /** Setzt die aktuell angezeigte Elementnummer. */
    public void setActualShownNumberOfElement(int actualShownNumberOfElement) {
        this.actualShownNumberOfElement = actualShownNumberOfElement;
        goToNumberOfElementsIndexField.setText(Integer.toString(actualShownNumberOfElement));
    }

    /** Lässt keine aktuelle Dokumentnummer anzeigen. */
    public void clearActualShownNumberOfElement() {
        goToNumberOfElementsIndexField.setText("");
    }

    /** Getter für die aktuell angezeigte Elementnummer. */
    public int getActualShownNumberOfElement() {
        return actualShownNumberOfElement;
    }

}
