"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.changeColorPalette = changeColorPalette;
exports.getColorStops = getColorStops;
exports.getStopsFromColorRangesByNewInterval = getStopsFromColorRangesByNewInterval;
exports.mergePaletteParams = mergePaletteParams;
exports.toColorRanges = toColorRanges;
exports.updateRangeType = updateRangeType;
exports.withUpdatingColorRanges = withUpdatingColorRanges;
exports.withUpdatingPalette = withUpdatingPalette;
var _palettes = require("../../palettes");
var _utils = require("./color_ranges/utils");
/*
 * 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.
 */

/**
 * Some name conventions here:
 * * `displayStops` => It's an additional transformation of `stops` into a [0, N] domain for the EUIPaletteDisplay component.
 * * `stops` => final steps used to table coloring. It is a rightShift of the colorStops
 * * `colorStops` => user's color stop inputs.  Used to compute range min.
 *
 * When the user inputs the colorStops, they are designed to be the initial part of the color segment,
 * so the next stops indicate where the previous stop ends.
 * Both table coloring logic and EuiPaletteDisplay format implementation works differently than our current `colorStops`,
 * by having the stop values at the end of each color segment rather than at the beginning: `stops` values are computed by a rightShift of `colorStops`.
 * EuiPaletteDisplay has an additional requirement as it is always mapped against a domain [0, N]: from `stops` the `displayStops` are computed with
 * some continuity enrichment and a remap against a [0, 100] domain to make the palette component work ok.
 *
 * These naming conventions would be useful to track the code flow in this feature as multiple transformations are happening
 * for a single change.
 */

function updateRangeType(newRangeType, activePalette, dataBounds, palettes, colorRanges) {
  var _activePalette$params, _activePalette$params2, _activePalette$params3, _activePalette$params4;
  const continuity = (_activePalette$params = (_activePalette$params2 = activePalette.params) === null || _activePalette$params2 === void 0 ? void 0 : _activePalette$params2.continuity) !== null && _activePalette$params !== void 0 ? _activePalette$params : _palettes.DEFAULT_CONTINUITY;
  const params = {
    rangeType: newRangeType
  };
  const {
    min: newMin,
    max: newMax
  } = (0, _palettes.getDataMinMax)(newRangeType, dataBounds);
  const {
    min: oldMin,
    max: oldMax
  } = (0, _palettes.getDataMinMax)((_activePalette$params3 = activePalette.params) === null || _activePalette$params3 === void 0 ? void 0 : _activePalette$params3.rangeType, dataBounds);
  const newColorStops = getStopsFromColorRangesByNewInterval(colorRanges, {
    oldInterval: oldMax - oldMin,
    newInterval: newMax - newMin,
    newMin,
    oldMin
  });
  if (activePalette.name === _palettes.CUSTOM_PALETTE) {
    const stops = (0, _palettes.getPaletteStops)(palettes, {
      ...activePalette.params,
      colorStops: newColorStops,
      ...params
    }, {
      dataBounds
    });
    params.colorStops = newColorStops;
    params.stops = stops;
  } else {
    params.stops = (0, _palettes.getPaletteStops)(palettes, {
      ...activePalette.params,
      ...params
    }, {
      prevPalette: activePalette.name,
      dataBounds
    });
  }
  const lastStop = activePalette.name === _palettes.CUSTOM_PALETTE ? newColorStops[newColorStops.length - 1].stop : params.stops[params.stops.length - 1].stop;
  params.rangeMin = (0, _palettes.checkIsMinContinuity)(continuity) ? Number.NEGATIVE_INFINITY : activePalette.name === _palettes.CUSTOM_PALETTE ? newColorStops[0].stop : params.stops[0].stop;
  params.rangeMax = (0, _palettes.checkIsMaxContinuity)(continuity) ? Number.POSITIVE_INFINITY : (_activePalette$params4 = activePalette.params) !== null && _activePalette$params4 !== void 0 && _activePalette$params4.rangeMax ? (0, _palettes.calculateStop)(activePalette.params.rangeMax, newMin, oldMin, oldMax - oldMin, newMax - newMin) : lastStop > newMax ? lastStop + 1 : newMax;
  return params;
}
function changeColorPalette(newPalette, activePalette, palettes, dataBounds, disableSwitchingContinuity) {
  var _activePalette$params5, _activePalette$params6, _activePalette$params7;
  const isNewPaletteCustom = newPalette.name === _palettes.CUSTOM_PALETTE;
  const newParams = {
    ...activePalette.params,
    name: newPalette.name,
    colorStops: undefined,
    continuity: disableSwitchingContinuity ? (_activePalette$params5 = (_activePalette$params6 = activePalette.params) === null || _activePalette$params6 === void 0 ? void 0 : _activePalette$params6.continuity) !== null && _activePalette$params5 !== void 0 ? _activePalette$params5 : _palettes.DEFAULT_CONTINUITY : _palettes.DEFAULT_CONTINUITY,
    reverse: false // restore the reverse flag
  };

  // we should pass colorStops so that correct calculate new color stops (if there was before) for custom palette
  const newColorStops = getColorStops(palettes, ((_activePalette$params7 = activePalette.params) === null || _activePalette$params7 === void 0 ? void 0 : _activePalette$params7.colorStops) || [], activePalette, dataBounds);
  if (isNewPaletteCustom) {
    newParams.colorStops = newColorStops;
  }
  return {
    ...newPalette,
    params: {
      ...newParams,
      stops: (0, _palettes.getPaletteStops)(palettes, newParams, {
        prevPalette: isNewPaletteCustom || activePalette.name === _palettes.CUSTOM_PALETTE ? undefined : newPalette.name,
        dataBounds,
        mapFromMinValue: true
      }),
      rangeMin: (0, _palettes.checkIsMinContinuity)(newParams.continuity) ? Number.NEGATIVE_INFINITY : Math.min(dataBounds.min, newColorStops[0].stop),
      rangeMax: (0, _palettes.checkIsMaxContinuity)(newParams.continuity) ? Number.POSITIVE_INFINITY : Math.min(dataBounds.max, newColorStops[newColorStops.length - 1].stop)
    }
  };
}
function withUpdatingPalette(palettes, activePalette, colorRanges, dataBounds, continuity) {
  var _ref, _activePalette$params8, _params, _params2, _colorStops$;
  const currentContinuity = (_ref = continuity !== null && continuity !== void 0 ? continuity : (_activePalette$params8 = activePalette.params) === null || _activePalette$params8 === void 0 ? void 0 : _activePalette$params8.continuity) !== null && _ref !== void 0 ? _ref : _palettes.DEFAULT_CONTINUITY;
  let sortedColorRanges = colorRanges;
  if (colorRanges.some((value, index) => index !== colorRanges.length - 1 ? value.start > colorRanges[index + 1].start : false)) {
    sortedColorRanges = (0, _utils.sortColorRanges)(colorRanges);
  }
  const {
    max,
    colorStops
  } = (0, _utils.toColorStops)(sortedColorRanges, currentContinuity);
  const newPallete = getSwitchToCustomParams(palettes, activePalette, {
    continuity: currentContinuity,
    colorStops,
    steps: ((_params = activePalette.params) === null || _params === void 0 ? void 0 : _params.steps) || _palettes.DEFAULT_COLOR_STEPS,
    reverse: (_params2 = activePalette.params) === null || _params2 === void 0 ? void 0 : _params2.reverse,
    rangeMin: (_colorStops$ = colorStops[0]) === null || _colorStops$ === void 0 ? void 0 : _colorStops$.stop,
    rangeMax: max
  }, dataBounds);
  return {
    activePalette: newPallete,
    colorRanges
  };
}
function withUpdatingColorRanges(palettes, activePalette, dataBounds) {
  var _activePalette$params9;
  return {
    colorRanges: toColorRanges(palettes, ((_activePalette$params9 = activePalette.params) === null || _activePalette$params9 === void 0 ? void 0 : _activePalette$params9.colorStops) || [], activePalette, dataBounds),
    activePalette
  };
}

// Utility to remap color stops within new domain
function getStopsFromColorRangesByNewInterval(colorRanges, {
  newInterval,
  oldInterval,
  newMin,
  oldMin
}) {
  return (colorRanges || []).map(({
    color,
    start
  }) => {
    let stop = (0, _palettes.calculateStop)(start, newMin, oldMin, oldInterval, newInterval);
    if (oldInterval === 0) {
      stop = newInterval + newMin;
    }
    return {
      color,
      stop: (0, _palettes.roundValue)(stop)
    };
  });
}
function mergePaletteParams(activePalette, newParams) {
  return {
    ...activePalette,
    params: {
      ...activePalette.params,
      ...newParams
    }
  };
}
function getSwitchToCustomParams(palettes, activePalette, newParams, dataBounds) {
  var _activePalette$params10;
  // if it's already a custom palette just return the params
  if ((activePalette === null || activePalette === void 0 ? void 0 : (_activePalette$params10 = activePalette.params) === null || _activePalette$params10 === void 0 ? void 0 : _activePalette$params10.name) === _palettes.CUSTOM_PALETTE) {
    const stops = (0, _palettes.getPaletteStops)(palettes, {
      steps: _palettes.DEFAULT_COLOR_STEPS,
      ...activePalette.params,
      ...newParams
    }, {
      dataBounds
    });
    return mergePaletteParams(activePalette, {
      ...newParams,
      stops
    });
  }
  // prepare everything to switch to custom palette
  const newPaletteParams = {
    steps: _palettes.DEFAULT_COLOR_STEPS,
    ...activePalette.params,
    ...newParams,
    name: _palettes.CUSTOM_PALETTE
  };
  const stops = (0, _palettes.getPaletteStops)(palettes, newPaletteParams, {
    prevPalette: newPaletteParams.colorStops ? undefined : activePalette.name,
    dataBounds
  });
  return mergePaletteParams({
    name: _palettes.CUSTOM_PALETTE,
    type: 'palette'
  }, {
    ...newPaletteParams,
    stops
  });
}
function getColorStops(palettes, colorStops, activePalette, dataBounds) {
  var _activePalette$params11;
  // just forward the current stops if custom
  if ((activePalette === null || activePalette === void 0 ? void 0 : activePalette.name) === _palettes.CUSTOM_PALETTE && colorStops !== null && colorStops !== void 0 && colorStops.length) {
    return colorStops;
  }
  // for predefined palettes create some stops, then drop the last one.
  // we're using these as starting point for the user
  let freshColorStops = (0, _palettes.getPaletteStops)(palettes, {
    ...(activePalette === null || activePalette === void 0 ? void 0 : activePalette.params)
  },
  // mapFromMinValue is a special flag to offset the stops values
  // used here to avoid a new remap/left shift
  {
    dataBounds,
    mapFromMinValue: true,
    defaultPaletteName: activePalette.name
  });
  if (activePalette !== null && activePalette !== void 0 && (_activePalette$params11 = activePalette.params) !== null && _activePalette$params11 !== void 0 && _activePalette$params11.reverse) {
    freshColorStops = (0, _palettes.reversePalette)(freshColorStops);
  }
  return freshColorStops;
}

/**
 * Both table coloring logic and EuiPaletteDisplay format implementation works differently than our current `colorStops`,
 * by having the stop values at the end of each color segment rather than at the beginning: `stops` values are computed by a rightShift of `colorStops`.
 * EuiPaletteDisplay has an additional requirement as it is always mapped against a domain [0, N]: from `stops` the `displayStops` are computed with
 * some continuity enrichment and a remap against a [0, 100] domain to make the palette component work ok.
 *
 * These naming conventions would be useful to track the code flow in this feature as multiple transformations are happening
 * for a single change.
 */
function toColorRanges(palettes, colorStops, activePalette, dataBounds) {
  var _activePalette$params12;
  const {
    continuity = _palettes.DEFAULT_CONTINUITY,
    rangeType = _palettes.DEFAULT_RANGE_TYPE
  } = (_activePalette$params12 = activePalette.params) !== null && _activePalette$params12 !== void 0 ? _activePalette$params12 : {};
  const {
    min: dataMin,
    max: dataMax
  } = (0, _palettes.getDataMinMax)(rangeType, dataBounds);
  return getColorStops(palettes, colorStops || [], activePalette, dataBounds).map((colorStop, index, array) => {
    var _ref2, _colorStop$stop, _activePalette$params13, _ref3, _array$stop, _array, _activePalette$params14;
    const isFirst = index === 0;
    const isLast = index === array.length - 1;
    return {
      color: colorStop.color,
      start: isFirst && (0, _palettes.checkIsMinContinuity)(continuity) ? Number.NEGATIVE_INFINITY : (_ref2 = (_colorStop$stop = colorStop.stop) !== null && _colorStop$stop !== void 0 ? _colorStop$stop : (_activePalette$params13 = activePalette.params) === null || _activePalette$params13 === void 0 ? void 0 : _activePalette$params13.rangeMin) !== null && _ref2 !== void 0 ? _ref2 : dataMin,
      end: isLast && (0, _palettes.checkIsMaxContinuity)(continuity) ? Number.POSITIVE_INFINITY : (_ref3 = (_array$stop = (_array = array[index + 1]) === null || _array === void 0 ? void 0 : _array.stop) !== null && _array$stop !== void 0 ? _array$stop : (_activePalette$params14 = activePalette.params) === null || _activePalette$params14 === void 0 ? void 0 : _activePalette$params14.rangeMax) !== null && _ref3 !== void 0 ? _ref3 : dataMax
    };
  });
}