package test.javafx.scene;


import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Node;
import javafx.scene.layout.StackPane;
import javafx.scene.control.Label;
import javafx.scene.Scene;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.skin.ProgressIndicatorSkin;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;

import java.lang.ref.WeakReference;
import java.util.LinkedList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

import junit.framework.Assert;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.assertTrue;
import static test.util.Util.TIMEOUT;
import test.util.Util;
import test.util.memory.JMemoryBuddy;

public class DirtyNodesLeakTest {
    @BeforeClass
    public static void initFX() throws Exception {
        CountDownLatch startupLatch = new CountDownLatch(1);
        Platform.setImplicitExit(false);
        Platform.startup(startupLatch::countDown);
        Assert.assertTrue("Timeout waiting for FX runtime to start",
                startupLatch.await(TIMEOUT, TimeUnit.MILLISECONDS));
    }

    @Test
    public void leakDeterminationIndicator() throws Exception {
        JMemoryBuddy.memoryTest((checker) -> {
            CountDownLatch showingLatch = new CountDownLatch(1);
            Util.runAndWait(() -> {
                Stage stage = new Stage();
                Label label = new Label("Hello!!");
                StackPane root = new StackPane(label);
                Scene scene = new Scene(root);
                stage.setScene(scene);

                checker.setAsReferenced(scene);
                checker.assertCollectable(label);
                stage.setOnShown(l -> {
                    Platform.runLater(() -> {
                        root.getChildren().clear();
                        stage.close();
                        showingLatch.countDown();
                    });
                });
                stage.show();
            });
            try {
                Assert.assertTrue("Timeout waiting for setOnShown", showingLatch.await(15, TimeUnit.SECONDS));
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
    }
}
