package be.iminds.ilabt.jfed;

import javafx.animation.*;
import javafx.application.Platform;
import javafx.application.Preloader;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.effect.BoxBlur;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.scene.transform.Scale;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration;

import java.util.Calendar;
import java.util.Random;

/**
 * User: twalcari
 * Date: 7/15/2014
 * Time: 15:42
 */
public class JFedPreloader extends Preloader {
    private static final Random RAND = new Random();
    private static final int HEIGHT = 250;
    private static final String MESSAGE_LOADING_RESOURCES = "Loading resources";
    private static final String MESSAGE_INITALIZING = "Initializing";

    private Stage stage;
    private Scene scene;

    private final Pane root;
    private final Label progressLabel = new Label(MESSAGE_LOADING_RESOURCES);
    private final ProgressBar progressBar = new ProgressBar(0);

    private static final int WIDTH = 400;
    private static final int PROGRESSBAR_HEIGHT = 4;

    private final BoxBlur boxBlur = new BoxBlur(10, 3, 3);
    private final DropShadow glow = new DropShadow(1, 0, 0, Color.YELLOW);
    private final String[] paths = new String[]{"M -184.00,170.00\n" +
                                                        "           C -184.00,170.00 -99.00,94.00 20.00,122.00\n" +
                                                        "             139.00,150.00 279.00,235.00 391.00,223.00\n" +
                                                        "             503.00,211.00 691.00,101.00 691.00,101.00",
                                                "M -84.00,221.00\n" +
                                                        "           C -84.00,221.00 148.00,164.00 236.00,167.00\n" +
                                                        "             324.00,170.00 408.00,206.00 489.00,205.00\n" +
                                                        "             570.00,204.00 712.00,189.00 733.00,177.00",
                                                "M -157.00,249.00\n" +
                                                        "           C -157.00,249.00 5.00,184.00 93.00,187.00\n" +
                                                        "             181.00,190.00 381.00,227.00 462.00,226.00\n" +
                                                        "             543.00,225.00 712.00,189.00 733.00,177.00",
                                                "M -170.00,205.00\n" +
                                                        "           C -170.00,205.00 -6.00,151.00 113.00,179.00\n" +
                                                        "             232.00,207.00 341.00,218.00 453.00,206.00\n" +
                                                        "             565.00,194.00 688.00,145.00 688.00,145.00",
                                                "M -148.00,220.00\n" +
                                                        "           C -148.00,220.00 -10.00,129.00 109.00,157.00\n" +
                                                        "             228.00,185.00 351.00,224.00 463.00,212.00\n" +
                                                        "             575.00,200.00 684.00,171.00 684.00,171.00"};
    private final Color[] colors =
            new Color[]{Color.AQUAMARINE, Color.GOLD, Color.LAWNGREEN, Color.YELLOWGREEN, Color.GREENYELLOW};

    public JFedPreloader() {

        root = new Pane();
        root.getStylesheets().add(getClass().getResource("preloader.css").toExternalForm());
        root.getStyleClass().add("pane");

        Label logoLabel = new Label("jFed");
        logoLabel.getStyleClass().add("title");

        Image logo = new Image(getClass().getResource("jfed-logo_64.png").toExternalForm());
        ImageView logoImageView = new ImageView(logo);
        logoLabel.setGraphic(logoImageView);
        progressLabel.getStyleClass().add("progress-message");

        Label copyrightLabel = new Label(String.format("© 2012-%d iMinds vzw. Available under MIT license.",
                Calendar.getInstance().get(Calendar.YEAR)));
        copyrightLabel.getStyleClass().add("copyright");

        progressBar.setPrefHeight(PROGRESSBAR_HEIGHT);
        progressBar.setPrefWidth(WIDTH);


        root.getChildren().addAll(logoLabel, progressLabel, copyrightLabel, progressBar);
        progressBar.relocate(0, HEIGHT - PROGRESSBAR_HEIGHT);
        progressLabel.relocate(120, 140);
        copyrightLabel.relocate(10, HEIGHT - PROGRESSBAR_HEIGHT - 25);


        //add background animations
        for (int i = 0; i < paths.length; i++) {
            SVGPath path = new SVGPath();
            path.setContent(paths[i]);
            path.setStroke(colors[i]);
            path.setFill(Color.TRANSPARENT);
            path.setEffect(boxBlur);
            path.getTransforms().addAll(new Translate(0, 40), new Scale(.6, .6));

            Circle circle = new Circle(0, 0, 2, colors[i]);
            circle.setEffect(glow);

            root.getChildren().add(0, circle);
            root.getChildren().add(0, path);

            PathTransition transition = new PathTransition(Duration.seconds(5 + RAND.nextDouble() * 5), path, circle);
            transition.setCycleCount(Animation.INDEFINITE);
            transition.play();


        }

        //initialize animations

//        RotateTransition logoRotateTransition = new RotateTransition(Duration.seconds(1.5), logoImageView);
//        logoRotateTransition.setByAngle(360);
//        logoRotateTransition.setAutoReverse(true);
//        logoRotateTransition.setCycleCount(Transition.INDEFINITE);

        FadeTransition fadeTransition = new FadeTransition(Duration.seconds(1.3), logoLabel);
        fadeTransition.setFromValue(0);
        fadeTransition.setToValue(1);
        fadeTransition.setInterpolator(Interpolator.EASE_OUT);

        Path path = new Path();
        path.getElements().add(new MoveTo(250, 100));
        path.getElements().add(new HLineTo(190));
        PathTransition pathTransition = new PathTransition(Duration.seconds(1.3), path, logoLabel);

        ParallelTransition parallelTransition = new ParallelTransition(fadeTransition, pathTransition);
        //SequentialTransition sequentialTransition = new SequentialTransition(parallelTransition, logoRotateTransition);

        parallelTransition.play();
    }

    /**
     * ====================
     * TESTING PURPOSE ONLY
     * ====================
     *
     * @param stage
     * @throws Exception
     */
    @Override
    public void start(Stage stage) throws Exception {
        this.stage = stage;
        scene = new Scene(root, WIDTH, HEIGHT, Color.WHITE);

        stage.initStyle(StageStyle.UNDECORATED);
        stage.setScene(scene);

        Task<Void> counterTask = new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                while (true) {
                    count++;
                    count %= 4;

                    Platform.runLater(() -> updateProgressMessage());

                    Thread.sleep(800);
                }
            }


        };

        Thread counterThread = new Thread(counterTask);
        counterThread.setDaemon(true);
        counterThread.start();
    }

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

    @Override
    public void handleProgressNotification(ProgressNotification pn) {
        if (pn.getProgress() != 1 && !stage.isShowing()) {
            stage.show();
        }
        progressBar.setProgress(pn.getProgress());
    }

    @Override
    public void handleStateChangeNotification(StateChangeNotification stateChangeNotification) {
        if (stateChangeNotification.getType() == StateChangeNotification.Type.BEFORE_LOAD) {
            currentProgressMessage = MESSAGE_LOADING_RESOURCES;
            updateProgressMessage();
        } else if (stateChangeNotification.getType() == StateChangeNotification.Type.BEFORE_INIT) {
            currentProgressMessage = MESSAGE_INITALIZING;
            updateProgressMessage();
        } else {
            if (stage.isShowing()) {
                //fade out, hide stage at the end of animation
                FadeTransition ft = new FadeTransition(
                        Duration.millis(1000), stage.getScene().getRoot());
                ft.setFromValue(1.0);
                ft.setToValue(0.0);
                final Stage s = stage;
                EventHandler<ActionEvent> eh = t -> s.hide();
                ft.setOnFinished(eh);
                ft.play();

            } else {

                stage.hide();
            }
        }
    }

    @Override
    public void handleApplicationNotification(PreloaderNotification preloaderNotification) {
        super.handleApplicationNotification(preloaderNotification);
    }

    private int count = 0;
    private String currentProgressMessage = MESSAGE_LOADING_RESOURCES;

    private void updateProgressMessage() {
        StringBuilder sb = new StringBuilder(currentProgressMessage);
        for (int i = 0; i < count; i++) {
            sb.append('.');
        }
        progressLabel.setText(sb.toString());
    }
}
