////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////

package pp.dialog;

import com.jme3.input.KeyInput;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.TextField;
import com.simsilica.lemur.component.SpringGridLayout;
import com.simsilica.lemur.event.KeyAction;

/**
 * A dialog class that asks for text input. Usually, this is a single-line
 * text input.
 *
 * @see #getInput()
 */
public class TextInputDialog extends SimpleDialog {
    // TextField for user input
    private final TextField input = new TextField("");

    /**
     * Constructs a TextInputDialog associated with the specified dialog manager.
     *
     * @param manager the dialog manager to associate the dialog with
     */
    private TextInputDialog(DialogManager manager) {
        super(manager);
        input.setSingleLine(true); // Set the input field to be single-line
        input.setPreferredWidth(500f); // Set preferred width of the input field
    }

    /**
     * Returns the input field.
     *
     * @return the input field
     */
    public TextField getInput() {
        return input;
    }

    /**
     * Maps the specified key action to trigger a click on the OK button.
     *
     * @param action the key action to map
     */
    private void clickOkOn(KeyAction action) {
        input.getActionMap().put(action, (c, k) -> {
            if (getOkButton() != null)
                getOkButton().click();
        });
    }

    /**
     * Creates a builder for TextInputDialog.
     *
     * @param manager the dialog manager to associate the dialog with
     * @return a TextInputDialogBuilder instance
     */
    public static TextInputDialogBuilder builder(DialogManager manager) {
        return new TextInputDialogBuilder(manager);
    }

    /**
     * A builder class for creating TextInputDialog instances.
     */
    public static class TextInputDialogBuilder extends DialogBuilder<TextInputDialog> {
        private String label;
        private boolean returnHitsOK = true;

        /**
         * Constructs a TextInputDialogBuilder with the specified dialog manager.
         *
         * @param manager the dialog manager to associate the dialog with
         */
        private TextInputDialogBuilder(DialogManager manager) {
            super(manager, TextInputDialog::new);
        }

        /**
         * Extends the dialog with additional components like a label and input field.
         *
         * @param dialog the dialog to be extended
         */
        @Override
        protected void extendDialog(TextInputDialog dialog) {
            final TextField textField = dialog.getInput();
            if (label == null) {
                dialog.addChild(textField);
            }
            else {
                final Container c = dialog.addChild(new Container(new SpringGridLayout()));
                c.addChild(new Label(label));
                c.addChild(textField, 1);
            }
            if (returnHitsOK) {
                // move the caret right so that it becomes visible at the end of a long text
                textField.getDocumentModel().right();
                // Hitting a return key is like pushing the ok button
                dialog.clickOkOn(new KeyAction(KeyInput.KEY_RETURN));
                dialog.clickOkOn(new KeyAction(KeyInput.KEY_NUMPADENTER));
            }
        }

        /**
         * Sets the label for the input field.
         *
         * @param label the label text
         * @return this builder instance for chaining
         */
        public TextInputDialogBuilder setLabel(String label) {
            this.label = label;
            return this;
        }

        /**
         * Sets whether hitting the return key triggers the OK button.
         *
         * @param returnHitsOK true to trigger OK button on return key, false otherwise
         * @return this builder instance for chaining
         */
        public TextInputDialogBuilder setReturnHitsOK(boolean returnHitsOK) {
            this.returnHitsOK = returnHitsOK;
            return this;
        }
    }
}
