package pl.edu.pw.mini.jk.sg.mixeduct.resulttrends;

import org.apache.commons.collections4.queue.CircularFifoQueue;
import org.apache.commons.math3.stat.StatUtils;

import com.codepoetics.protonpack.StreamUtils;

public class OscilationCheck implements Oscilation {
	private final int oscilateCheckFirstIteration;
	private final double oscilateCheckThreshold;

	private final CircularFifoQueue<Double> lastResults;
	private final CircularFifoQueue<Double> lastResultsSmooth;
	private final CircularFifoQueue<Double> lastResultsToSmoth;

	public OscilationCheck(int oscilateCheckIterations, int oscilateCheckSmoothSteps, int oscilateCheckFirstIteration,
			double oscilateCheckThreshold) {
		super();
		this.oscilateCheckFirstIteration = oscilateCheckFirstIteration;
		this.oscilateCheckThreshold = oscilateCheckThreshold;

		this.lastResults = new CircularFifoQueue<>(oscilateCheckIterations);
		this.lastResultsSmooth = new CircularFifoQueue<>(oscilateCheckIterations);
		this.lastResultsToSmoth = new CircularFifoQueue<>(oscilateCheckSmoothSteps);
	}

	/* (non-Javadoc)
	 * @see pl.edu.pw.mini.jk.sg.game.common.Oscilation#registerResult(double)
	 */
	@Override
	public void registerResult(double result) {

		lastResults.add(result);
		lastResultsToSmoth.add(result);
		lastResultsSmooth.add(lastResultsToSmoth.stream().mapToDouble(i -> i).average().getAsDouble());
	}

	/* (non-Javadoc)
	 * @see pl.edu.pw.mini.jk.sg.game.common.Oscilation#isOscilating(int)
	 */
	@Override
	public boolean isOscilating(final int currentIteration) {
		if (oscilateCheckFirstIteration > currentIteration) {
			return false;
		} else {
			// Uwaga na przesunięcie!!!
			double[] differences = StreamUtils.zip(lastResults.stream(), lastResultsSmooth.stream(), (l, r) -> l - r)
					.mapToDouble(i -> i).toArray();
			return StatUtils.variance(differences) > oscilateCheckThreshold;
		}
	}

}
