package visualiser.Controllers;


import javafx.application.Platform;
import javafx.beans.property.Property;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Circle;
import shared.model.Bearing;
import shared.model.Wind;

/**
 * Controller for the arrow.fxml view.
 */
public class ArrowController {


    @FXML
    private Pane compass;

    @FXML
    private StackPane arrowStackPane;

    @FXML
    private ImageView arrowImage;

    @FXML
    private Circle circle;

    @FXML
    private Label northLabel;

    @FXML
    private Label windLabel;

    @FXML
    private Label speedLabel;


    /**
     * This is the property our arrow control binds to.
     */
    private Property<Wind> wind;


    /**
     * Constructor.
     */
    public ArrowController() {
    }


    /**
     * Sets which wind property the arrow control should bind to.
     * @param wind The wind property to bind to.
     */
    public void setWindProperty(Property<Wind> wind) {
        this.wind  = wind;

        wind.addListener((observable, oldValue, newValue) -> {
            if (newValue != null) {
                Platform.runLater(() -> updateWind(newValue));
            }
        });
    }


    /**
     * Updates the control to use the new wind value.
     * This updates the arrow direction (due to bearing), arrow length (due to speed), and label (due to speed).
     * @param wind The wind value to use.
     */
    private void updateWind(Wind wind) {
        updateWindBearing(wind.getWindDirection());
        updateWindSpeed(wind.getWindSpeed());
    }


    /**
     * Updates the control to account for the new wind speed.
     * This changes the length (height) of the wind arrow, and updates the speed label.
     * @param speedKnots The new wind speed, in knots.
     */
    private void updateWindSpeed(double speedKnots) {
        updateWindArrowLength(speedKnots);
        updateWindSpeedLabel(speedKnots);
    }

    /**
     * Updates the length of the wind arrow according to the specified wind speed.
     * @param speedKnots Wind speed, in knots.
     */
    private void updateWindArrowLength(double speedKnots) {

        //At 2 knots, the arrow reaches its minimum height, and at 30 knots it reaches its maximum height.
        double minKnots = 2;
        double maxKnots = 30;
        double deltaKnots = maxKnots - minKnots;

        double minHeight = 25;
        double maxHeight = 75;
        double deltaHeight = maxHeight - minHeight;

        //Clamp speed.
        if (speedKnots > maxKnots) {
            speedKnots = maxKnots;
        } else if (speedKnots < minKnots) {
            speedKnots = minKnots;
        }

        //How far between the knots bounds is the current speed?
        double currentDeltaKnots = speedKnots - minKnots;
        double currentKnotsScalar = currentDeltaKnots / deltaKnots;

        //Thus, how far between the pixel height bounds should the arrow height be?
        double newHeight = minHeight + (currentKnotsScalar * deltaHeight);

        arrowImage.setFitHeight(newHeight);
    }

    /**
     * Updates the wind speed label according to the specified wind speed.
     * @param speedKnots Wind speed, in knots.
     */
    private void updateWindSpeedLabel(double speedKnots) {
        speedLabel.setText(String.format("%.1fkn", speedKnots));
    }


    /**
     * Updates the control to account for a new wind bearing.
     * This rotates the arrow according to the bearing.
     * @param bearing The bearing to use to rotate arrow.
     */
    private void updateWindBearing(Bearing bearing) {

        //We need to display wind-from, so add 180 degrees.
        Bearing fromBearing = Bearing.fromDegrees(bearing.degrees() + 180d);

        //Rotate the wind arrow.
        arrowStackPane.setRotate(fromBearing.degrees());
    }




}
