"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _react = _interopRequireWildcard(require("react"));
var _charts = require("@elastic/charts");
var _i18n = require("@kbn/i18n");
var _eui = require("@elastic/eui");
var _public = require("@kbn/charts-plugin/public");
var _constants = require("@kbn/visualizations-plugin/common/constants");
var _utils = require("@kbn/visualizations-plugin/common/utils");
var _chartExpressionsCommon = require("@kbn/chart-expressions-common");
var _utils2 = require("../../common/utils");
var _constants2 = require("../../common/constants");
var _expression_renderers = require("../../common/types/expression_renderers");
var _utils3 = require("../utils");
var _chart_split = require("./chart_split");
var _visualization_noresults = require("./visualization_noresults");
var _partition_vis_component = require("./partition_vis_component.styles");
var _filter_out_config = require("../utils/filter_out_config");
var _filter_helpers = require("../utils/filter_helpers");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
/*
 * 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.
 */

const PartitionVisComponent = props => {
  var _visParams$labels$per, _visParams$legendPosi, _visParams$distinctCo, _window$_echDebugStat, _visParams$legendSize, _visParams$maxLegendL;
  const {
    columnCellValueActions,
    visData: originalVisData,
    visParams: preVisParams,
    visType,
    services,
    syncColors,
    interactive,
    overrides,
    hasOpenedOnAggBasedEditor
  } = props;
  const visParams = (0, _react.useMemo)(() => (0, _filter_out_config.filterOutConfig)(visType, preVisParams), [preVisParams, visType]);
  const chartTheme = props.chartsThemeService.useChartsTheme();
  const chartBaseTheme = props.chartsThemeService.useChartsBaseTheme();
  const {
    table: visData,
    metricAccessor,
    bucketAccessors
  } = (0, _react.useMemo)(() => (0, _utils2.consolidateMetricColumns)(originalVisData, visParams.dimensions.buckets, visParams.dimensions.metrics, visParams.metricsToLabels), [originalVisData, visParams.dimensions.buckets, visParams.dimensions.metrics, visParams.metricsToLabels]);
  const {
    bucketColumns,
    metricColumn
  } = (0, _react.useMemo)(() => (0, _utils3.getColumns)({
    metric: metricAccessor,
    buckets: bucketAccessors
  }, visData), [bucketAccessors, metricAccessor, visData]);
  const formatters = (0, _react.useMemo)(() => (0, _utils3.generateFormatters)(visData, services.fieldFormats.deserialize), [services.fieldFormats.deserialize, visData]);
  const showLegendDefault = (0, _react.useCallback)(() => {
    var _props$uiState$get, _props$uiState;
    const showLegendDef = (0, _utils3.shouldShowLegend)(visType, visParams.legendDisplay, bucketColumns);
    return (_props$uiState$get = (_props$uiState = props.uiState) === null || _props$uiState === void 0 ? void 0 : _props$uiState.get('vis.legendOpen', showLegendDef)) !== null && _props$uiState$get !== void 0 ? _props$uiState$get : showLegendDef;
  }, [bucketColumns, props.uiState, visParams.legendDisplay, visType]);
  const [showLegend, setShowLegend] = (0, _react.useState)(() => showLegendDefault());
  const showToggleLegendElement = props.uiState !== undefined;
  const [chartIsLoaded, setChartIsLoaded] = (0, _react.useState)(false);
  const [containerDimensions, setContainerDimensions] = (0, _react.useState)();
  const parentRef = (0, _react.useRef)(null);
  (0, _react.useEffect)(() => {
    // chart should be loaded to compute the dimensions
    // otherwise the height is set to 0
    if (parentRef && parentRef.current && chartIsLoaded) {
      const parentHeight = parentRef.current.getBoundingClientRect().height;
      const parentWidth = parentRef.current.getBoundingClientRect().width;
      setContainerDimensions({
        width: parentWidth,
        height: parentHeight
      });
    }
  }, [chartIsLoaded, parentRef]);
  (0, _react.useEffect)(() => {
    const legendShow = showLegendDefault();
    setShowLegend(legendShow);
  }, [showLegendDefault]);
  const onRenderChange = (0, _react.useCallback)((isRendered = true) => {
    if (isRendered) {
      props.renderComplete();
      setChartIsLoaded(true);
    }
  }, [props]);

  // handles slice click event
  const handleSliceClick = (0, _react.useCallback)((clickedLayers, buckets, vData, splitChartDimension, splitChartFormatter) => {
    const data = (0, _utils3.getFilterClickData)(clickedLayers, buckets, metricColumn.id, vData, originalVisData, visParams.dimensions.metrics.length, splitChartDimension, splitChartFormatter);
    props.fireEvent({
      name: 'filter',
      data: {
        data
      }
    });
  }, [metricColumn.id, originalVisData, props, visParams.dimensions.metrics.length]);

  // handles legend action event data
  const getLegendActionEventData = (0, _react.useCallback)(vData => series => {
    const data = (0, _utils3.getFilterEventData)(vData, series);
    return {
      name: 'filter',
      data: {
        negate: false,
        data
      }
    };
  }, []);
  const handleLegendAction = (0, _react.useCallback)((event, negate = false) => {
    props.fireEvent({
      ...event,
      data: {
        ...event.data,
        negate
      }
    });
  }, [props]);
  const toggleLegend = (0, _react.useCallback)(() => {
    setShowLegend(value => {
      var _props$uiState2;
      const newValue = !value;
      (_props$uiState2 = props.uiState) === null || _props$uiState2 === void 0 ? void 0 : _props$uiState2.set('vis.legendOpen', newValue);
      return newValue;
    });
  }, [props.uiState]);
  const setColor = (0, _react.useCallback)((newColor, seriesLabel) => {
    var _props$uiState3, _props$uiState4, _props$uiState5, _props$uiState6;
    const colors = ((_props$uiState3 = props.uiState) === null || _props$uiState3 === void 0 ? void 0 : _props$uiState3.get('vis.colors')) || {};
    if (colors[seriesLabel] === newColor || !newColor) {
      delete colors[seriesLabel];
    } else {
      colors[seriesLabel] = newColor;
    }
    (_props$uiState4 = props.uiState) === null || _props$uiState4 === void 0 ? void 0 : _props$uiState4.setSilent('vis.colors', null);
    (_props$uiState5 = props.uiState) === null || _props$uiState5 === void 0 ? void 0 : _props$uiState5.set('vis.colors', colors);
    (_props$uiState6 = props.uiState) === null || _props$uiState6 === void 0 ? void 0 : _props$uiState6.emit('reload');
  }, [props.uiState]);
  const getSliceValue = (0, _react.useCallback)((d, metric) => {
    const value = d[metric.id];
    return Number.isFinite(value) && value >= 0 ? value : 0;
  }, []);
  const defaultFormatter = services.fieldFormats.deserialize;
  // formatters
  const metricFieldFormatter = (0, _utils3.getFormatter)(metricColumn, formatters, defaultFormatter);
  const {
    splitColumn,
    splitRow
  } = visParams.dimensions;
  const splitChartFormatter = splitColumn ? (0, _utils3.getFormatter)(typeof splitColumn[0] === 'string' ? (0, _utils.getColumnByAccessor)(splitColumn[0], visData.columns) : splitColumn[0], formatters, defaultFormatter) : splitRow ? (0, _utils3.getFormatter)(typeof splitRow[0] === 'string' ? (0, _utils.getColumnByAccessor)(splitRow[0], visData.columns) : splitRow[0], formatters, defaultFormatter) : undefined;
  const percentFormatter = services.fieldFormats.deserialize({
    id: 'percent',
    params: {
      pattern: `0,0.[${'0'.repeat((_visParams$labels$per = visParams.labels.percentDecimals) !== null && _visParams$labels$per !== void 0 ? _visParams$labels$per : _constants2.DEFAULT_PERCENT_DECIMALS)}]%`
    }
  });
  const isDarkMode = props.chartsThemeService.useDarkMode();
  const layers = (0, _react.useMemo)(() => {
    var _props$uiState7;
    return (0, _utils3.getLayers)(visType, bucketColumns, visParams, visData, {
      ...((_props$uiState7 = props.uiState) === null || _props$uiState7 === void 0 ? void 0 : _props$uiState7.get('vis.colors', {})),
      ...props.visParams.labels.colorOverrides
    }, visData.rows, props.palettesRegistry, formatters, services.fieldFormats, syncColors, isDarkMode);
  }, [visType, bucketColumns, visParams, visData, props.uiState, props.visParams.labels.colorOverrides, props.palettesRegistry, formatters, services.fieldFormats, syncColors, isDarkMode]);
  const legendActions = (0, _react.useMemo)(() => interactive ? (0, _utils3.getLegendActions)(_utils3.canFilter, getLegendActionEventData(visData), handleLegendAction, columnCellValueActions, visParams, visData, services.data.actions, services.fieldFormats) : undefined, [columnCellValueActions, getLegendActionEventData, handleLegendAction, interactive, services.data.actions, services.fieldFormats, visData, visParams]);
  const rescaleFactor = (0, _react.useMemo)(() => {
    var _slices$filter;
    const overallSum = visData.rows.reduce((sum, row) => sum + row[metricColumn.id], 0);
    const slices = visData.rows.map(row => row[metricColumn.id] / overallSum);
    const smallSlices = (_slices$filter = slices.filter(value => value < 0.02)) !== null && _slices$filter !== void 0 ? _slices$filter : [];
    if (smallSlices.length) {
      // shrink up to 20% to give some room for the linked values
      return 1 / (1 + Math.min(smallSlices.length * 0.05, 0.2));
    }
    return 1;
  }, [visData.rows, metricColumn]);
  const {
    theme: settingsThemeOverrides = {},
    ...settingsOverrides
  } = (0, _chartExpressionsCommon.getOverridesFor)(overrides, 'settings');
  const themeOverrides = (0, _react.useMemo)(() => (0, _utils3.getPartitionTheme)(visType, visParams, chartTheme, containerDimensions, rescaleFactor, hasOpenedOnAggBasedEditor), [visType, visParams, chartTheme, containerDimensions, rescaleFactor, hasOpenedOnAggBasedEditor]);
  const fixedViewPort = document.getElementById('app-fixed-viewport');
  const legendPosition = (_visParams$legendPosi = visParams.legendPosition) !== null && _visParams$legendPosi !== void 0 ? _visParams$legendPosi : _charts.Position.Right;
  const splitChartColumnAccessor = splitColumn ? (0, _utils3.getSplitDimensionAccessor)(visData.columns, splitColumn[0], formatters, defaultFormatter) : undefined;
  const splitChartRowAccessor = splitRow ? (0, _utils3.getSplitDimensionAccessor)(visData.columns, splitRow[0], formatters, defaultFormatter) : undefined;
  const splitChartDimension = splitColumn ? (0, _utils.getColumnByAccessor)(splitColumn[0], visData.columns) : splitRow ? (0, _utils.getColumnByAccessor)(splitRow[0], visData.columns) : undefined;
  const hasTooltipActions = interactive && bucketAccessors.filter(a => a !== 'metric-name').length > 0;
  const tooltip = {
    ...(fixedViewPort ? {
      boundary: fixedViewPort
    } : {}),
    type: visParams.addTooltip ? _charts.TooltipType.Follow : _charts.TooltipType.None,
    actions: hasTooltipActions ? [{
      disabled: selected => selected.length < 1,
      label: selected => selected.length === 0 ? _i18n.i18n.translate('expressionPartitionVis.tooltipActions.emptyFilterSelection', {
        defaultMessage: 'Select at least one series to filter'
      }) : _i18n.i18n.translate('expressionPartitionVis.tooltipActions.filterValues', {
        defaultMessage: 'Filter {seriesNumber} series',
        values: {
          seriesNumber: selected.length
        }
      }),
      onSelect: tooltipSelectedValues => {
        const cells = (0, _filter_helpers.getMultiFilterCells)(tooltipSelectedValues, bucketColumns, visData);
        props.fireEvent({
          name: 'multiFilter',
          data: {
            data: [{
              table: visData,
              cells
            }]
          }
        });
      }
    }] : undefined
  };

  /**
   * Checks whether data have all zero values.
   * If so, the no data container is loaded.
   */
  const isAllZeros = (0, _react.useMemo)(() => visData.rows.every(row => row[metricColumn.id] === 0), [visData.rows, metricColumn]);
  const isEmpty = visData.rows.length === 0;
  const isMetricEmpty = visData.rows.every(row => !row[metricColumn.id]);

  /**
   * Checks whether data have negative values.
   * If so, the no data container is loaded.
   */
  const hasNegative = (0, _react.useMemo)(() => visData.rows.some(row => {
    const value = row[metricColumn.id];
    return typeof value === 'number' && value < 0;
  }), [visData.rows, metricColumn]);
  const flatLegend = !visParams.nestedLegend || (0, _utils3.isLegendFlat)(visType, splitChartDimension);
  const canShowPieChart = !isEmpty && !isMetricEmpty && !isAllZeros && !hasNegative;
  const {
    euiTheme
  } = (0, _eui.useEuiTheme)();
  const chartContainerStyle = showToggleLegendElement ? (0, _partition_vis_component.partitionVisContainerWithToggleStyleFactory)(euiTheme) : _partition_vis_component.partitionVisContainerStyle;
  const partitionType = (0, _utils3.getPartitionType)(visType);
  const customLegendSort = (0, _react.useMemo)(() => {
    if (!showLegend || !flatLegend) {
      return;
    }
    const [bucketColumn] = bucketColumns;
    if (!bucketColumn.id) {
      return;
    }
    const lookup = {};
    visData.rows.forEach((row, i) => {
      const category = row[bucketColumn.id];
      if (!(category in lookup)) {
        lookup[category] = i;
      }
    });
    return (a, b) => {
      if (a.key == null) {
        return 1;
      }
      if (b.key == null) {
        return -1;
      }
      return lookup[a.key] - lookup[b.key];
    };
  }, [bucketColumns, flatLegend, showLegend, visData.rows]);
  return /*#__PURE__*/_react.default.createElement("div", {
    css: chartContainerStyle,
    "data-test-subj": "partitionVisChart"
  }, !canShowPieChart ? /*#__PURE__*/_react.default.createElement(_visualization_noresults.VisualizationNoResults, {
    hasNegativeValues: hasNegative,
    chartType: visType,
    renderComplete: onRenderChange
  }) : /*#__PURE__*/_react.default.createElement("div", {
    css: _partition_vis_component.partitionVisWrapperStyle,
    ref: parentRef
  }, /*#__PURE__*/_react.default.createElement(_utils3.LegendColorPickerWrapperContext.Provider, {
    value: {
      legendPosition,
      setColor,
      bucketColumns,
      palette: visParams.palette.name,
      data: visData.rows,
      uiState: props.uiState,
      distinctColors: (_visParams$distinctCo = visParams.distinctColors) !== null && _visParams$distinctCo !== void 0 ? _visParams$distinctCo : false
    }
  }, showToggleLegendElement && /*#__PURE__*/_react.default.createElement(_public.LegendToggle, {
    onClick: toggleLegend,
    showLegend: showLegend,
    legendPosition: legendPosition
  }), /*#__PURE__*/_react.default.createElement(_charts.Chart, (0, _extends2.default)({
    size: "100%"
  }, (0, _chartExpressionsCommon.getOverridesFor)(overrides, 'chart')), /*#__PURE__*/_react.default.createElement(_chart_split.ChartSplit, {
    splitColumnAccessor: splitChartColumnAccessor,
    splitRowAccessor: splitChartRowAccessor
  }), /*#__PURE__*/_react.default.createElement(_charts.Tooltip, tooltip), /*#__PURE__*/_react.default.createElement(_charts.Settings, (0, _extends2.default)({
    noResults: /*#__PURE__*/_react.default.createElement(_visualization_noresults.VisualizationNoResults, {
      chartType: visType,
      renderComplete: onRenderChange
    }),
    debugState: (_window$_echDebugStat = window._echDebugStateFlag) !== null && _window$_echDebugStat !== void 0 ? _window$_echDebugStat : false,
    showLegend: showLegend !== null && showLegend !== void 0 ? showLegend : (0, _utils3.shouldShowLegend)(visType, visParams.legendDisplay, bucketColumns),
    legendPosition: legendPosition,
    legendSize: _constants.LegendSizeToPixels[(_visParams$legendSize = visParams.legendSize) !== null && _visParams$legendSize !== void 0 ? _visParams$legendSize : _constants.DEFAULT_LEGEND_SIZE],
    legendMaxDepth: visParams.nestedLegend ? undefined : 1,
    legendColorPicker: props.uiState ? _utils3.LegendColorPickerWrapper : undefined,
    flatLegend: flatLegend,
    legendSort: customLegendSort,
    showLegendExtra: visParams.showValuesInLegend,
    onElementClick: ([elementEvent]) => {
      // this cast is safe because we are rendering a partition chart
      const [layerValues] = elementEvent;
      handleSliceClick(layerValues, bucketColumns, visData, splitChartDimension, splitChartFormatter);
    },
    legendAction: legendActions,
    theme: [
    // Chart background should be transparent for the usage at Canvas.
    {
      background: {
        color: 'transparent'
      }
    }, themeOverrides, chartTheme, {
      legend: {
        labelOptions: {
          maxLines: visParams.truncateLegend ? (_visParams$maxLegendL = visParams.maxLegendLines) !== null && _visParams$maxLegendL !== void 0 ? _visParams$maxLegendL : 1 : 0
        }
      }
    }, ...(Array.isArray(settingsThemeOverrides) ? settingsThemeOverrides : [settingsThemeOverrides])],
    baseTheme: chartBaseTheme,
    onRenderChange: onRenderChange,
    ariaLabel: props.visParams.ariaLabel,
    ariaUseDefaultSummary: !props.visParams.ariaLabel
  }, settingsOverrides)), /*#__PURE__*/_react.default.createElement(_charts.Partition, (0, _extends2.default)({
    id: visType,
    smallMultiples: _chart_split.SMALL_MULTIPLES_ID,
    data: visData.rows,
    layout: partitionType,
    specialFirstInnermostSector: visParams.startFromSecondLargestSlice,
    valueAccessor: d => getSliceValue(d, metricColumn),
    percentFormatter: d => percentFormatter.convert(d / 100),
    valueGetter: !visParams.labels.show || visParams.labels.valuesFormat === _expression_renderers.ValueFormats.VALUE || !visParams.labels.values ? undefined : _expression_renderers.ValueFormats.PERCENT,
    valueFormatter: d => !visParams.labels.show || !visParams.labels.values ? '' : metricFieldFormatter.convert(d),
    layers: layers,
    topGroove: !visParams.labels.show ? 0 : undefined
  }, (0, _chartExpressionsCommon.getOverridesFor)(overrides, 'partition')))))));
};

// eslint-disable-next-line import/no-default-export
var _default = /*#__PURE__*/(0, _react.memo)(PartitionVisComponent);
exports.default = _default;
module.exports = exports.default;