"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GanttChartBase = void 0;
var tslib_1 = require("tslib");
var React = require("react");
var d3_array_1 = require("d3-array");
var react_1 = require("@fluentui/react");
var index_1 = require("../Legends/index");
var index_2 = require("../CommonComponents/index");
var index_3 = require("../../utilities/index");
var image_export_utils_1 = require("../../utilities/image-export-utils");
var chart_utilities_1 = require("@fluentui/chart-utilities");
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, props = tslib_1.__rest(_a, ["useUTC", "yAxisCategoryOrder"]);
    var _barHeight = React.useRef(0);
    var _calloutId = React.useRef((0, react_1.getId)('callout'));
    var margins = React.useRef({});
    var _bars = React.useRef([]);
    var _xAxisType = React.useRef(index_3.XAxisTypes.DateAxis);
    var _yAxisType = React.useRef(index_3.YAxisType.StringAxis);
    var _calloutAnchorPoint = React.useRef(null);
    var _cartesianChartRef = React.useRef(null);
    var _legendsRef = React.useRef(null);
    var _domainMargin = React.useRef(index_3.MIN_DOMAIN_MARGIN);
    var _yAxisPadding = React.useRef(0);
    var _emptyChartId = React.useRef((0, react_1.getId)('Gantt_empty'));
    var _legendColorMap = React.useRef({});
    var _gradientId = React.useRef((0, react_1.getId)('Gantt_gradient'));
    var prevProps = React.useRef({});
    var _f = React.useState(''), calloutColor = _f[0], setCalloutColor = _f[1];
    var _g = React.useState(false), isCalloutVisible = _g[0], setCalloutVisible = _g[1];
    var _h = React.useState(''), hoveredLegend = _h[0], setHoveredLegend = _h[1];
    var _j = React.useState(null), calloutTarget = _j[0], setCalloutTarget = _j[1];
    var _k = React.useState(''), calloutLegend = _k[0], setCalloutLegend = _k[1];
    var _l = React.useState(''), xCalloutValue = _l[0], setXCalloutValue = _l[1];
    var _m = React.useState(''), yCalloutValue = _m[0], setYCalloutValue = _m[1];
    var _o = React.useState(((_b = props.legendProps) === null || _b === void 0 ? void 0 : _b.selectedLegends) || []), selectedLegends = _o[0], setSelectedLegends = _o[1];
    var _p = React.useState(), dataPointCalloutProps = _p[0], setDataPointCalloutProps = _p[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;
        _legendColorMap.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 (!_legendColorMap.current[legend]) {
                var startColor = 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 = startColor;
                if (props.enableGradient) {
                    var nextGradient = (0, index_3.getNextGradient)(colorIndex, 0, (_c = props.theme) === null || _c === void 0 ? void 0 : _c.isInverted);
                    startColor = ((_d = point.gradient) === null || _d === void 0 ? void 0 : _d[0]) || nextGradient[0];
                    endColor = ((_e = point.gradient) === null || _e === void 0 ? void 0 : _e[1]) || nextGradient[1];
                }
                _legendColorMap.current[legend] = [startColor, endColor];
                colorIndex += 1;
            }
            return tslib_1.__assign(tslib_1.__assign(tslib_1.__assign({}, point), { color: _legendColorMap.current[legend][0] }), (props.enableGradient ? { gradient: _legendColorMap.current[legend] } : {}));
        })) !== null && _b !== void 0 ? _b : []);
    }, [props.data, (_c = props.theme) === null || _c === void 0 ? void 0 : _c.isInverted, props.enableGradient]);
    var _dateFormatOptions = React.useMemo(function () {
        if (_xAxisType.current !== 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]);
    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 _adjustProps = function () {
        _barHeight.current = Math.max(props.barHeight || 24, 1);
        if (props.data && props.data.length > 0) {
            _xAxisType.current = (0, index_3.getTypeOfAxis)(props.data[0].x.start, true);
            _yAxisType.current = (0, index_3.getTypeOfAxis)(props.data[0].y, false);
        }
        _yAxisPadding.current = (0, index_3.getScalePadding)(props.yAxisPadding, undefined, 1 / 2);
    };
    var _getMargins = React.useCallback(function (_margins) {
        margins.current = _margins;
    }, []);
    var _renderContentForOnlyBars = function (point) {
        return (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 }));
    };
    var _renderCallout = function (point) {
        return point ? _renderContentForOnlyBars(point) : null;
    };
    var _getCustomizedCallout = function () {
        return props.onRenderCalloutPerDataPoint
            ? props.onRenderCalloutPerDataPoint(dataPointCalloutProps, _renderCallout)
            : null;
    };
    var _getFormattedXValue = React.useCallback(function (point) {
        var formattedStartX;
        var formattedEndX;
        if (_xAxisType.current === 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]);
    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, ". ") + "".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));
        setDataPointCalloutProps(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 _createBars = React.useCallback(function (xScale, yScale) {
        var bars = _points.map(function (point, index) {
            var shouldHighlight = _noLegendHighlighted() || _legendHighlighted(point.legend);
            var startColor = point.color;
            var endColor = startColor;
            if (props.enableGradient) {
                startColor = point.gradient[0];
                endColor = point.gradient[1];
            }
            var gradientId = "".concat(_gradientId.current, "_").concat(index);
            var startX = xScale(point.x.start);
            var endX = xScale(point.x.end);
            var y = (_yAxisType.current === index_3.YAxisType.StringAxis
                ? yScale(point.y) + yScale.bandwidth() / 2
                : yScale(point.y)) -
                _barHeight.current / 2;
            return (React.createElement(React.Fragment, { key: index },
                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", { x: Math.min(startX, endX), y: y, width: Math.abs(endX - startX), height: _barHeight.current, rx: props.roundCorners ? 3 : 0, fill: props.enableGradient ? "url(#".concat(gradientId, ")") : startColor, 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 bars;
    }, [
        _getAriaLabel,
        _legendHighlighted,
        _noLegendHighlighted,
        _onBarFocus,
        _onBarHover,
        props.enableGradient,
        props.roundCorners,
        _points,
    ]);
    var _getGraphData = React.useCallback(function (xScale, yScale, containerHeight, containerWidth, xAxisElement, yAxisElement) {
        return (_bars.current = _createBars(xScale, yScale));
    }, [_createBars]);
    var _onBarLeave = function () {
        // do nothing
    };
    var _handleChartMouseLeave = React.useCallback(function () {
        _calloutAnchorPoint.current = null;
        setCalloutTarget(null);
        setCalloutVisible(false);
        setCalloutLegend('');
        setCalloutColor('');
        setXCalloutValue('');
        setYCalloutValue('');
        setDataPointCalloutProps(undefined);
    }, []);
    var _closeCallout = function () {
        setCalloutVisible(false);
    };
    var _onLegendHover = function (legend) {
        setHoveredLegend(legend);
    };
    var _onLegendLeave = function () {
        setHoveredLegend('');
    };
    var _getLegendData = function () {
        var actions = [];
        Object.keys(_legendColorMap.current).forEach(function (legendTitle) {
            var legend = {
                title: legendTitle,
                color: _legendColorMap.current[legendTitle][0],
                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;
    };
    var _onLegendSelectionChange = 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);
        }
    };
    var _getChartTitle = function () {
        var chartTitle = props.chartTitle;
        return (chartTitle ? "".concat(chartTitle, ". ") : '') + "Gantt chart with ".concat(_points.length, " bars. ");
    };
    var _isChartEmpty = function () {
        return !(props.data && props.data.length > 0);
    };
    var _getYDomainMargins = React.useCallback(function (containerHeight) {
        _domainMargin.current = 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.current !== index_3.YAxisType.StringAxis) {
            _barHeight.current = Math.max(props.barHeight ||
                (0, index_3.calculateAppropriateBarWidth)(uniqueY, totalHeight, _yAxisPadding.current), 1);
            _domainMargin.current += _barHeight.current / 2;
        }
        return tslib_1.__assign(tslib_1.__assign({}, margins.current), { top: margins.current.top + _domainMargin.current, bottom: margins.current.bottom + _domainMargin.current });
    }, [props.barHeight, _points]);
    var _getOrderedYAxisLabels = function () {
        return (0, index_3.sortAxisCategories)(_mapCategoryToValues(), yAxisCategoryOrder);
    };
    var _mapCategoryToValues = function () {
        var categoryToValues = {};
        _points.forEach(function (point) {
            if (!categoryToValues[point.y]) {
                categoryToValues[point.y] = [];
            }
            // FIXME
            // categoryToValues[point.y].push(point.x.end - point.x.start);
        });
        return categoryToValues;
    };
    var _renderBars = React.useCallback(function () {
        return React.createElement("g", null, _bars.current);
    }, []);
    if (!_isChartEmpty()) {
        _adjustProps();
        var yAxisLabels = _getOrderedYAxisLabels();
        var legendBars = _getLegendData();
        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.current, chartTitle: _getChartTitle(), points: _points, chartType: index_3.ChartTypes.GanttChart, xAxisType: _xAxisType.current, yAxisType: _yAxisType.current, stringDatasetForYAxisDomain: yAxisLabels, calloutProps: calloutProps, tickParams: tickParams, legendBars: legendBars, createYAxis: index_3.createYAxisForHorizontalBarChartWithAxis, getDomainNRangeValues: _getDomainNRangeValues, createStringYAxis: index_3.createStringYAxisForHorizontalBarChartWithAxis, getMinMaxOfYAxis: index_3.findHBCWANumericMinMaxOfY, focusZoneDirection: react_1.FocusZoneDirection.vertical, customizedCallout: _getCustomizedCallout(), getmargins: _getMargins, getYDomainMargins: _getYDomainMargins, getGraphData: _getGraphData, onChartMouseLeave: _handleChartMouseLeave, ref: _cartesianChartRef, useUTC: useUTC, children: _renderBars })));
    }
    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