/*
 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package be.iminds.ilabt.jfed.experimenter_gui.ui;

import com.sun.javafx.scene.control.skin.resources.ControlResources;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.StringProperty;
import javafx.css.PseudoClass;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.ButtonBar.ButtonData;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;

/**
 * A dialog that shows a text input control to the user.
 *
 * @see Dialog
 * @since JavaFX 8u40
 */
public class ConfirmingPasswordInputDialog extends Dialog<String> {
    private static final PseudoClass ERROR_PSEUDO_CLASS = PseudoClass.getPseudoClass("error");

    /**************************************************************************
     * Fields
     **************************************************************************/

    private final GridPane grid;
    private final Label label;
    private final Label label1;
    private final Label label2;
    private final PasswordField passwordField1;
    private final PasswordField passwordField2;
    private final IntegerProperty minimumPasswordSize = new SimpleIntegerProperty(4);

    private final BooleanBinding invalidPassword1Length;
    private final BooleanBinding validLengthPasswordBinding;
    private final BooleanBinding matchingPasswordBinding;


    /**************************************************************************
     *
     * Constructors
     *
     **************************************************************************/


    /**
     * Creates a new PasswordInputDialog.
     */
    public ConfirmingPasswordInputDialog() {
        final DialogPane dialogPane = getDialogPane();
        dialogPane.getStylesheets().add(getClass().getResource("confirming-password.css").toExternalForm());

        // -- passwordField1
        this.passwordField1 = new PasswordField();
        this.passwordField1.setMaxWidth(Double.MAX_VALUE);
        GridPane.setHgrow(passwordField1, Priority.ALWAYS);
        GridPane.setFillWidth(passwordField1, true);

        this.passwordField2 = new PasswordField();
        this.passwordField2.setMaxWidth(Double.MAX_VALUE);
        GridPane.setHgrow(passwordField2, Priority.ALWAYS);
        GridPane.setFillWidth(passwordField2, true);

        // -- label
        label = createContentLabel(dialogPane.getContentText());
        label.setPrefWidth(Region.USE_COMPUTED_SIZE);
        label.textProperty().bind(dialogPane.contentTextProperty());

        label1 = createContentLabel("Password:");
        label1.setPrefWidth(Region.USE_COMPUTED_SIZE);
        label1.setAlignment(Pos.BASELINE_RIGHT);

        label2 = createContentLabel("Confirm:");
        label2.setPrefWidth(Region.USE_COMPUTED_SIZE);
        label2.setAlignment(Pos.BASELINE_RIGHT);

        this.grid = new GridPane();
        this.grid.setHgap(10);
        this.grid.setVgap(5);
        this.grid.setMaxWidth(Double.MAX_VALUE);
        this.grid.setAlignment(Pos.CENTER_LEFT);

        dialogPane.contentTextProperty().addListener(o -> updateGrid());

        setTitle(ControlResources.getString("Dialog.confirm.title"));
        dialogPane.setHeaderText(ControlResources.getString("Dialog.confirm.header"));
        dialogPane.getStyleClass().add("text-input-dialog");
        dialogPane.getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);

        updateGrid();

        setResultConverter((dialogButton) -> {
            ButtonData data = dialogButton == null ? null : dialogButton.getButtonData();
            return data == ButtonData.OK_DONE ? passwordField1.getText() : null;
        });

        Node okButton = getDialogPane().lookupButton(ButtonType.OK);


        invalidPassword1Length = Bindings.length(passwordField1.textProperty()).lessThan(minimumPasswordSize);
        invalidPassword1Length.addListener(observable -> passwordField1.pseudoClassStateChanged(ERROR_PSEUDO_CLASS, invalidPassword1Length.get()));

        validLengthPasswordBinding =
                Bindings.length(passwordField1.textProperty()).greaterThanOrEqualTo(minimumPasswordSize);
        matchingPasswordBinding = Bindings.equal(passwordField1.textProperty(), passwordField2.textProperty());

        okButton.disableProperty().bind(validLengthPasswordBinding.not().or(matchingPasswordBinding.not()));

        matchingPasswordBinding.addListener(observable -> passwordField2.pseudoClassStateChanged(ERROR_PSEUDO_CLASS, !matchingPasswordBinding.get()));


    }


    /**
     * Creates a Label node that works well within a Dialog.
     *
     * @param text The text to display
     */
    static Label createContentLabel(String text) {
        Label label = new Label(text);
        label.setMaxWidth(Double.MAX_VALUE);
        label.setMaxHeight(Double.MAX_VALUE);
        label.getStyleClass().add("content");
        label.setWrapText(true);
        label.setPrefWidth(360);
        return label;
    }


    /**************************************************************************
     *
     * Public API
     *
     **************************************************************************/

    /**
     * Returns the {@link PasswordField} used within this dialog.
     */
    public final PasswordField getEditor() {
        return passwordField1;
    }

    public void setConfirmText(String text) {
        label2.setText(text);
    }

    public String getConfirmText() {
        return label2.getText();
    }

    public StringProperty confirmTextProperty() {
        return label2.textProperty();
    }


    /**************************************************************************
     * Private Implementation
     **************************************************************************/

    private void updateGrid() {
        grid.getChildren().clear();

        grid.add(label, 0, 0, 2, 1);
        grid.add(label1, 0, 1);
        grid.add(passwordField1, 1, 1);
        grid.add(label2, 0, 2);
        grid.add(passwordField2, 1, 2);
        getDialogPane().setContent(grid);

        Platform.runLater(passwordField1::requestFocus);
    }
}
