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

/*
 * Copyright 2018 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.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

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

import de.duehl.swing.ui.colors.Colorizer;
import de.duehl.swing.ui.dialogs.base.ModalDialogBase;

/**
 * Diese Klasse öffnet einen Dialog zum Eingeben zweier Werte.
 *
 * Der Aufrufer muss apply() überschreiben, er kann mit getFirstValue() und mit getSecondValue()
 * die Werte aufrufen. Mit applyFailure(String message) wird das schließen des Dialogs verhindert.
 * Mit applyOK() wird angezeigt, dass alles in Ordnung ist. Der Dialog wird beendet und mit
 * getFirstValue() und mit getSecondValue() können nun die verifizierten Werte abgefragt werden.
 *
 * @version 1.02     2018-02-08
 * @author Christian Dühl
 */

public abstract class EnterTwoValuesDialog extends ModalDialogBase {

    private static final Dimension DIALOG_DIMENSION = new Dimension(500, 120);

    /** Text der Frage über dem ersten Eingabefeld. */
    private final String firstQuestion;

    /** Vorgabe die im ersten Eingabefeld angezeigt werden soll. */
    private final String firstPresetting;

    /** Erstes Feld in das der Benutzer seine Daten eingibt. */
    private final JTextField firstValueField;

    /** Text der Frage über dem zweiten Eingabefeld. */
    private final String secondQuestion;

    /** Vorgabe die im zweiten Eingabefeld angezeigt werden soll. */
    private final String secondPresetting;

    /** Zweites Feld in das der Benutzer seine Daten eingibt. */
    private final JTextField secondValueField;

    /** Gibt an, ob der Dialog beendet werden kann. */
    private boolean applyOk;

    /**
     * Konstruktor.
     *
     * @param parentLocation
     *            Position des Rahmens der Oberfläche, vor der dieser Dialog erzeugt wird.
     * @param programImage
     *            Icon für den Dialog.
     * @param dialogTitle
     *            Titel des Dialogs.
     * @param firstQuestion
     *            Text der Frage über dem ersten Eingabefeld.
     * @param firstPresetting
     *            Vorgabe die im ersten Eingabefeld angezeigt werden soll.
     * @param secondQuestion
     *            Text der Frage über dem zweiten Eingabefeld.
     * @param secondPresetting
     *            Vorgabe die im zweiten Eingabefeld angezeigt werden soll.
     */
    public EnterTwoValuesDialog(Point parentLocation, Image programImage, String dialogTitle,
            String firstQuestion, String firstPresetting, String secondQuestion,
            String secondPresetting) {
        this(null, parentLocation, programImage, dialogTitle, firstQuestion, firstPresetting,
                secondQuestion, secondPresetting);
    }

    /**
     * Konstruktor.
     *
     * @param colorizer
     *            Farbverwaltung für die Gui.
     * @param parentLocation
     *            Position des Rahmens der Oberfläche, vor der dieser Dialog erzeugt wird.
     * @param programImage
     *            Icon für den Dialog.
     * @param dialogTitle
     *            Titel des Dialogs.
     * @param firstQuestion
     *            Text der Frage über dem ersten Eingabefeld.
     * @param firstPresetting
     *            Vorgabe die im ersten Eingabefeld angezeigt werden soll.
     * @param secondQuestion
     *            Text der Frage über dem zweiten Eingabefeld.
     * @param secondPresetting
     *            Vorgabe die im zweiten Eingabefeld angezeigt werden soll.
     */
    public EnterTwoValuesDialog(Colorizer colorizer, Point parentLocation, Image programImage,
            String dialogTitle, String firstQuestion, String firstPresetting, String secondQuestion,
            String secondPresetting) {
        super(parentLocation, programImage, dialogTitle, DIALOG_DIMENSION, colorizer);
        this.firstQuestion = firstQuestion;
        this.firstPresetting = firstPresetting;
        this.secondQuestion = secondQuestion;
        this.secondPresetting = secondPresetting;

        firstValueField = new JTextField();
        secondValueField = new JTextField();

        fillDialog();

        addClosingWindowListener(() -> escape());
    }

    /** Erstellt die Dialog-Gui. */
    @Override
    protected void populateDialog() {
        add(createMainFrame(), BorderLayout.CENTER);

        setKeyBindings();
    }

    private Component createMainFrame() {
        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(2, 0, 5, 5));

        panel.add(createFirstPart());
        panel.add(createSecondPart());

        return panel;
    }

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

        panel.add(createFirstQuestionPart(), BorderLayout.CENTER);
        panel.add(createEnterFirstValuePart(), BorderLayout.SOUTH);

        return panel;
    }

    private Component createFirstQuestionPart() {
        JLabel label = new JLabel(firstQuestion);
        setColors(label);

        return label;
    }

    private Component createEnterFirstValuePart() {
        setColors(firstValueField);
        firstValueField.setCaretColor(Color.RED);
        firstValueField.addKeyListener(new KeyListener() {
            @Override
            public void keyPressed(KeyEvent arg0) {
            }
            @Override
            public void keyReleased(KeyEvent event) {
                if (KeyEvent.VK_ENTER == event.getKeyCode()) {
                    secondValueField.requestFocus();
                }
            }
            @Override
            public void keyTyped(KeyEvent arg0) {
            }
        });
        firstValueField.setText(firstPresetting);
        firstValueField.selectAll();
        return firstValueField;
    }

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

        panel.add(createSecondQuestionPart(), BorderLayout.CENTER);
        panel.add(createEnterSecondValuePart(), BorderLayout.SOUTH);

        return panel;
    }

    private Component createSecondQuestionPart() {
        JLabel label = new JLabel(secondQuestion);
        setColors(label);

        return label;
    }

    private Component createEnterSecondValuePart() {
        setColors(secondValueField);
        secondValueField.setCaretColor(Color.RED);
        secondValueField.addKeyListener(new KeyListener() {
            @Override
            public void keyPressed(KeyEvent arg0) {
            }
            @Override
            public void keyReleased(KeyEvent event) {
                if (KeyEvent.VK_ENTER == event.getKeyCode()) {
                    applyDialog();
                }
            }
            @Override
            public void keyTyped(KeyEvent arg0) {
            }
        });
        secondValueField.setText(secondPresetting);
        secondValueField.selectAll();
        return secondValueField;
    }

    private void setKeyBindings() {
        setKeyBindingEscape(() -> escape());
    }

    private void escape() {
        firstValueField.setText(""); // Leer bei Abbruch
        secondValueField.setText(""); // Leer bei Abbruch
        applyOk = false;
        closeDialog();
    }

    private void applyDialog() {
        applyOk = false;
        apply();
        if (applyOk) {
            closeDialog();
        }
    }

    /**
     * Der Aufrufer muss apply() überschreiben, er kann mit getFirstValue() und mit
     * getSecondValue() die Werte aufrufen. Mit applyFailure(String message) wird das schließen des
     * Dialogs verhindert. Mit applyOK() wird angezeigt, dass alles in Ordnung ist. Der Dialog wird
     * beendet und mit getFirstValue() und mit getSecondValue() können nun die verifizierten Werte
     * abgefragt werden.
     */
    protected abstract void apply();

    protected void applyFailure(String message) {
        createErrorHandler().error(message);
        applyOk = false;
    }

    protected void applyOk() {
        applyOk = true;
    }

    /** Getter für den ersten vom Benutzer eingegebenen Wert. */
    public String getFirstValue() {
        return firstValueField.getText().trim();
    }

    /** Getter für den zweiten vom Benutzer eingegebenen Wert. */
    public String getSecondValue() {
        return secondValueField.getText().trim();
    }

    /** Gibt an, ob der Dialog regulär und mit bestandener Prüfung der Werte beendet wurde. */
    public boolean isApplyOk() {
        return applyOk;
    }

}
