import { array_compute_max } from "../../../core/collection/array/array_compute_max.js";
import { array_compute_min } from "../../../core/collection/array/array_compute_min.js";
import { RingBuffer } from "../../../core/collection/RingBuffer.js";
import { computeStatisticalMean } from "../../../core/math/statistics/computeStatisticalMean.js";
import { computeStatisticalPartialMedian } from "../../../core/math/statistics/computeStatisticalPartialMedian.js";
import { AbstractMetric } from "./AbstractMetric.js";

/**
 * Metric container with a limited size and great performance characteristics.
 * Does not allocate memory during usage.
 */
export class RingBufferMetric extends AbstractMetric {
    /**
     *
     * @param {number} [size] how many records should the ring-buffer hold?
     */
    constructor(size = 128) {
        super();

        /**
         *
         * @type {RingBuffer}
         * @readonly
         * @private
         */
        this.__data = new RingBuffer(size);
    }

    /**
     * Resize underlying buffer to be able to keep a different number of records
     * @param {number} size
     */
    resize(size) {
        this.__data.resize(size);
    }

    /**
     * When metric has no records - this will produce 0
     * @return {number}
     */
    getLastRecord() {
        if (this.__data.count === 0) {
            return 0;
        }

        return this.__data.getHead();
    }

    record(value) {
        this.__data.push(value);
    }

    /**
     *
     * @param {MetricStatistics} result
     * @returns {boolean}
     */
    computeStats(result) {

        const buffer = this.__data;
        const array = buffer.data;
        const data_count = buffer.count;

        if (data_count === 0) {

            // no data
            result.mean = 0;
            result.median = 0;
            result.min = 0;
            result.max = 0;

            return false;

        } else {

            result.mean = computeStatisticalMean(array, 0, data_count);
            result.median = computeStatisticalPartialMedian(array, 0, data_count - 1);
            result.max = array_compute_max(array, 0, data_count);
            result.min = array_compute_min(array, 0, data_count);

            return true;

        }
    }

    clear() {
        this.__data.clear();
    }
}
