package com.jivesoftware.os.miru.sea.anomaly.plugins;

import com.google.common.math.LongMath;
import com.jivesoftware.os.miru.plugin.bitmap.MiruBitmaps;
import com.jivesoftware.os.miru.sea.anomaly.plugins.SeaAnomalyAnswer.Waveform;
import com.jivesoftware.os.mlogger.core.MetricLogger;
import com.jivesoftware.os.mlogger.core.MetricLoggerFactory;
import java.util.Arrays;
import java.util.List;

/**
 *
 */
public class SeaAnomaly {

    private static final MetricLogger LOG = MetricLoggerFactory.getLogger();

    public <BM extends IBM, IBM> Waveform metricingSum(MiruBitmaps<BM, IBM> bitmaps,
        BM rawAnswer,
        List<BM> answers,
        int[] indexes,
        int numBits)
        throws Exception {

        LOG.debug("Get metricing for answers={}", answers);

        long[] waveform = sum(indexes, numBits, answers, bitmaps);

        return new Waveform(waveform);
    }

    public <BM extends IBM, IBM> Waveform metricingAvg(MiruBitmaps<BM, IBM> bitmaps,
        BM rawAnswer,
        List<BM> answers,
        int[] indexes,
        int numBits)
        throws Exception {

        LOG.debug("Get metricing for answers={}", answers);

        long[] rawCardinalities = new long[indexes.length - 1];
        bitmaps.boundedCardinalities(rawAnswer, new int[][] { indexes }, new long[][] { rawCardinalities });

        long[] waveform = sum(indexes, numBits, answers, bitmaps);

        for (int i = 0; i < waveform.length; i++) {
            if (rawCardinalities[i] > 0) {
                waveform[i] /= rawCardinalities[i];
            }
        }
        return new Waveform(waveform);
    }


    static <BM extends IBM, IBM> long[] sum(int[] indexes, int numBits, List<BM> answers, MiruBitmaps<BM, IBM> bitmaps) {
        long[] waveform = null;
        long[] rawCardinalities = new long[indexes.length - 1];

        for (int i = 0; i < numBits; i++) {
            BM answer = answers.get(i);
            if (answer != null) {
                Arrays.fill(rawCardinalities, 0);
                bitmaps.boundedCardinalities(answer, new int[][] { indexes }, new long[][] { rawCardinalities });
                if (waveform == null) {
                    waveform = new long[rawCardinalities.length];
                }
                long multiplier = (1L << i);
                for (int j = 0; j < waveform.length; j++) {
                    if (rawCardinalities[j] > 0) {
                        long add = rawCardinalities[j] * multiplier;
                        try {
                            waveform[j] = LongMath.checkedAdd(waveform[j], add);
                        } catch (Exception x) {
                            waveform[j] = Long.MAX_VALUE;
                            LOG.inc("overflows");
                        }
                    }
                }
            }
        }
        return waveform;

    }
}

@@ -388,16 +388,168 @@
 il.List;
+%0Aimport org.apache.commons.math.analysis.interpolation.SplineInterpolator;%0Aimport org.apache.commons.math.analysis.polynomials.PolynomialSplineFunction;
 %0A%0A/**%0A *
@@ -654,24 +654,103 @@
 tLogger();%0A%0A
+    private final SplineInterpolator interpolator = new SplineInterpolator();%0A%0A
     public %3C
@@ -1637,160 +1637,1118 @@
     
-for (int i = 0; i %3C waveform.length; i++) %7B%0A            if (rawCardinalities%5Bi%5D %3E 0) %7B%0A                waveform%5Bi%5D /= rawCardinalities%5Bi%5D;%0A            %7D
+double%5B%5D x = new double%5Bwaveform.length%5D;%0A        double%5B%5D y = new double%5Bwaveform.length%5D;%0A        int count = 0;%0A        for (int i = 0; i %3C waveform.length; i++) %7B%0A            if (rawCardinalities%5Bi%5D %3E 0) %7B%0A                x%5Bcount%5D = i;%0A                y%5Bcount%5D /= rawCardinalities%5Bi%5D;%0A                count++;%0A            %7D%0A        %7D%0A%0A        if (count == waveform.length) %7B%0A            for (int i = 0; i %3C waveform.length; i++) %7B%0A                if (rawCardinalities%5Bi%5D %3E 0) %7B%0A                    waveform%5Bi%5D /= rawCardinalities%5Bi%5D;%0A                %7D%0A            %7D%0A        %7D else %7B%0A            double%5B%5D ix = new double%5Bcount%5D;%0A            double%5B%5D iy = new double%5Bcount%5D;%0A            System.arraycopy(x, 0, ix, 0, count);%0A            System.arraycopy(y, 0, iy, 0, count);%0A%0A            PolynomialSplineFunction splineFunction = interpolator.interpolate(ix, iy);%0A%0A            long%5B%5D interpolated = new long%5Bwaveform.length%5D;%0A            for (int i = 0; i %3C waveform.length; i++) %7B%0A                interpolated%5Bi%5D = (long) splineFunction.value((double) i);%0A            %7D%0A%0A            waveform = interpolated;
 %0A   

add interpolation to anomaly averaging