define(["require", "exports", "tslib", "react", "@fluentui/react/lib/Utilities", "../Legends/index", "@fluentui/react/lib/Callout", "@fluentui/react-focus", "../../utilities/index", "../../utilities/FocusableTooltipText", "../../utilities/locale-util"], function (require, exports, tslib_1, React, Utilities_1, index_1, Callout_1, react_focus_1, index_2, FocusableTooltipText_1, locale_util_1) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.StackedBarChartBase = void 0;
    var getClassNames = (0, Utilities_1.classNamesFunction)();
    var StackedBarChartBase = /** @class */ (function (_super) {
        tslib_1.__extends(StackedBarChartBase, _super);
        function StackedBarChartBase(props) {
            var _this = _super.call(this, props) || this;
            _this._isRTL = (0, Utilities_1.getRTL)();
            _this._handleChartMouseLeave = function () {
                _this._calloutAnchorPoint = null;
                _this.setState({
                    isCalloutVisible: false,
                });
            };
            _this._closeCallout = function () {
                _this.setState({
                    isCalloutVisible: false,
                });
            };
            /**
             * This function checks if the given legend is highlighted or not.
             * A legend can be highlighted in 2 ways:
             * 1. selection: if the user clicks on it
             * 2. hovering: if there is no selected legend and the user hovers over it
             */
            _this._legendHighlighted = function (legendTitle) {
                return (_this.state.selectedLegend === legendTitle ||
                    (_this.state.selectedLegend === '' && _this.state.activeLegend === legendTitle));
            };
            /**
             * This function checks if none of the legends is selected or hovered.
             */
            _this._noLegendHighlighted = function () {
                return _this.state.selectedLegend === '' && _this.state.activeLegend === '';
            };
            _this._getAriaLabel = function (point) {
                var _a;
                var legend = point.xAxisCalloutData || point.legend;
                var yValue = point.yAxisCalloutData || point.data || 0;
                return ((_a = point.callOutAccessibilityData) === null || _a === void 0 ? void 0 : _a.ariaLabel) || (legend ? "".concat(legend, ", ") : '') + "".concat(yValue, ".");
            };
            _this.state = {
                isCalloutVisible: false,
                selectedLegend: '',
                activeLegend: '',
                refSelected: null,
                dataForHoverCard: 0,
                color: '',
                xCalloutValue: '',
                yCalloutValue: '',
                calloutLegend: '',
                barSpacingInPercent: 0,
            };
            _this._refArray = [];
            _this._onLeave = _this._onLeave.bind(_this);
            _this._refCallback = _this._refCallback.bind(_this);
            _this._onBarLeave = _this._onBarLeave.bind(_this);
            _this._calloutId = (0, Utilities_1.getId)('callout');
            _this._emptyChartId = (0, Utilities_1.getId)('_SBC_empty');
            _this.barChartSvgRef = React.createRef();
            return _this;
        }
        StackedBarChartBase.prototype.componentDidMount = function () {
            var _a;
            var svgWidth = ((_a = this.barChartSvgRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect().width) || 0;
            var MARGIN_WIDTH_IN_PX = 3;
            if (svgWidth) {
                var currentBarSpacing = (MARGIN_WIDTH_IN_PX / svgWidth) * 100;
                this.setState({ barSpacingInPercent: currentBarSpacing });
            }
        };
        StackedBarChartBase.prototype.render = function () {
            if (!this._isChartEmpty()) {
                this._adjustProps();
                var _a = this.props, data_1 = _a.data, benchmarkData = _a.benchmarkData, targetData = _a.targetData, hideNumberDisplay = _a.hideNumberDisplay, ignoreFixStyle = _a.ignoreFixStyle, culture_1 = _a.culture;
                var palette = this.props.theme.palette;
                var barHeight = ignoreFixStyle || data_1.chartData.length > 2 ? this.props.barHeight : 12;
                if (benchmarkData) {
                    // benchmark color is used to render color for benchmark triangle and benchmark legend
                    benchmarkData.color = benchmarkData.color || palette.neutralTertiary;
                }
                if (targetData) {
                    // target color is used to render color for target triangle and target legend
                    targetData.color = targetData.color || palette.neutralSecondary;
                }
                var bars = this._createBarsAndLegends(data_1, barHeight, palette, benchmarkData, targetData);
                var showRatio = hideNumberDisplay === false && !ignoreFixStyle && data_1.chartData.length === 2;
                var showNumber = hideNumberDisplay === false && !ignoreFixStyle && data_1.chartData.length === 1;
                var total = data_1.chartData.reduce(function (acc, value) { return acc + (value.data ? value.data : 0); }, 0);
                var benchmarkRatio = 0;
                if (benchmarkData && total) {
                    benchmarkRatio = (benchmarkData.data / total) * 100;
                }
                var targetRatio = 0;
                if (targetData && total) {
                    targetRatio = (targetData.data / total) * 100;
                }
                var showLegend = this.props.hideLegend === false && (ignoreFixStyle || data_1.chartData.length > 2);
                this._classNames = getClassNames(this.props.styles, {
                    legendColor: this.state.color,
                    theme: this.props.theme,
                    benchmarkColor: benchmarkData ? benchmarkData.color : '',
                    benchmarkRatio: benchmarkRatio,
                    targetColor: targetData ? targetData.color : '',
                    targetRatio: targetRatio,
                    showTriangle: !!(benchmarkData || targetData),
                });
                var getChartData = function () {
                    return (0, locale_util_1.convertToLocaleString)(data_1.chartData[0].data ? data_1.chartData[0].data : 0, culture_1);
                };
                return (React.createElement("div", { className: this._classNames.root, onMouseLeave: this._handleChartMouseLeave },
                    React.createElement(react_focus_1.FocusZone, { direction: react_focus_1.FocusZoneDirection.horizontal },
                        React.createElement("div", { className: this._classNames.chartTitle },
                            data_1.chartTitle && (React.createElement(FocusableTooltipText_1.FocusableTooltipText, { className: this._classNames.chartTitleLeft, content: data_1.chartTitle, accessibilityData: data_1.chartTitleAccessibilityData })),
                            showRatio && (React.createElement("div", tslib_1.__assign({}, (0, index_2.getAccessibleDataObject)(data_1.chartDataAccessibilityData, 'text', false)),
                                React.createElement("span", { className: this._classNames.ratioNumerator }, getChartData()),
                                !this.props.hideDenominator && (React.createElement("span", { className: this._classNames.ratioDenominator }, ' / ' + (0, locale_util_1.convertToLocaleString)(total, culture_1))))),
                            showNumber && (React.createElement("div", tslib_1.__assign({ className: this._classNames.ratioNumerator }, (0, index_2.getAccessibleDataObject)(data_1.chartDataAccessibilityData, 'text', false)), getChartData()))),
                        (benchmarkData || targetData) && (React.createElement("div", { className: this._classNames.benchmarkContainer },
                            benchmarkData && React.createElement("div", { className: this._classNames.benchmark, role: "text" }),
                            targetData && React.createElement("div", { className: this._classNames.target, role: "text" })))),
                    React.createElement(react_focus_1.FocusZone, { direction: react_focus_1.FocusZoneDirection.horizontal },
                        React.createElement("div", null,
                            React.createElement("svg", { ref: this.barChartSvgRef, className: this._classNames.chart, "aria-label": data_1 === null || data_1 === void 0 ? void 0 : data_1.chartTitle },
                                React.createElement("g", null, bars[0]),
                                React.createElement(Callout_1.Callout, tslib_1.__assign({ gapSpace: 15, isBeakVisible: false, target: this.state.refSelected, setInitialFocus: true, hidden: !(!this.props.hideTooltip && this.state.isCalloutVisible), directionalHint: Callout_1.DirectionalHint.topAutoEdge, id: this._calloutId, onDismiss: this._closeCallout, 
                                    // eslint-disable-next-line @typescript-eslint/no-deprecated
                                    preventDismissOnLostFocus: true, 
                                    /** Keep the callout updated with details of focused/hovered bar */
                                    shouldUpdateWhenHidden: true }, this.props.calloutProps, (0, index_2.getAccessibleDataObject)(this.state.callOutAccessibilityData, 'text', false)),
                                    React.createElement(React.Fragment, null, this.props.onRenderCalloutPerDataPoint ? (this.props.onRenderCalloutPerDataPoint(this.state.dataPointCalloutProps)) : (React.createElement(index_2.ChartHoverCard, { Legend: this.state.xCalloutValue ? this.state.xCalloutValue : this.state.calloutLegend, YValue: this.state.yCalloutValue ? this.state.yCalloutValue : this.state.dataForHoverCard, color: this.state.color, culture: culture_1 }))))))),
                    showLegend && React.createElement("div", { className: this._classNames.legendContainer }, bars[1])));
            }
            return (React.createElement("div", { id: this._emptyChartId, role: 'alert', style: { opacity: '0' }, "aria-label": 'Graph has no data to display' }));
        };
        StackedBarChartBase.prototype._adjustProps = function () {
            this._classNames = getClassNames(this.props.styles, {
                legendColor: this.state.color,
                theme: this.props.theme,
                width: this.props.width,
                barHeight: this.props.barHeight,
                className: this.props.className,
            });
        };
        /**
         * The Create bar functions returns an array of <rect> elements, which form the bars
         * For each bar an x value, and a width needs to be specified
         * The computations are done based on percentages
         * Extra margin is also provided, in the x value to provide some spacing
         */
        StackedBarChartBase.prototype._createBarsAndLegends = function (data, barHeight, palette, benchmarkData, targetData) {
            var _this = this;
            var _a;
            var noOfBars = ((_a = data.chartData) === null || _a === void 0 ? void 0 : _a.reduce(function (count, point) { return (count += (point.data || 0) > 0 ? 1 : 0); }, 0)) ||
                1;
            var totalMarginPercent = this.state.barSpacingInPercent * (noOfBars - 1);
            var defaultPalette = [palette.blueLight, palette.blue, palette.blueMid, palette.red, palette.black];
            var legendDataItems = [];
            // calculating starting point of each bar and it's range
            var startingPoint = [];
            var total = data.chartData.reduce(function (acc, point) { return acc + (point.data ? point.data : 0); }, 0);
            var prevPosition = 0;
            var value = 0;
            var sumOfPercent = 0;
            data.chartData.map(function (point, index) {
                var pointData = point.data ? point.data : 0;
                value = (pointData / total) * 100;
                if (value < 1 && value !== 0) {
                    value = 1;
                }
                else if (value > 99 && value !== 100) {
                    value = 99;
                }
                sumOfPercent += value;
                return sumOfPercent;
            });
            /**
             * The %age of the space occupied by the margin needs to subtracted
             * while computing the scaling ratio, since the margins are not being
             * scaled down, only the data is being scaled down from a higher percentage to lower percentage
             * Eg: 95% of the space is taken by the bars, 5% by the margins
             * Now if the sumOfPercent is 120% -> This needs to be scaled down to 95%, not 100%
             * since that's only space available to the bars
             */
            var scalingRatio = sumOfPercent !== 0 ? sumOfPercent / (100 - totalMarginPercent) : 1;
            var bars = data.chartData.map(function (point, index) {
                var _a, _b, _c, _d;
                var startColor = point.color ? point.color : defaultPalette[Math.floor(Math.random() * 4 + 1)];
                var endColor = startColor;
                if (_this.props.enableGradient) {
                    startColor = ((_a = point.gradient) === null || _a === void 0 ? void 0 : _a[0]) || (0, index_2.getNextGradient)(index, 0, (_b = _this.props.theme) === null || _b === void 0 ? void 0 : _b.isInverted)[0];
                    endColor = ((_c = point.gradient) === null || _c === void 0 ? void 0 : _c[1]) || (0, index_2.getNextGradient)(index, 0, (_d = _this.props.theme) === null || _d === void 0 ? void 0 : _d.isInverted)[1];
                }
                var pointData = point.data ? point.data : 0;
                // mapping data to the format Legends component needs
                var legend = {
                    title: point.legend,
                    color: startColor,
                    action: total > 0
                        ? function () {
                            _this._onClick(point.legend);
                        }
                        : undefined,
                    hoverAction: total > 0
                        ? function () {
                            _this._handleChartMouseLeave();
                            _this._onHover(point.legend);
                        }
                        : undefined,
                    onMouseOutAction: total > 0
                        ? function () {
                            _this._onLeave();
                        }
                        : undefined,
                };
                if (!point.placeHolder) {
                    legendDataItems.push(legend);
                }
                if (index > 0) {
                    prevPosition += value;
                }
                value = (pointData / total) * 100;
                if (value < 1 && value !== 0) {
                    value = 1 / scalingRatio;
                }
                else if (value > 99 && value !== 100) {
                    value = 99 / scalingRatio;
                }
                else {
                    value = value / scalingRatio;
                }
                startingPoint.push(prevPosition);
                var styles = _this.props.styles;
                var shouldHighlight = _this._legendHighlighted(point.legend) || _this._noLegendHighlighted() ? true : false;
                _this._classNames = getClassNames(styles, {
                    theme: _this.props.theme,
                    shouldHighlight: shouldHighlight,
                    href: _this.props.href,
                });
                var gradientId = (0, Utilities_1.getId)('SBC_Gradient') + "_".concat(index);
                return (React.createElement("g", { key: index, className: _this._classNames.opacityChangeOnHover, ref: function (e) {
                        _this._refCallback(e, legend.title);
                    }, "data-is-focusable": !_this.props.hideTooltip && shouldHighlight, onFocus: _this._onBarFocus.bind(_this, pointData, startColor, point), onBlur: _this._onBarLeave, "aria-label": _this._getAriaLabel(point), role: "img", onMouseOver: _this._onBarHover.bind(_this, pointData, startColor, point), onMouseMove: _this._onBarHover.bind(_this, pointData, startColor, point), onMouseLeave: _this._onBarLeave, pointerEvents: "all", onClick: _this.props.href ? _this._redirectToUrl.bind(_this, _this.props.href) : point.onClick },
                    _this.props.enableGradient && (React.createElement("defs", null,
                        React.createElement("linearGradient", { id: gradientId },
                            React.createElement("stop", { offset: "0", stopColor: startColor }),
                            React.createElement("stop", { offset: "100%", stopColor: endColor })))),
                    React.createElement("rect", { key: index, id: (0, Utilities_1.getId)('_SBC_bar'), x: "".concat(_this._isRTL
                            ? 100 - startingPoint[index] - value - _this.state.barSpacingInPercent * index
                            : startingPoint[index] + _this.state.barSpacingInPercent * index, "%"), y: 0, width: value + '%', height: barHeight, rx: _this.props.roundCorners ? 3 : 0, fill: _this.props.enableGradient ? "url(#".concat(gradientId, ")") : startColor })));
            });
            // add benchmark legends
            this._addLegend(legendDataItems, benchmarkData);
            this._addLegend(legendDataItems, targetData);
            var legends = (React.createElement(index_1.Legends, tslib_1.__assign({ legends: legendDataItems, enabledWrapLines: this.props.enabledLegendsWrapLines, overflowProps: this.props.legendsOverflowProps, focusZonePropsInHoverCard: this.props.focusZonePropsForLegendsInHoverCard, overflowText: this.props.legendsOverflowText }, this.props.legendProps)));
            return [
                total === 0
                    ? [
                        this._generateEmptyBar(barHeight, this.props.barBackgroundColor ? this.props.barBackgroundColor : palette.neutralLight),
                    ]
                    : bars,
                legends,
            ];
        };
        StackedBarChartBase.prototype._onBarFocus = function (pointData, color, point) {
            var _this = this;
            this._refArray.forEach(function (obj) {
                if (obj.index === point.legend) {
                    _this.setState({
                        refSelected: obj.refElement,
                        /** Show the callout if highlighted bar is focused and Hide it if unhighlighted bar is focused */
                        isCalloutVisible: _this.state.selectedLegend === '' || _this.state.selectedLegend === point.legend,
                        calloutLegend: point.legend,
                        dataForHoverCard: pointData,
                        color: color,
                        xCalloutValue: point.xAxisCalloutData,
                        yCalloutValue: point.yAxisCalloutData,
                        dataPointCalloutProps: tslib_1.__assign(tslib_1.__assign({}, point), { color: color }),
                        callOutAccessibilityData: point.callOutAccessibilityData,
                    });
                }
            });
        };
        StackedBarChartBase.prototype._addLegend = function (legendDataItems, data) {
            if (data) {
                var legend = {
                    title: data.legend,
                    color: data.color,
                    shape: 'triangle',
                };
                legendDataItems.push(legend);
            }
        };
        StackedBarChartBase.prototype._generateEmptyBar = function (barHeight, color) {
            return (React.createElement("g", { key: 0, className: this._classNames.opacityChangeOnHover },
                React.createElement("rect", { key: 0, id: (0, Utilities_1.getId)('_SBC_empty_bar_'), x: '0%', y: 0, width: '100%', height: barHeight, fill: color })));
        };
        StackedBarChartBase.prototype._refCallback = function (element, legendTitle) {
            this._refArray.push({ index: legendTitle, refElement: element });
        };
        StackedBarChartBase.prototype._onClick = function (legendTitle) {
            if (this.state.selectedLegend === legendTitle) {
                this.setState({
                    selectedLegend: '',
                });
            }
            else {
                this.setState({
                    selectedLegend: legendTitle,
                });
            }
        };
        StackedBarChartBase.prototype._onHover = function (legendTitle) {
            this.setState({
                activeLegend: legendTitle,
            });
        };
        StackedBarChartBase.prototype._onLeave = function () {
            this.setState({
                activeLegend: '',
            });
        };
        StackedBarChartBase.prototype._onBarHover = function (pointData, color, point, mouseEvent) {
            mouseEvent.persist();
            if (this._calloutAnchorPoint !== point) {
                this._calloutAnchorPoint = point;
                this.setState({
                    refSelected: mouseEvent,
                    /** Show the callout if highlighted bar is hovered and Hide it if unhighlighted bar is hovered */
                    isCalloutVisible: this.state.selectedLegend === '' || this.state.selectedLegend === point.legend,
                    calloutLegend: point.legend,
                    dataForHoverCard: pointData,
                    color: color,
                    xCalloutValue: point.xAxisCalloutData,
                    yCalloutValue: point.yAxisCalloutData,
                    dataPointCalloutProps: tslib_1.__assign(tslib_1.__assign({}, point), { color: color }),
                    callOutAccessibilityData: point.callOutAccessibilityData,
                });
            }
        };
        StackedBarChartBase.prototype._onBarLeave = function () {
            /**/
        };
        StackedBarChartBase.prototype._redirectToUrl = function (href) {
            href ? (window.location.href = href) : '';
        };
        StackedBarChartBase.prototype._isChartEmpty = function () {
            return !(this.props.data && this.props.data.chartData && this.props.data.chartData.length > 0);
        };
        StackedBarChartBase.defaultProps = {
            barHeight: 12,
            hideNumberDisplay: false,
            hideLegend: false,
            ignoreFixStyle: false,
        };
        return StackedBarChartBase;
    }(React.Component));
    exports.StackedBarChartBase = StackedBarChartBase;
});
//# sourceMappingURL=StackedBarChart.base.js.map