"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.calculateStop = calculateStop;
exports.checkIsMinContinuity = exports.checkIsMaxContinuity = void 0;
exports.getDataMinMax = getDataMinMax;
exports.getFallbackDataBounds = void 0;
exports.getPaletteStops = getPaletteStops;
exports.getStepValue = getStepValue;
exports.remapStopsByNewInterval = remapStopsByNewInterval;
exports.reversePalette = reversePalette;
exports.roundValue = roundValue;
exports.shiftPalette = shiftPalette;
var _constants = require("./constants");
/*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the Elastic License
 * 2.0 and the Server Side Public License, v 1; you may not use this file except
 * in compliance with, at your election, the Elastic License 2.0 or the Server
 * Side Public License, v 1.
 */

/** @internal **/
function calculateStop(stopValue, newMin, oldMin, oldInterval, newInterval) {
  if (oldInterval === 0) {
    return newInterval + newMin;
  }
  return roundValue(newMin + (stopValue - oldMin) * newInterval / oldInterval);
}

/**
 * This is a generic function to compute stops from the current parameters.
 */
function getPaletteStops(palettes, activePaletteParams,
// used to customize color resolution
{
  prevPalette,
  dataBounds,
  mapFromMinValue,
  defaultPaletteName
}) {
  const {
    min: minValue,
    max: maxValue
  } = getOverallMinMax(activePaletteParams, dataBounds);
  const interval = maxValue - minValue;
  const {
    stops: currentStops,
    ...otherParams
  } = activePaletteParams || {};
  if (activePaletteParams.name === 'custom' && activePaletteParams !== null && activePaletteParams !== void 0 && activePaletteParams.colorStops) {
    // need to generate the palette from the existing controlStops
    return shiftPalette(activePaletteParams.colorStops, maxValue);
  }
  const steps = (activePaletteParams === null || activePaletteParams === void 0 ? void 0 : activePaletteParams.steps) || _constants.DEFAULT_COLOR_STEPS;
  // generate a palette from predefined ones and customize the domain
  const colorStopsFromPredefined = palettes.get(prevPalette || (activePaletteParams === null || activePaletteParams === void 0 ? void 0 : activePaletteParams.name) || defaultPaletteName || _constants.DEFAULT_PALETTE_NAME).getCategoricalColors(steps, otherParams);
  const newStopsMin = mapFromMinValue || interval === 0 ? minValue : interval / steps;
  return remapStopsByNewInterval(colorStopsFromPredefined.map((color, index) => ({
    color,
    stop: index
  })), {
    newInterval: interval,
    oldInterval: colorStopsFromPredefined.length,
    newMin: newStopsMin,
    oldMin: 0
  });
}

// Utility to remap color stops within new domain
function remapStopsByNewInterval(controlStops, {
  newInterval,
  oldInterval,
  newMin,
  oldMin
}) {
  return (controlStops || []).map(({
    color,
    stop
  }) => {
    return {
      color,
      stop: calculateStop(stop, newMin, oldMin, oldInterval, newInterval)
    };
  });
}

// Need to shift the Custom palette in order to correctly visualize it when in display mode
function shiftPalette(stops, max) {
  // shift everything right and add an additional stop at the end
  const result = stops.map((entry, i, array) => ({
    ...entry,
    stop: i + 1 < array.length ? array[i + 1].stop : max
  }));
  if (stops[stops.length - 1].stop === max) {
    // extends the range by a fair amount to make it work the extra case for the last stop === max
    const computedStep = getStepValue(stops, result, max) || 1;
    // do not go beyond the unit step in this case
    const step = Math.min(1, computedStep);
    result[stops.length - 1].stop = max + step;
  }
  return result;
}
function getOverallMinMax(params, dataBounds) {
  var _params$colorStops$0$, _params$colorStops, _params$colorStops$, _params$colorStops$st, _params$colorStops2, _params$colorStops3;
  const {
    min: dataMin,
    max: dataMax
  } = getDataMinMax(params === null || params === void 0 ? void 0 : params.rangeType, dataBounds);
  const minStopValue = (_params$colorStops$0$ = params === null || params === void 0 ? void 0 : (_params$colorStops = params.colorStops) === null || _params$colorStops === void 0 ? void 0 : (_params$colorStops$ = _params$colorStops[0]) === null || _params$colorStops$ === void 0 ? void 0 : _params$colorStops$.stop) !== null && _params$colorStops$0$ !== void 0 ? _params$colorStops$0$ : Number.POSITIVE_INFINITY;
  const maxStopValue = (_params$colorStops$st = params === null || params === void 0 ? void 0 : (_params$colorStops2 = params.colorStops) === null || _params$colorStops2 === void 0 ? void 0 : (_params$colorStops3 = _params$colorStops2[params.colorStops.length - 1]) === null || _params$colorStops3 === void 0 ? void 0 : _params$colorStops3.stop) !== null && _params$colorStops$st !== void 0 ? _params$colorStops$st : Number.NEGATIVE_INFINITY;
  const overallMin = Math.min(dataMin, minStopValue);
  const overallMax = Math.max(dataMax, maxStopValue);
  return {
    min: overallMin,
    max: overallMax
  };
}
function roundValue(value, fractionDigits = 2) {
  return Number((Math.floor(value * 100) / 100).toFixed(fractionDigits));
}

// very simple heuristic: pick last two stops and compute a new stop based on the same distance
// if the new stop is above max, then reduce the step to reach max, or if zero then just 1.
//
// it accepts two series of stops as the function is used also when computing stops from colorStops
function getStepValue(colorStops, newColorStops, max) {
  const length = newColorStops.length;
  // workout the steps from the last 2 items
  const dataStep = length > 1 ? newColorStops[length - 1].stop - newColorStops[length - 2].stop || 1 : 1;
  let step = Number(dataStep.toFixed(2));
  if (max < colorStops[length - 1].stop + step) {
    const diffToMax = max - colorStops[length - 1].stop;
    // if the computed step goes way out of bound, fallback to 1, otherwise reach max
    step = diffToMax > 0 ? diffToMax : 1;
  }
  return step;
}
function getDataMinMax(rangeType, dataBounds) {
  const dataMin = rangeType === 'number' ? dataBounds.min : _constants.DEFAULT_MIN_STOP;
  const dataMax = rangeType === 'number' ? dataBounds.max : _constants.DEFAULT_MAX_STOP;
  return {
    min: dataMin,
    max: dataMax
  };
}
const checkIsMinContinuity = continuity => Boolean(continuity && ['below', 'all'].includes(continuity));
exports.checkIsMinContinuity = checkIsMinContinuity;
const checkIsMaxContinuity = continuity => Boolean(continuity && ['above', 'all'].includes(continuity));
exports.checkIsMaxContinuity = checkIsMaxContinuity;
const getFallbackDataBounds = (rangeType = 'percent') => rangeType === 'percent' ? {
  min: 0,
  max: 100,
  fallback: true
} : {
  min: 1,
  max: 1,
  fallback: true
};
exports.getFallbackDataBounds = getFallbackDataBounds;
function reversePalette(paletteColorRepresentation = []) {
  const stops = paletteColorRepresentation.map(({
    stop
  }) => stop);
  return paletteColorRepresentation.map(({
    color
  }, i) => ({
    color,
    stop: stops[paletteColorRepresentation.length - i - 1]
  })).reverse();
}