package br.ufrgs.inf.prosoft.tigris;

import br.ufrgs.inf.prosoft.tigris.sampling.Granularity;
import br.ufrgs.inf.prosoft.tigris.sampling.GranularityType;
import br.ufrgs.inf.prosoft.tigris.sampling.Sampling;
import org.apache.commons.math3.ml.neuralnet.sofm.util.ExponentialDecayFunction;
import org.junit.Assert;
import org.junit.Test;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class SamplingTest {

    @Test
    public void samplingDecisionWithNoChance(){
        Sampling sampling = new Sampling(0, 100, false);
        for (int i = 0; i < 2000; i++) {
            Assert.assertFalse(sampling.samplingDecision(new Granularity(GranularityType.METHOD, "function"), 0));
        }
        Assert.assertEquals(0, sampling.getSample().getTotalItems());
        Assert.assertEquals(2000, sampling.getPopulation().getTotalItems());
    }

    @Test
    public void samplingDecisionWith100Chance(){
        Sampling sampling = new Sampling(1, 100, false);
        Granularity granularity = new Granularity(GranularityType.METHOD, "function");
        for (int i = 0; i < 2000; i++) {
            Assert.assertTrue(sampling.samplingDecision(granularity, 0));
            sampling.addSampledItem(granularity, 0, 0);
        }
        Assert.assertEquals(2000, sampling.getSample().getTotalItems());
        Assert.assertEquals(2000, sampling.getPopulation().getTotalItems());
    }

    @Test
    public void isReadyWithOneGranularity(){
        Sampling sampling = new Sampling(1, 100, true);
        Granularity granularity = new Granularity(GranularityType.METHOD, "function");
        for (int i = 0; i < 2000; i++) {
            Assert.assertTrue(sampling.samplingDecision(granularity, 0));
            sampling.addSampledItem(granularity, 0, 0);
        }
        Assert.assertTrue(sampling.isReady());
    }

    @Test
    public void isReadyWithMultipleGranularity(){
        Sampling sampling = new Sampling(1, 100000, true);
        for (int i = 0; i < 1000; i++) {
            Granularity granularity = new Granularity(GranularityType.METHOD, "function");
            Assert.assertTrue(sampling.samplingDecision(granularity, i));
            sampling.addSampledItem(granularity, 0, 0);
        }
        for (int i = 0; i < 1000; i++) {
            Granularity granularity = new Granularity(GranularityType.METHOD, "function2");
            Assert.assertTrue(sampling.samplingDecision(granularity, i));
            sampling.addSampledItem(granularity, 0, 0);
        }
        for (int i = 0; i < 1000; i++) {
            Granularity granularity = new Granularity(GranularityType.METHOD, "function3");
            Assert.assertTrue(sampling.samplingDecision(granularity, i));
            sampling.addSampledItem(granularity, 0, 0);
        }
        Assert.assertTrue(sampling.isReady());
    }

    @Test
    public void decayingConfidenceTest(){
        Sampling sampling = new Sampling(0.5, 6000, true);

        long startTime = System.currentTimeMillis();

        while(sampling.decayingConfidenceFactor(System.currentTimeMillis() - startTime) > 0);

        Assert.assertEquals(sampling.decayingConfidenceFactor(System.currentTimeMillis() - startTime), 0, 0);
    }

//    @Test
    public void decayingWeightGeneration(){
//        Sampling sampling = new Sampling(0.5, 3000, true);

        ExponentialDecayFunction decay = new ExponentialDecayFunction(1, 0.01, 1200);
        long startValue = 1;

        List<Double> values = new ArrayList<>();

        double value = new BigDecimal(decay.value(startValue))
                .setScale(2, BigDecimal.ROUND_FLOOR).doubleValue();
        while(value > 0) {
            startValue++;
            values.add(value);
            value = new BigDecimal(decay.value(startValue))
                    .setScale(2, BigDecimal.ROUND_FLOOR).doubleValue();
        }

        Collections.reverse(values);
        System.out.println(values);
        System.out.println(values.size());
    }
}
