package com.yahoo.sketches.tuple;

import org.testng.Assert;
import org.testng.annotations.Test;

import java.util.Random;

public class FilterTest {

    private final int numberOfElements = 100;

    @Test
    public void emptySketch() {
        Sketch<DoubleSummary> sketch = Sketches.createEmptySketch();

        Filter<DoubleSummary> filter = new Filter<>(o -> true);

        Sketch<DoubleSummary> filteredSketch = filter.filter(sketch);

        Assert.assertEquals(filteredSketch.getEstimate(), 0.0);
        Assert.assertEquals(filteredSketch.getThetaLong(), sketch.getThetaLong());
        Assert.assertTrue(filteredSketch.isEmpty());
        Assert.assertEquals(filteredSketch.getLowerBound(1), 0.0);
        Assert.assertEquals(filteredSketch.getUpperBound(1), 0.0);
    }

    @Test
    public void nullSketch() {
        Filter<DoubleSummary> filter = new Filter<>(o -> true);

        Sketch<DoubleSummary> filteredSketch = filter.filter(null);

        Assert.assertEquals(filteredSketch.getEstimate(), 0.0);
        Assert.assertEquals(filteredSketch.getThetaLong(), Long.MAX_VALUE);
        Assert.assertTrue(filteredSketch.isEmpty());
        Assert.assertEquals(filteredSketch.getLowerBound(1), 0.0);
        Assert.assertEquals(filteredSketch.getUpperBound(1), 0.0);
    }

    @Test
    public void filledSketchShouldBehaveTheSame() {
        UpdatableSketch<Double, DoubleSummary> sketch = new UpdatableSketchBuilder<>(new DoubleSummaryFactory()).build();

        fillSketch(sketch, numberOfElements, 0.0);

        Filter<DoubleSummary> filter = new Filter<>(o -> true);

        Sketch<DoubleSummary> filteredSketch = filter.filter(sketch);

        Assert.assertEquals(filteredSketch.getEstimate(), sketch.getEstimate());
        Assert.assertEquals(filteredSketch.getThetaLong(), sketch.getThetaLong());
        Assert.assertFalse(filteredSketch.isEmpty());
        Assert.assertEquals(filteredSketch.getLowerBound(1), sketch.getLowerBound(1));
        Assert.assertEquals(filteredSketch.getUpperBound(1), sketch.getUpperBound(1));
    }

    @Test
    public void filledSketchShouldFilterOutElements() {
        UpdatableSketch<Double, DoubleSummary> sketch = new UpdatableSketchBuilder<>(new DoubleSummaryFactory()).build();

        fillSketch(sketch, numberOfElements, 0.0);
        fillSketch(sketch, 2 * numberOfElements, 1.0);

        Filter<DoubleSummary> filter = new Filter<>(o -> o.getValue() < 0.5);

        Sketch<DoubleSummary> filteredSketch = filter.filter(sketch);

        Assert.assertEquals(filteredSketch.getEstimate(), (double) numberOfElements);
        Assert.assertEquals(filteredSketch.getThetaLong(), sketch.getThetaLong());
        Assert.assertFalse(filteredSketch.isEmpty());
        Assert.assertTrue(filteredSketch.getLowerBound(1) <= filteredSketch.getEstimate());
        Assert.assertTrue(filteredSketch.getUpperBound(1) >= filteredSketch.getEstimate());
    }

    @Test
    public void filteringInEstimationMode() {
        UpdatableSketch<Double, DoubleSummary> sketch = new UpdatableSketchBuilder<>(new DoubleSummaryFactory()).build();

        int n = 10000;
        fillSketch(sketch, n, 0.0);
        fillSketch(sketch, 2 * n, 1.0);

        Filter<DoubleSummary> filter = new Filter<>(o -> o.getValue() < 0.5);

        Sketch<DoubleSummary> filteredSketch = filter.filter(sketch);

        Assert.assertEquals(filteredSketch.getEstimate(), n, n * 0.05);
        Assert.assertEquals(filteredSketch.getThetaLong(), sketch.getThetaLong());
        Assert.assertFalse(filteredSketch.isEmpty());
        Assert.assertTrue(filteredSketch.getLowerBound(1) <= filteredSketch.getEstimate());
        Assert.assertTrue(filteredSketch.getUpperBound(1) >= filteredSketch.getEstimate());
    }

    @Test
    public void nonEmptySketchWithNoEntries() {
      UpdatableSketch<Double, DoubleSummary> sketch = new UpdatableSketchBuilder<>(new DoubleSummaryFactory()).setSamplingProbability(0.0001f).build();
      sketch.update(0, 0.0);

      Assert.assertFalse(sketch.isEmpty());
      Assert.assertEquals(sketch.getRetainedEntries(), 0);

      Filter<DoubleSummary> filter = new Filter<>(o -> true);

      Sketch<DoubleSummary> filteredSketch = filter.filter(sketch);

      Assert.assertFalse(filteredSketch.isEmpty());
      Assert.assertEquals(filteredSketch.getEstimate(), sketch.getEstimate());
      Assert.assertEquals(filteredSketch.getThetaLong(), sketch.getThetaLong());
      Assert.assertEquals(filteredSketch.getLowerBound(1), sketch.getLowerBound(1));
      Assert.assertEquals(filteredSketch.getUpperBound(1), sketch.getUpperBound(1));
    }

    private static void fillSketch(UpdatableSketch<Double, DoubleSummary> sketch, int numberOfElements, Double sketchValue) {
        Random random = new Random();

        for (int cont = 0; cont < numberOfElements; cont++) {
            sketch.update(random.nextLong(), sketchValue);
        }
    }
}
@@ -28,16 +28,42 @@
 tuple;%0A%0A
+import java.util.Random;%0A%0A
 import o
@@ -121,34 +121,8 @@
 t;%0A%0A
-import java.util.Random;%0A%0A
 publ
@@ -156,16 +156,23 @@
 private 
+static 
 final in
@@ -196,16 +196,102 @@
 s = 100;
+%0A    private static final Random random = new Random(1);//deterministic for this class
 %0A%0A    @T
@@ -1491,32 +1491,44 @@
 ummary%3E sketch =
+%0A           
  new UpdatableSk
@@ -2279,32 +2279,44 @@
 ummary%3E sketch =
+%0A           
  new UpdatableSk
@@ -3141,32 +3141,44 @@
 ummary%3E sketch =
+%0A           
  new UpdatableSk
@@ -3990,16 +3990,26 @@
 sketch =
+%0A         
  new Upd
@@ -4022,32 +4022,47 @@
 SketchBuilder%3C%3E(
+%0A              
 new DoubleSummar
@@ -4850,16 +4850,24 @@
  sketch,
+%0A       
  int num
@@ -4907,49 +4907,10 @@
 ) %7B%0A
-        Random random = new Random();%0A%0A  
+%0A%0A
     
@@ -4971,26 +4971,24 @@
 %7B%0A          
-  
 sketch.updat
@@ -5022,18 +5022,16 @@
 Value);%0A
-  
       %7D%0A

Make random tests deterministic.