import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.ListChangeListener;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

/**
 * Demonstrates the bug in which {@code Parent.children} fails to set the flag to recompute
 * {@code Parent.viewOrderChildren} when {@link Node#toFront()} changes the children order
 * while children have nonzero {@link Node#viewOrderProperty()}.
 **/
public class NodeToFrontBugDemo extends Application {

   @Override
   public void start( final Stage primaryStage ) throws Exception {
      final CheckBox workaroundCheckBox = new CheckBox( "Apply bug workaround after toFront()" );
      workaroundCheckBox.setLayoutX( 200 );
      workaroundCheckBox.setLayoutY( 300 );
      final Button button1 = new Button();
      button1.setViewOrder( -1 );
      button1.setOnAction( __ -> {
         button1.toFront();
         if( workaroundCheckBox.isSelected() ) {
            // Temporarily change node's view order, then change it back.
            // This causes a call to Parent.markViewOrderChildrenDirty().
            button1.setViewOrder( 0 );
            button1.setViewOrder( -1 );
         }
      } );
      final Button button2 = new Button();
      button2.setViewOrder( -1 );
      button2.setOnAction( __ -> {
         button2.toFront();
         if( workaroundCheckBox.isSelected() ) {
            // Temporarily change node's view order, then change it back.
            // This causes a call to Parent.markViewOrderChildrenDirty().
            button2.setViewOrder( 0 );
            button2.setViewOrder( -1 );
         }
      } );
      final Pane pane = new Pane( workaroundCheckBox, button1, button2 );
      final Runnable button1TextUpdater = () -> button1.setText(
            "Click to bring to front. Children index: "
                  + pane.getChildren().indexOf( button1 ) + ", viewOrder: " + button1.getViewOrder() );
      button1TextUpdater.run();
      pane.getChildrenUnmodifiable().addListener( (ListChangeListener<Node>) __ -> button1TextUpdater.run() );
      button1.viewOrderProperty().addListener( ( __, ___, ____ ) -> button1TextUpdater.run() );
      final Runnable button2TextUpdater = () -> button2.setText(
            "Click to bring to front. Children index: "
                  + pane.getChildren().indexOf( button2 ) + ", viewOrder: " + button2.getViewOrder() );
      button2TextUpdater.run();
      pane.getChildrenUnmodifiable().addListener( (ListChangeListener<Node>) __ -> button2TextUpdater.run() );
      button1.viewOrderProperty().addListener( ( __, ___, ____ ) -> button2TextUpdater.run() );
      primaryStage.setTitle( "Node.toFront() with nonzero viewOrder bug demo" );
      primaryStage.setScene( new Scene( pane, 600, 500 ) );
      primaryStage.show();
      Platform.runLater( () -> {
         button1.setLayoutX( 100 );
         button1.setLayoutY( 200 );
         button2.setLayoutX( 100 + 0.5 * button1.getLayoutBounds().getWidth() );
         button2.setLayoutY( 200 + 0.5 * button1.getLayoutBounds().getHeight() );
      } );
   }

   public static void main( final String[] args ) {
      launch( args );
   }
}