package org.fxmisc.flowless;

import javafx.scene.Node;
import javafx.scene.layout.Region;
import javafx.scene.transform.Scale;
import org.reactfx.value.Val;
import org.reactfx.value.Var;

/**
 * Acts as an intermediate class between {@link VirtualizedScrollPane} and
 * its {@link Virtualized} content in that it scales the content without
 * also scaling the ScrollPane's scroll bars.
 * <pre>
 *     {@code
 *     Virtualized actualContent = // creation code
 *     ScaledVirtualized<Virtualized> wrapper = new ScaledVirtualized(actualContent);
 *     VirtualizedScrollPane<ScaledVirtualized> vsPane = new VirtualizedScrollPane(wrapper);
 *
 *     // To scale actualContent without also scaling vsPane's scrollbars:
 *     wrapper.scaleProperty().setY(3);
 *     wrapper.scaleProperty().setX(2);
 *     }
 * </pre>
 * @param <V> the {@link Virtualized} content to be scaled when inside a {@link VirtualizedScrollPane}
 */
public class ScaledVirtualized<V extends Node & Virtualized> extends Region implements Virtualized {
    private final V content;
    private Scale scale = new Scale();

    private Val<Double> estHeight;
    private Val<Double> estWidth;
    private Var<Double> estScrollX;
    private Var<Double> estScrollY;

    public ScaledVirtualized(V content) {
        super();
        this.content = content;
        getChildren().add(content);
        getTransforms().add(scale);

        estHeight = Val.combine(
                content.totalHeightEstimateProperty(),
                scale.yProperty(),
                (estHeight, scaleFactor) -> estHeight * scaleFactor.doubleValue()
        );
        estWidth = Val.combine(
                content.totalWidthEstimateProperty(),
                scale.xProperty(),
                (estWidth, scaleFactor) -> estWidth * scaleFactor.doubleValue()
        );
        estScrollX = Var.mapBidirectional(
                content.estimatedScrollXProperty(),
                scrollX -> scrollX * scale.getX(),
                scrollX -> scrollX / scale.getX()
        );
        estScrollY = Var.mapBidirectional(
                content.estimatedScrollYProperty(),
                scrollY -> scrollY * scale.getY(),
                scrollY -> scrollY / scale.getY()
        );

        scale.xProperty()     .addListener((obs, ov, nv) -> layoutChildren());
        scale.yProperty()     .addListener((obs, ov, nv) -> layoutChildren());
        scale.zProperty()     .addListener((obs, ov, nv) -> layoutChildren());
        scale.pivotXProperty().addListener((obs, ov, nv) -> layoutChildren());
        scale.pivotYProperty().addListener((obs, ov, nv) -> layoutChildren());
        scale.pivotZProperty().addListener((obs, ov, nv) -> layoutChildren());
    }

    @Override
    protected void layoutChildren() {
        double width = getLayoutBounds().getWidth();
        double height = getLayoutBounds().getHeight();
        content.resize(width / scale.getX(), height/ scale.getY());
    }

    @Override
    public Var<Double> estimatedScrollXProperty() {
        return estScrollX;
    }

    @Override
    public Var<Double> estimatedScrollYProperty() {
        return estScrollY;
    }

    @Override
    public Val<Double> totalHeightEstimateProperty() {
        return estHeight;
    }

    @Override
    public Val<Double> totalWidthEstimateProperty() {
        return estWidth;
    }

    public Scale scaleProperty() {
        return scale;
    }
}

@@ -2293,38 +2293,37 @@
  ov, nv) -%3E 
-layoutChildren
+requestLayout
 ());%0A       
@@ -2371,38 +2371,37 @@
  ov, nv) -%3E 
-layoutChildren
+requestLayout
 ());%0A       
@@ -2449,38 +2449,37 @@
  ov, nv) -%3E 
-layoutChildren
+requestLayout
 ());%0A       
@@ -2527,38 +2527,37 @@
  ov, nv) -%3E 
-layoutChildren
+requestLayout
 ());%0A       
@@ -2605,38 +2605,37 @@
  ov, nv) -%3E 
-layoutChildren
+requestLayout
 ());%0A       
@@ -2687,30 +2687,29 @@
  nv) -%3E 
-layoutChildren
+requestLayout
 ());%0A   
@@ -3366,29 +3366,24 @@
 c Scale 
-scaleProperty
+getScale
 () %7B%0A   

Use correct layout method; rename scale's getter to getScale()