/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";

/* eslint-env worker */

/**
 * Import `createTask` to communicate with `devtools/shared/worker`.
 */
importScripts("resource://gre/modules/workers/require.js");
const { createTask } = require("resource://devtools/shared/worker/helper.js");

/**
 * @see LineGraphWidget.prototype.setDataFromTimestamps in Graphs.js
 * @param number id
 * @param array timestamps
 * @param number interval
 * @param number duration
 */
createTask(self, "plotTimestampsGraph", function ({ timestamps,
                                                    interval, duration }) {
  let plottedData = plotTimestamps(timestamps, interval);
  let plottedMinMaxSum = getMinMaxAvg(plottedData, timestamps, duration);

  return { plottedData, plottedMinMaxSum };
});

/**
 * Gets the min, max and average of the values in an array.
 * @param array source
 * @param array timestamps
 * @param number duration
 * @return object
 */
function getMinMaxAvg(source, timestamps, duration) {
  let totalFrames = timestamps.length;
  let maxValue = Number.MIN_SAFE_INTEGER;
  let minValue = Number.MAX_SAFE_INTEGER;
  // Calculate the average by counting how many frames occurred
  // in the duration of the recording, rather than average the frame points
  // we have, as that weights higher FPS, as there'll be more timestamps for
  // those values
  let avgValue = totalFrames / (duration / 1000);

  for (let { value } of source) {
    maxValue = Math.max(value, maxValue);
    minValue = Math.min(value, minValue);
  }

  return { minValue, maxValue, avgValue };
}

/**
 * Takes a list of numbers and plots them on a line graph representing
 * the rate of occurences in a specified interval.
 *
 * @param array timestamps
 *        A list of numbers representing time, ordered ascending. For example,
 *        this can be the raw data received from the framerate actor, which
 *        represents the elapsed time on each refresh driver tick.
 * @param number interval
 *        The maximum amount of time to wait between calculations.
 * @param number clamp
 *        The maximum allowed value.
 * @return array
 *         A collection of { delta, value } objects representing the
 *         plotted value at every delta time.
 */
function plotTimestamps(timestamps, interval = 100, clamp = 60) {
  let timeline = [];
  let totalTicks = timestamps.length;

  // If the refresh driver didn't get a chance to tick before the
  // recording was stopped, assume rate was 0.
  if (totalTicks == 0) {
    timeline.push({ delta: 0, value: 0 });
    timeline.push({ delta: interval, value: 0 });
    return timeline;
  }

  let frameCount = 0;
  let prevTime = +timestamps[0];

  for (let i = 1; i < totalTicks; i++) {
    let currTime = +timestamps[i];
    frameCount++;

    let elapsedTime = currTime - prevTime;
    if (elapsedTime < interval) {
      continue;
    }

    let rate = Math.min(1000 / (elapsedTime / frameCount), clamp);
    timeline.push({ delta: prevTime, value: rate });
    timeline.push({ delta: currTime, value: rate });

    frameCount = 0;
    prevTime = currTime;
  }

  return timeline;
}
