define(["require", "exports", "tslib", "react", "d3-array", "@fluentui/react", "../Legends/index", "../CommonComponents/index", "../../utilities/index", "../../utilities/image-export-utils", "@fluentui/chart-utilities"], function (require, exports, tslib_1, React, d3_array_1, react_1, index_1, index_2, index_3, image_export_utils_1, chart_utilities_1) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.GanttChartBase = void 0;
    var DEFAULT_BAR_HEIGHT = 24;
    var MIN_BAR_HEIGHT = 1;
    exports.GanttChartBase = React.forwardRef(function (_a, forwardedRef) {
        var _b, _c;
        var _d = _a.useUTC, useUTC = _d === void 0 ? true : _d, _e = _a.yAxisCategoryOrder, yAxisCategoryOrder = _e === void 0 ? 'default' : _e, _f = _a.maxBarHeight, maxBarHeight = _f === void 0 ? 24 : _f, props = tslib_1.__rest(_a, ["useUTC", "yAxisCategoryOrder", "maxBarHeight"]);
        var _barHeight = React.useRef(DEFAULT_BAR_HEIGHT);
        var _calloutId = React.useRef((0, react_1.getId)('callout'));
        var _margins = React.useRef({});
        var _calloutAnchorPoint = React.useRef(null);
        var _cartesianChartRef = React.useRef(null);
        var _legendsRef = React.useRef(null);
        var _emptyChartId = React.useRef((0, react_1.getId)('Gantt_empty'));
        var _legendMap = React.useRef({});
        var _prevProps = React.useRef({});
        var _g = React.useState(''), calloutColor = _g[0], setCalloutColor = _g[1];
        var _h = React.useState(false), isCalloutVisible = _h[0], setCalloutVisible = _h[1];
        var _j = React.useState(''), hoveredLegend = _j[0], setHoveredLegend = _j[1];
        var _k = React.useState(null), calloutTarget = _k[0], setCalloutTarget = _k[1];
        var _l = React.useState(''), calloutLegend = _l[0], setCalloutLegend = _l[1];
        var _m = React.useState(''), xCalloutValue = _m[0], setXCalloutValue = _m[1];
        var _o = React.useState(''), yCalloutValue = _o[0], setYCalloutValue = _o[1];
        var _p = React.useState(((_b = props.legendProps) === null || _b === void 0 ? void 0 : _b.selectedLegends) || []), selectedLegends = _p[0], setSelectedLegends = _p[1];
        var _q = React.useState(), calloutDataPoint = _q[0], setCalloutDataPoint = _q[1];
        React.useEffect(function () {
            var _a, _b, _c;
            if (!(0, index_3.areArraysEqual)((_a = _prevProps.current.legendProps) === null || _a === void 0 ? void 0 : _a.selectedLegends, (_b = props.legendProps) === null || _b === void 0 ? void 0 : _b.selectedLegends)) {
                setSelectedLegends(((_c = props.legendProps) === null || _c === void 0 ? void 0 : _c.selectedLegends) || []);
            }
            _prevProps.current = props;
        }, [props]);
        React.useImperativeHandle(props.componentRef, function () {
            var _a, _b;
            return ({
                chartContainer: (_b = (_a = _cartesianChartRef.current) === null || _a === void 0 ? void 0 : _a.chartContainer) !== null && _b !== void 0 ? _b : null,
                toImage: function (opts) {
                    var _a, _b;
                    return (0, image_export_utils_1.toImage)((_a = _cartesianChartRef.current) === null || _a === void 0 ? void 0 : _a.chartContainer, (_b = _legendsRef.current) === null || _b === void 0 ? void 0 : _b.toSVG, (0, react_1.getRTL)(), opts);
                },
            });
        }, []);
        var _points = React.useMemo(function () {
            var _a, _b;
            _legendMap.current = {};
            var colorIndex = 0;
            return ((_b = (_a = props.data) === null || _a === void 0 ? void 0 : _a.map(function (point) {
                var _a, _b, _c, _d, _e;
                var legend = "".concat(point.legend);
                if (!_legendMap.current[legend]) {
                    var startColor_1 = point.color
                        ? (0, index_3.getColorFromToken)(point.color, (_a = props.theme) === null || _a === void 0 ? void 0 : _a.isInverted)
                        : (0, index_3.getNextColor)(colorIndex, 0, (_b = props.theme) === null || _b === void 0 ? void 0 : _b.isInverted);
                    var endColor_1 = startColor_1;
                    if (props.enableGradient) {
                        var nextGradient = (0, index_3.getNextGradient)(colorIndex, 0, (_c = props.theme) === null || _c === void 0 ? void 0 : _c.isInverted);
                        startColor_1 = ((_d = point.gradient) === null || _d === void 0 ? void 0 : _d[0]) || nextGradient[0];
                        endColor_1 = ((_e = point.gradient) === null || _e === void 0 ? void 0 : _e[1]) || nextGradient[1];
                    }
                    _legendMap.current[legend] = { id: (0, react_1.getId)('legend'), startColor: startColor_1, endColor: endColor_1 };
                    colorIndex += 1;
                }
                var _f = _legendMap.current[legend], startColor = _f.startColor, endColor = _f.endColor;
                return tslib_1.__assign(tslib_1.__assign(tslib_1.__assign({}, point), { color: startColor }), (props.enableGradient ? { gradient: [startColor, endColor] } : {}));
            })) !== null && _b !== void 0 ? _b : []);
        }, [props.data, (_c = props.theme) === null || _c === void 0 ? void 0 : _c.isInverted, props.enableGradient]);
        var _xAxisType = React.useMemo(function () {
            if (_points.length > 0) {
                return (0, index_3.getTypeOfAxis)(_points[0].x.start, true);
            }
            return index_3.XAxisTypes.DateAxis;
        }, [_points]);
        var _yAxisType = React.useMemo(function () {
            if (_points.length > 0) {
                return (0, index_3.getTypeOfAxis)(_points[0].y, false);
            }
            return index_3.YAxisType.StringAxis;
        }, [_points]);
        var _yAxisPadding = React.useMemo(function () {
            return (0, index_3.getScalePadding)(props.yAxisPadding, undefined, 1 / 2);
        }, [props.yAxisPadding]);
        var _dateFormatOptions = React.useMemo(function () {
            if (_xAxisType !== index_3.XAxisTypes.DateAxis) {
                return undefined;
            }
            var lowestFormatLevel = 100;
            var highestFormatLevel = -1;
            _points.forEach(function (p) {
                var startFormatLevel = (0, index_3.getDateFormatLevel)(p.x.start, useUTC);
                var endFormatLevel = (0, index_3.getDateFormatLevel)(p.x.end, useUTC);
                lowestFormatLevel = Math.min(lowestFormatLevel, startFormatLevel, endFormatLevel);
                highestFormatLevel = Math.max(highestFormatLevel, startFormatLevel, endFormatLevel);
            });
            return (0, chart_utilities_1.getMultiLevelDateTimeFormatOptions)(lowestFormatLevel, highestFormatLevel);
        }, [useUTC, _points, _xAxisType]);
        var _mapYValueToXValues = React.useCallback(function () {
            var yValueToXValues = {};
            _points.forEach(function (point) {
                if (!yValueToXValues[point.y]) {
                    yValueToXValues[point.y] = [];
                }
                yValueToXValues[point.y].push(+point.x.end - +point.x.start);
            });
            return yValueToXValues;
        }, [_points]);
        var _getOrderedYAxisLabels = React.useCallback(function () {
            var yValueToXValues = _mapYValueToXValues();
            if (_yAxisType !== index_3.YAxisType.StringAxis) {
                return Object.keys(yValueToXValues).sort(function (a, b) { return +a - +b; });
            }
            if (yAxisCategoryOrder === 'default') {
                return Object.keys(yValueToXValues).reverse();
            }
            return (0, index_3.sortAxisCategories)(yValueToXValues, yAxisCategoryOrder);
        }, [_mapYValueToXValues, _yAxisType, yAxisCategoryOrder]);
        var _yAxisLabels = React.useMemo(function () { return _getOrderedYAxisLabels(); }, [_getOrderedYAxisLabels]);
        var _getDomainNRangeValues = React.useCallback(function (points, margins, containerWidth, chartType, isRTL, xAxisType, barWidth, tickValues, shiftX) {
            var xValues = [];
            points.forEach(function (point) {
                xValues.push(point.x.start, point.x.end);
            });
            var xMin = (0, d3_array_1.min)(xValues) || 0;
            var xMax = (0, d3_array_1.max)(xValues) || 0;
            return {
                dStartValue: isRTL ? xMax : xMin,
                dEndValue: isRTL ? xMin : xMax,
                rStartValue: margins.left + (isRTL ? 0 : shiftX),
                rEndValue: containerWidth - margins.right - (isRTL ? shiftX : 0),
            };
        }, []);
        var _getMargins = React.useCallback(function (margins) {
            _margins.current = margins;
        }, []);
        var _getFormattedXValue = React.useCallback(function (point) {
            var formattedStartX;
            var formattedEndX;
            if (_xAxisType === index_3.XAxisTypes.DateAxis) {
                formattedStartX = (0, chart_utilities_1.formatDateToLocaleString)(point.x.start, props.culture, useUTC, false, _dateFormatOptions);
                formattedEndX = (0, chart_utilities_1.formatDateToLocaleString)(point.x.end, props.culture, useUTC, false, _dateFormatOptions);
            }
            else {
                formattedStartX = point.x.start.toString();
                formattedEndX = point.x.end.toString();
            }
            return "".concat(formattedStartX, " - ").concat(formattedEndX);
        }, [props.culture, useUTC, _dateFormatOptions, _xAxisType]);
        var _getCustomizedCallout = React.useCallback(function () {
            var defaultRender = function (point) {
                return point ? (React.createElement(index_3.ChartHoverCard, { XValue: point.yAxisCalloutData || point.y.toString(), Legend: point.legend, YValue: point.xAxisCalloutData || _getFormattedXValue(point), color: point.color, culture: props.culture })) : null;
            };
            return props.onRenderCalloutPerDataPoint
                ? props.onRenderCalloutPerDataPoint(calloutDataPoint, defaultRender)
                : null;
            //eslint-disable-next-line react-hooks/exhaustive-deps
        }, [_getFormattedXValue, calloutDataPoint, props.culture, props.onRenderCalloutPerDataPoint]);
        var _getAriaLabel = React.useCallback(function (point) {
            var _a;
            var xValue = point.xAxisCalloutData || _getFormattedXValue(point);
            var yValue = point.yAxisCalloutData || point.y;
            return (((_a = point.callOutAccessibilityData) === null || _a === void 0 ? void 0 : _a.ariaLabel) ||
                "".concat(yValue, ". ") + (point.legend ? "".concat(point.legend, ", ") : '') + "".concat(xValue, "."));
        }, [_getFormattedXValue]);
        var _getHighlightedLegend = React.useCallback(function () {
            return selectedLegends.length > 0 ? selectedLegends : hoveredLegend ? [hoveredLegend] : [];
        }, [hoveredLegend, selectedLegends]);
        /**
         * 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
         */
        var _legendHighlighted = React.useCallback(function (legend) {
            return _getHighlightedLegend().includes("".concat(legend));
        }, [_getHighlightedLegend]);
        /**
         * This function checks if none of the legends is selected or hovered.
         */
        var _noLegendHighlighted = React.useCallback(function () {
            return _getHighlightedLegend().length === 0;
        }, [_getHighlightedLegend]);
        var _showCallout = React.useCallback(function (target, point) {
            if (!(_noLegendHighlighted() || _legendHighlighted(point.legend)) || _calloutAnchorPoint.current === point) {
                return;
            }
            _calloutAnchorPoint.current = point;
            setCalloutTarget(target);
            setCalloutVisible(true);
            setCalloutLegend(point.legend);
            setCalloutColor(point.color);
            setXCalloutValue(point.yAxisCalloutData || point.y.toString());
            setYCalloutValue(point.xAxisCalloutData || _getFormattedXValue(point));
            setCalloutDataPoint(point);
        }, [_getFormattedXValue, _legendHighlighted, _noLegendHighlighted]);
        var _onBarFocus = React.useCallback(function (point, focusEvent) {
            _showCallout(focusEvent.currentTarget, point);
        }, [_showCallout]);
        var _onBarHover = React.useCallback(function (point, mouseEvent) {
            _showCallout(mouseEvent.currentTarget, point);
        }, [_showCallout]);
        var _onBarLeave = React.useCallback(function () {
            // do nothing
        }, []);
        var _handleChartMouseLeave = React.useCallback(function () {
            _calloutAnchorPoint.current = null;
            setCalloutTarget(null);
            setCalloutVisible(false);
            setCalloutLegend('');
            setCalloutColor('');
            setXCalloutValue('');
            setYCalloutValue('');
            setCalloutDataPoint(undefined);
        }, []);
        var _closeCallout = React.useCallback(function () {
            setCalloutVisible(false);
        }, []);
        var _getBarHeight = React.useCallback(function (adjustedValue) {
            var barHeight;
            if (typeof props.barHeight === 'number') {
                barHeight = props.barHeight;
            }
            else {
                barHeight = adjustedValue;
            }
            if (typeof maxBarHeight === 'number') {
                barHeight = Math.min(barHeight, maxBarHeight);
            }
            barHeight = Math.max(barHeight, MIN_BAR_HEIGHT);
            return barHeight;
        }, [maxBarHeight, props.barHeight]);
        var _getOrderedDataPoints = React.useCallback(function () {
            var result = [];
            var yValueToPoints = {};
            _points.forEach(function (point) {
                if (!yValueToPoints[point.y]) {
                    yValueToPoints[point.y] = [];
                }
                yValueToPoints[point.y].push(point);
            });
            for (var i = _yAxisLabels.length - 1; i >= 0; i--) {
                var yValue = _yAxisLabels[i];
                if (yValueToPoints[yValue]) {
                    result.push.apply(result, yValueToPoints[yValue].sort(function (a, b) { return +a.x.start - +b.x.start; }));
                }
            }
            return result;
        }, [_points, _yAxisLabels]);
        var _createBars = React.useCallback(function (_a) {
            var xScale = _a.xScale, yScale = _a.yScalePrimary;
            var getGradientId = function (legend) {
                var legendId = _legendMap.current["".concat(legend)].id;
                return "".concat(legendId, "_gradient");
            };
            var gradientDefs = [];
            if (props.enableGradient) {
                Object.keys(_legendMap.current).forEach(function (legend, index) {
                    var _a = _legendMap.current[legend], startColor = _a.startColor, endColor = _a.endColor;
                    gradientDefs.push(React.createElement("linearGradient", { key: index, id: getGradientId(legend) },
                        React.createElement("stop", { offset: "0", stopColor: startColor }),
                        React.createElement("stop", { offset: "100%", stopColor: endColor })));
                });
            }
            var scaleBandwidth = 0;
            if (_yAxisType === index_3.YAxisType.StringAxis) {
                scaleBandwidth = yScale.bandwidth();
                _barHeight.current = _getBarHeight(scaleBandwidth);
            }
            var points = _getOrderedDataPoints();
            var bars = points.map(function (point, index) {
                var rectStartX = xScale(point.x.start);
                var rectEndX = xScale(point.x.end);
                // eslint-disable-next-line @typescript-eslint/no-explicit-any
                var rectY = yScale(point.y) + (scaleBandwidth - _barHeight.current) / 2;
                var shouldHighlight = _noLegendHighlighted() || _legendHighlighted(point.legend);
                return (React.createElement("rect", { key: index, x: Math.min(rectStartX, rectEndX), y: rectY, width: Math.abs(rectEndX - rectStartX), height: _barHeight.current, rx: props.roundCorners ? 3 : 0, fill: props.enableGradient ? "url(#".concat(getGradientId(point.legend), ")") : point.color, opacity: shouldHighlight ? 1 : 0.1, onClick: point.onClick, onMouseOver: function (event) { return _onBarHover(point, event); }, onMouseLeave: _onBarLeave, onFocus: function (event) { return _onBarFocus(point, event); }, onBlur: _onBarLeave, "data-is-focusable": shouldHighlight, role: "img", "aria-label": _getAriaLabel(point) }));
            });
            return (React.createElement("g", null,
                gradientDefs.length > 0 ? React.createElement("defs", null, gradientDefs) : null,
                bars));
        }, [
            _getAriaLabel,
            _getBarHeight,
            _getOrderedDataPoints,
            _legendHighlighted,
            _noLegendHighlighted,
            _onBarFocus,
            _onBarHover,
            _onBarLeave,
            _yAxisType,
            props.enableGradient,
            props.roundCorners,
        ]);
        var _onLegendHover = React.useCallback(function (legend) {
            setHoveredLegend(legend);
        }, []);
        var _onLegendLeave = React.useCallback(function () {
            setHoveredLegend('');
        }, []);
        var _onLegendSelectionChange = React.useCallback(function (_selectedLegends, event, currentLegend) {
            var _a, _b;
            if ((_a = props.legendProps) === null || _a === void 0 ? void 0 : _a.canSelectMultipleLegends) {
                setSelectedLegends(_selectedLegends);
            }
            else {
                setSelectedLegends(_selectedLegends.slice(-1));
            }
            if ((_b = props.legendProps) === null || _b === void 0 ? void 0 : _b.onChange) {
                props.legendProps.onChange(_selectedLegends, event, currentLegend);
            }
        }, [props.legendProps]);
        var _getLegendData = React.useCallback(function () {
            var actions = [];
            Object.keys(_legendMap.current).forEach(function (legendTitle) {
                var legend = {
                    title: legendTitle,
                    color: _legendMap.current[legendTitle].startColor,
                    hoverAction: function () {
                        _handleChartMouseLeave();
                        _onLegendHover(legendTitle);
                    },
                    onMouseOutAction: function () {
                        _onLegendLeave();
                    },
                };
                actions.push(legend);
            });
            var legends = (React.createElement(index_1.Legends, tslib_1.__assign({ legends: actions, enabledWrapLines: props.enabledLegendsWrapLines, overflowProps: props.legendsOverflowProps, focusZonePropsInHoverCard: props.focusZonePropsForLegendsInHoverCard, overflowText: props.legendsOverflowText, onChange: _onLegendSelectionChange, ref: _legendsRef }, props.legendProps)));
            return legends;
        }, [
            _handleChartMouseLeave,
            _onLegendHover,
            _onLegendLeave,
            _onLegendSelectionChange,
            props.enabledLegendsWrapLines,
            props.focusZonePropsForLegendsInHoverCard,
            props.legendProps,
            props.legendsOverflowProps,
            props.legendsOverflowText,
        ]);
        var _getChartTitle = React.useCallback(function () {
            return (props.chartTitle ? "".concat(props.chartTitle, ". ") : '') + "Gantt chart with ".concat(_points.length, " data points. ");
        }, [_points.length, props.chartTitle]);
        var _isChartEmpty = React.useCallback(function () {
            return _points.length === 0;
        }, [_points.length]);
        var _getYDomainMargins = React.useCallback(function (containerHeight) {
            var domainMargin = index_3.MIN_DOMAIN_MARGIN;
            var ySet = new Set();
            _points.forEach(function (point) {
                ySet.add(point.y);
            });
            var uniqueY = Array.from(ySet);
            /** Total height available to render the bars */
            var totalHeight = containerHeight - (_margins.current.top + index_3.MIN_DOMAIN_MARGIN) - (_margins.current.bottom + index_3.MIN_DOMAIN_MARGIN);
            if (_yAxisType !== index_3.YAxisType.StringAxis) {
                _barHeight.current = _getBarHeight((0, index_3.calculateAppropriateBarWidth)(uniqueY, totalHeight, _yAxisPadding));
                domainMargin += _barHeight.current / 2;
            }
            return tslib_1.__assign(tslib_1.__assign({}, _margins.current), { top: _margins.current.top + domainMargin, bottom: _margins.current.bottom + domainMargin });
        }, [_getBarHeight, _points, _yAxisPadding, _yAxisType]);
        if (!_isChartEmpty()) {
            _barHeight.current = _getBarHeight(DEFAULT_BAR_HEIGHT);
            var calloutProps = tslib_1.__assign({ isCalloutVisible: isCalloutVisible, directionalHint: react_1.DirectionalHint.topAutoEdge, id: "toolTip".concat(_calloutId.current), target: calloutTarget, isBeakVisible: false, gapSpace: 15, color: calloutColor, legend: calloutLegend, XValue: xCalloutValue, YValue: yCalloutValue, onDismiss: _closeCallout, preventDismissOnLostFocus: true }, props.calloutProps);
            var tickParams = {
                tickValues: props.tickValues,
                tickFormat: props.tickFormat,
            };
            return (React.createElement(index_2.CartesianChart, tslib_1.__assign({}, props, { yAxisPadding: _yAxisPadding, chartTitle: _getChartTitle(), points: _points, chartType: index_3.ChartTypes.GanttChart, xAxisType: _xAxisType, yAxisType: _yAxisType, stringDatasetForYAxisDomain: _yAxisLabels, calloutProps: calloutProps, tickParams: tickParams, legendBars: _getLegendData(), createYAxis: index_3.createYAxisForHorizontalBarChartWithAxis, getDomainNRangeValues: _getDomainNRangeValues, createStringYAxis: index_3.createStringYAxisForHorizontalBarChartWithAxis, getMinMaxOfYAxis: index_3.findHBCWANumericMinMaxOfY, focusZoneDirection: react_1.FocusZoneDirection.bidirectional, customizedCallout: _getCustomizedCallout(), getmargins: _getMargins, getYDomainMargins: _getYDomainMargins, onChartMouseLeave: _handleChartMouseLeave, ref: _cartesianChartRef, useUTC: useUTC, children: _createBars })));
        }
        else {
            return (React.createElement("div", { id: _emptyChartId.current, role: 'alert', style: { opacity: '0' }, "aria-label": 'Graph has no data to display' }));
        }
    });
    exports.GanttChartBase.displayName = 'GanttChart';
});
//# sourceMappingURL=GanttChart.base.js.map