import javafx.animation.FadeTransition;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Cursor;
import javafx.scene.Scene;
import javafx.scene.effect.DropShadow;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Polygon;
import javafx.stage.Stage;
import javafx.util.Duration;

import static javafx.application.Application.launch;
import static javafx.scene.paint.Color.*;

/**
 * Displays a triangle with a linear gradient and a fade transition. The corners are
 * selected by the user through mouse clicks. The triangle can be dragged by the mouse.
 *
 * @author Drue Coles
 */
public class GlowingTriangle2 extends Application {

    private final Polygon triangle = new Polygon();

    // Coordinates of the mouse cursor during drag events.
    private double cursorX;
    private double cursorY;

    @Override
    public void start(Stage primaryStage) {

        // Create an empty black scene and add it to the stage.
        Pane root = new Pane();
        final int size = 500;
        Scene scene = new Scene(root, size, size, PALEGREEN);
        primaryStage.setTitle("Glowing Triangle");
        primaryStage.setScene(scene);
        primaryStage.show();

        // Add a drop shadow
        DropShadow dropShadow = new DropShadow();
        dropShadow.setOffsetY(5.0);
        dropShadow.setOffsetX(5.0);
        dropShadow.setColor(GRAY);
        triangle.setEffect(dropShadow);

        root.setOnMouseClicked(event -> {
            // Add point to polygon at location of the mouse click.
            double x = event.getX();
            double y = event.getY();
            triangle.getPoints().addAll(x, y);

            // If fewer than three points have been added, draw a dot at the location
            // of the mouse click. Otherwise, remove the two dots, remove this event
            // handler, and add the triangle to the scene.
            if (triangle.getPoints().size() < 6) {
                Circle dot = new Circle(x, y, 4);
                dot.setFill(BLACK);
                root.getChildren().add(dot);
            } else {
                root.getChildren().clear();
                triangle.setFill(getLinearGradient(ORANGE, MAROON));
                getFadeTransition().play();
                root.setOnMouseClicked(null);
                root.getChildren().add(triangle);
            }
        });

        triangle.setOnMouseDragged(event -> {
            triangle.setTranslateX(event.getSceneX() - cursorX);
            triangle.setTranslateY(event.getSceneY() - cursorY);
        });

        triangle.setOnMousePressed(event -> {
            triangle.setCursor(Cursor.MOVE);
            cursorX = event.getSceneX() - cursorX;
            cursorY = event.getSceneY() - cursorY;
        });

        triangle.setOnMouseReleased(event -> {
            triangle.setCursor(Cursor.DEFAULT);
            cursorX = event.getSceneX() - cursorX;
            cursorY = event.getSceneY() - cursorY;
        });
    }

    /**
     * Returns a fade transition configured for the triangle.
     */
    private FadeTransition getFadeTransition() {
        FadeTransition ft = new FadeTransition(Duration.millis(1250), triangle);
        ft.setFromValue(1.0);
        ft.setToValue(0.5);
        ft.setCycleCount(Timeline.INDEFINITE);
        ft.setAutoReverse(true);
        return ft;
    }

    /**
     * Returns a linear gradient starting and ending with given colors.
     */
    private LinearGradient getLinearGradient(Color startColor, Color endColor) {
        Stop[] stops = new Stop[2];
        stops[0] = new Stop(0, startColor);
        stops[1] = new Stop(1, endColor);

        // (0, 0) and (1, 1) are scaled coordinates with respect to the 
        // bounding box of the shape to which this gradient is applied. 
        return new LinearGradient(0, 0, 1, 1, true, CycleMethod.NO_CYCLE, stops);
    }

    public static void main(String[] args) {
        launch(args);
    }
}