package ctbrec.ui.controls;

import java.io.File;
import java.io.IOException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ctbrec.StringUtil;
import ctbrec.ui.AutosizeAlert;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.Border;
import javafx.scene.layout.BorderStroke;
import javafx.scene.layout.BorderStrokeStyle;
import javafx.scene.layout.BorderWidths;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.paint.Color;
import javafx.stage.FileChooser;

public abstract class AbstractFileSelectionBox extends HBox {

    private static final Logger LOG = LoggerFactory.getLogger(AbstractFileSelectionBox.class);

    private StringProperty fileProperty = new SimpleStringProperty();
    protected TextField fileInput;
    protected boolean allowEmptyValue = false;
    private Tooltip validationError = new Tooltip();

    public AbstractFileSelectionBox() {
        super(5);
        fileInput = new TextField();
        fileInput.textProperty().addListener(textListener());
        fileInput.focusedProperty().addListener((obs, o, n) -> {
            if (!n.booleanValue()) {
                validationError.hide();
            }
        });
        Node browse = createBrowseButton();
        getChildren().addAll(fileInput, browse);
        fileInput.disableProperty().bind(disableProperty());
        browse.disableProperty().bind(disableProperty());
        HBox.setHgrow(fileInput, Priority.ALWAYS);

        disabledProperty().addListener((obs, oldV, newV) -> {
            if (newV.booleanValue()) {
                hideValidationHints();
            } else {
                if (StringUtil.isNotBlank(fileInput.getText())) {
                    setFile(new File(fileInput.getText()));
                }
            }
        });
    }

    public AbstractFileSelectionBox(String initialValue) {
        this();
        fileInput.setText(initialValue);
    }

    private ChangeListener<? super String> textListener() {
        return (obs, o, n) -> {
            String input = fileInput.getText();
            if (StringUtil.isBlank(input) && allowEmptyValue) {
                fileProperty.set("");
                hideValidationHints();
                return;
            } else {
                File program = new File(input);
                setFile(program);
            }
        };
    }

    protected void setFile(File file) {
        String msg = validate(file);
        if (msg != null) {
            fileInput.setBorder(new Border(new BorderStroke(Color.RED, BorderStrokeStyle.DASHED, new CornerRadii(2), new BorderWidths(2))));
            validationError.setText(msg);
            fileInput.setTooltip(validationError);
            Point2D p = fileInput.localToScreen(fileInput.getTranslateY(), fileInput.getTranslateY());
            if (!validationError.isShowing() && getScene() != null) {
                validationError.show(getScene().getWindow(), p.getX(), p.getY() + fileInput.getHeight() + 4);
            }
        } else {
            fileProperty.set(file.getAbsolutePath());
            hideValidationHints();
        }
    }

    private void hideValidationHints() {
        fileInput.setBorder(Border.EMPTY);
        fileInput.setTooltip(null);
        validationError.hide();
    }

    protected String validate(File file) {
        if (isDisabled()) {
            return null;
        }

        if (file == null || !file.exists()) {
            return "File does not exist";
        } else {
            return null;
        }
    }

    public void allowEmptyValue() {
        this.allowEmptyValue = true;
    }

    private Button createBrowseButton() {
        Button button = new Button("Select");
        button.setOnAction(e -> choose());
        return button;
    }

    protected void choose() {
        FileChooser chooser = new FileChooser();
        File program = chooser.showOpenDialog(null);
        if (program != null) {
            try {
                fileInput.setText(program.getCanonicalPath());
            } catch (IOException e1) {
                LOG.error("Couldn't determine path", e1);
                Alert alert = new AutosizeAlert(Alert.AlertType.ERROR, getScene());
                alert.setTitle("Whoopsie");
                alert.setContentText("Couldn't determine path");
                alert.showAndWait();
            }
            setFile(program);
        }
    }

    public StringProperty fileProperty() {
        return fileProperty;
    }
}
